mirror of
https://github.com/PuerkitoBio/goquery.git
synced 2026-10-19 08:14:33 +00:00
golang.org/x/net/html.ParseFragmentWithOptions initializes its form pointer based on whether the context element or any of its ancestors is a form element. If the context has a form ancestor, nested form tags are discarded per HTML parsing rules. Previously, cachedParseHtmlWithContext keyed cached fragments strictly by context tag name. When a selection contained targets both inside and outside forms sharing the same tag name, the first visited target cached its parsed fragment, leading to incorrect parsing for subsequent targets under the other form-ancestor state. Differentiate the fragment cache key by appending a form-ancestor indicator when context or any of its ancestors is a form element. Fixes #614
882 lines
23 KiB
Go
882 lines
23 KiB
Go
package goquery
|
|
|
|
import (
|
|
"log"
|
|
"testing"
|
|
)
|
|
|
|
const (
|
|
wrapHtml = "<div id=\"ins\">test string<div><p><em><b></b></em></p></div></div>"
|
|
)
|
|
|
|
func TestClonePreservesNamespaces(t *testing.T) {
|
|
doc := loadString(t, `<div><svg><circle></circle></svg><math><mi>x</mi></math></div>`)
|
|
for name, cloned := range map[string]*Selection{
|
|
"selection": doc.Find("div").Clone(),
|
|
"document": CloneDocument(doc).Selection,
|
|
} {
|
|
t.Run(name, func(t *testing.T) {
|
|
for selector, namespace := range map[string]string{
|
|
"svg": "svg", "circle": "svg", "math": "math", "mi": "math",
|
|
} {
|
|
node := cloned.Find(selector).Get(0)
|
|
if node == nil {
|
|
t.Fatalf("missing cloned %s", selector)
|
|
}
|
|
if node.Namespace != namespace {
|
|
t.Errorf("%s namespace = %q, want %q", selector, node.Namespace, namespace)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAfter(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").After("#nf6")
|
|
|
|
assertLength(t, doc.Find("#main #nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("#main + #nf6").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAfterMany(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find(".one").After("#nf6")
|
|
|
|
assertLength(t, doc.Find("#foot #nf6").Nodes, 1)
|
|
assertLength(t, doc.Find("#main #nf6").Nodes, 1)
|
|
assertLength(t, doc.Find(".one + #nf6").Nodes, 2)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAfterWithRemoved(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
s := doc.Find("#main").Remove()
|
|
s.After("#nf6")
|
|
|
|
assertLength(t, s.Find("#nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("#nf6").Nodes, 0)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAfterSelection(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").AfterSelection(doc.Find("#nf1, #nf2"))
|
|
|
|
assertLength(t, doc.Find("#main #nf1, #main #nf2").Nodes, 0)
|
|
assertLength(t, doc.Find("#foot #nf1, #foot #nf2").Nodes, 0)
|
|
assertLength(t, doc.Find("#main + #nf1, #nf1 + #nf2").Nodes, 2)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAfterHtml(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").AfterHtml("<strong>new node</strong>")
|
|
|
|
assertLength(t, doc.Find("#main + strong").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAfterHtmlContext(t *testing.T) {
|
|
doc := loadString(t, `
|
|
<html>
|
|
<body>
|
|
<table>
|
|
<tr>
|
|
<td>Before1</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Before2</td>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
</html>`)
|
|
doc.Find("table tr td").AfterHtml("<td class='c1'>Test</td><td class='c2'>Again</td>")
|
|
assertLength(t, doc.Find("table tr td").Nodes, 6)
|
|
assertClass(t, doc.Find("table tr td").Last(), "c2")
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAppend(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").Append("#nf6")
|
|
|
|
assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("#main #nf6").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAppendBody(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("body").Append("#nf6")
|
|
|
|
assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("#main #nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("body > #nf6").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAppendSelection(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").AppendSelection(doc.Find("#nf1, #nf2"))
|
|
|
|
assertLength(t, doc.Find("#foot #nf1").Nodes, 0)
|
|
assertLength(t, doc.Find("#foot #nf2").Nodes, 0)
|
|
assertLength(t, doc.Find("#main #nf1").Nodes, 1)
|
|
assertLength(t, doc.Find("#main #nf2").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAppendSelectionExisting(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").AppendSelection(doc.Find("#n1, #n2"))
|
|
|
|
assertClass(t, doc.Find("#main :nth-child(1)"), "three")
|
|
assertClass(t, doc.Find("#main :nth-child(5)"), "one")
|
|
assertClass(t, doc.Find("#main :nth-child(6)"), "two")
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAppendClone(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#n1").AppendSelection(doc.Find("#nf1").Clone())
|
|
|
|
assertLength(t, doc.Find("#foot #nf1").Nodes, 1)
|
|
assertLength(t, doc.Find("#main #nf1").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAppendHtml(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("div").AppendHtml("<strong>new node</strong>")
|
|
|
|
assertLength(t, doc.Find("strong").Nodes, 14)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestAppendHtmlContext(t *testing.T) {
|
|
doc := loadString(t, `
|
|
<html>
|
|
<body>
|
|
<table>
|
|
<tr>
|
|
<td>Before1</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Before2</td>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
</html>`)
|
|
doc.Find("table tr").AppendHtml("<td class='c1'>new1</td><td class='c2'>new2</td>")
|
|
|
|
assertLength(t, doc.Find("table td").Nodes, 6)
|
|
assertClass(t, doc.Find("table td").Last(), "c2")
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestBefore(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").Before("#nf6")
|
|
|
|
assertLength(t, doc.Find("#main #nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("body > #nf6:first-child").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestBeforeWithRemoved(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
s := doc.Find("#main").Remove()
|
|
s.Before("#nf6")
|
|
|
|
assertLength(t, s.Find("#nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("#nf6").Nodes, 0)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestBeforeSelection(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").BeforeSelection(doc.Find("#nf1, #nf2"))
|
|
|
|
assertLength(t, doc.Find("#main #nf1, #main #nf2").Nodes, 0)
|
|
assertLength(t, doc.Find("#foot #nf1, #foot #nf2").Nodes, 0)
|
|
assertLength(t, doc.Find("body > #nf1:first-child, #nf1 + #nf2").Nodes, 2)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestBeforeHtml(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").BeforeHtml("<strong>new node</strong>")
|
|
|
|
assertLength(t, doc.Find("body > strong:first-child").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestBeforeHtmlContext(t *testing.T) {
|
|
doc := loadString(t, `
|
|
<html>
|
|
<body>
|
|
<table>
|
|
<tr>
|
|
<td>Before1</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Before2</td>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
</html>`)
|
|
doc.Find("table tr td:first-child").BeforeHtml("<td class='c1'>new1</td><td class='c2'>new2</td>")
|
|
|
|
assertLength(t, doc.Find("table td").Nodes, 6)
|
|
assertClass(t, doc.Find("table td").First(), "c1")
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestEmpty(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
s := doc.Find("#main").Empty()
|
|
|
|
assertLength(t, doc.Find("#main").Children().Nodes, 0)
|
|
assertLength(t, s.Filter("div").Nodes, 6)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestPrepend(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").Prepend("#nf6")
|
|
|
|
assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("#main #nf6:first-child").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestPrependBody(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("body").Prepend("#nf6")
|
|
|
|
assertLength(t, doc.Find("#foot #nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("#main #nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("body > #nf6:first-child").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestPrependSelection(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").PrependSelection(doc.Find("#nf1, #nf2"))
|
|
|
|
assertLength(t, doc.Find("#foot #nf1").Nodes, 0)
|
|
assertLength(t, doc.Find("#foot #nf2").Nodes, 0)
|
|
assertLength(t, doc.Find("#main #nf1:first-child").Nodes, 1)
|
|
assertLength(t, doc.Find("#main #nf2:nth-child(2)").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestPrependSelectionExisting(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main").PrependSelection(doc.Find("#n5, #n6"))
|
|
|
|
assertClass(t, doc.Find("#main :nth-child(1)"), "five")
|
|
assertClass(t, doc.Find("#main :nth-child(2)"), "six")
|
|
assertClass(t, doc.Find("#main :nth-child(5)"), "three")
|
|
assertClass(t, doc.Find("#main :nth-child(6)"), "four")
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestPrependClone(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#n1").PrependSelection(doc.Find("#nf1").Clone())
|
|
|
|
assertLength(t, doc.Find("#foot #nf1:first-child").Nodes, 1)
|
|
assertLength(t, doc.Find("#main #nf1:first-child").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestPrependHtml(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("div").PrependHtml("<strong>new node</strong>")
|
|
|
|
assertLength(t, doc.Find("strong:first-child").Nodes, 14)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestPrependHtmlContext(t *testing.T) {
|
|
doc := loadString(t, `
|
|
<html>
|
|
<body>
|
|
<table>
|
|
<tr>
|
|
<td>Before1</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Before2</td>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
</html>`)
|
|
doc.Find("table tr").PrependHtml("<td class='c1'>new node</td><td class='c2'>other new node</td>")
|
|
|
|
assertLength(t, doc.Find("table td").Nodes, 6)
|
|
assertClass(t, doc.Find("table tr td").First(), "c1")
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestRemove(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#nf1").Remove()
|
|
|
|
assertLength(t, doc.Find("#foot #nf1").Nodes, 0)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestRemoveAll(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("*").Remove()
|
|
|
|
assertLength(t, doc.Find("*").Nodes, 0)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestRemoveRoot(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("html").Remove()
|
|
|
|
assertLength(t, doc.Find("html").Nodes, 0)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestRemoveFiltered(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
nf6 := doc.Find("#nf6")
|
|
s := doc.Find("div").RemoveFiltered("#nf6")
|
|
|
|
assertLength(t, doc.Find("#nf6").Nodes, 0)
|
|
assertLength(t, s.Nodes, 1)
|
|
if nf6.Nodes[0] != s.Nodes[0] {
|
|
t.Error("Removed node does not match original")
|
|
}
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestReplaceWith(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
|
|
doc.Find("#nf6").ReplaceWith("#main")
|
|
assertLength(t, doc.Find("#foot #main:last-child").Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
|
|
doc.Find("#foot").ReplaceWith("#main")
|
|
assertLength(t, doc.Find("#foot").Nodes, 0)
|
|
assertLength(t, doc.Find("#main").Nodes, 1)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestReplaceWithHtml(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#main, #foot").ReplaceWithHtml("<div id=\"replace\"></div>")
|
|
|
|
assertLength(t, doc.Find("#replace").Nodes, 2)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestReplaceWithHtmlContext(t *testing.T) {
|
|
doc := loadString(t, `
|
|
<html>
|
|
<body>
|
|
<table>
|
|
<tr>
|
|
<th>Before1</th>
|
|
</tr>
|
|
<tr>
|
|
<th>Before2</th>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
</html>`)
|
|
doc.Find("table th").ReplaceWithHtml("<td class='c1'>Test</td><td class='c2'>Replace</td>")
|
|
|
|
assertLength(t, doc.Find("table th").Nodes, 0)
|
|
assertLength(t, doc.Find("table tr td").Nodes, 4)
|
|
assertClass(t, doc.Find("table tr td").First(), "c1")
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestSetHtml(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
q := doc.Find("#main, #foot")
|
|
q.SetHtml(`<div id="replace">test</div>`)
|
|
|
|
assertLength(t, doc.Find("#replace").Nodes, 2)
|
|
assertLength(t, doc.Find("#main, #foot").Nodes, 2)
|
|
|
|
if q.Text() != "testtest" {
|
|
t.Errorf("Expected text to be %v, found %v", "testtest", q.Text())
|
|
}
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestSetHtmlNoMatch(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
q := doc.Find("#notthere")
|
|
q.SetHtml(`<div id="replace">test</div>`)
|
|
|
|
assertLength(t, doc.Find("#replace").Nodes, 0)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestSetHtmlEmpty(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
q := doc.Find("#main")
|
|
q.SetHtml(``)
|
|
|
|
assertLength(t, doc.Find("#main").Nodes, 1)
|
|
assertLength(t, doc.Find("#main").Children().Nodes, 0)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestSetHtmlContext(t *testing.T) {
|
|
doc := loadString(t, `
|
|
<html>
|
|
<body>
|
|
<table>
|
|
<tr>
|
|
<th>Before1</th>
|
|
</tr>
|
|
<tr>
|
|
<th>Before2</th>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
</html>`)
|
|
doc.Find("table tr").SetHtml("<td class='c1'>Test</td><td class='c2'>Again</td>")
|
|
|
|
assertLength(t, doc.Find("table th").Nodes, 0)
|
|
assertLength(t, doc.Find("table td").Nodes, 4)
|
|
assertLength(t, doc.Find("table tr").Nodes, 2)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestSetText(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
q := doc.Find("#main, #foot")
|
|
repl := "<div id=\"replace\">test</div>"
|
|
q.SetText(repl)
|
|
|
|
assertLength(t, doc.Find("#replace").Nodes, 0)
|
|
assertLength(t, doc.Find("#main, #foot").Nodes, 2)
|
|
|
|
if q.Text() != (repl + repl) {
|
|
t.Errorf("Expected text to be %v, found %v", (repl + repl), q.Text())
|
|
}
|
|
|
|
h, err := q.Html()
|
|
if err != nil {
|
|
t.Errorf("Error: %v", err)
|
|
}
|
|
esc := "<div id="replace">test</div>"
|
|
if h != esc {
|
|
t.Errorf("Expected html to be %v, found %v", esc, h)
|
|
}
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestReplaceWithSelection(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
sel := doc.Find("#nf6").ReplaceWithSelection(doc.Find("#nf5"))
|
|
|
|
assertSelectionIs(t, sel, "#nf6")
|
|
assertLength(t, doc.Find("#nf6").Nodes, 0)
|
|
assertLength(t, doc.Find("#nf5").Nodes, 1)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestUnwrap(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
|
|
doc.Find("#nf5").Unwrap()
|
|
assertLength(t, doc.Find("#foot").Nodes, 0)
|
|
assertLength(t, doc.Find("body > #nf1").Nodes, 1)
|
|
assertLength(t, doc.Find("body > #nf5").Nodes, 1)
|
|
|
|
printSel(t, doc.Selection)
|
|
|
|
doc = Doc2Clone()
|
|
|
|
doc.Find("#nf5, #n1").Unwrap()
|
|
assertLength(t, doc.Find("#foot").Nodes, 0)
|
|
assertLength(t, doc.Find("#main").Nodes, 0)
|
|
assertLength(t, doc.Find("body > #n1").Nodes, 1)
|
|
assertLength(t, doc.Find("body > #nf5").Nodes, 1)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestUnwrapBody(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
|
|
doc.Find("#main").Unwrap()
|
|
assertLength(t, doc.Find("body").Nodes, 1)
|
|
assertLength(t, doc.Find("body > #main").Nodes, 1)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestUnwrapHead(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
|
|
doc.Find("title").Unwrap()
|
|
assertLength(t, doc.Find("head").Nodes, 0)
|
|
assertLength(t, doc.Find("head > title").Nodes, 0)
|
|
assertLength(t, doc.Find("title").Nodes, 1)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestUnwrapHtml(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
|
|
doc.Find("head").Unwrap()
|
|
assertLength(t, doc.Find("html").Nodes, 0)
|
|
assertLength(t, doc.Find("html head").Nodes, 0)
|
|
assertLength(t, doc.Find("head").Nodes, 1)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestWrap(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#nf1").Wrap("#nf2")
|
|
nf1 := doc.Find("#foot #nf2 #nf1")
|
|
assertLength(t, nf1.Nodes, 1)
|
|
|
|
nf2 := doc.Find("#nf2")
|
|
assertLength(t, nf2.Nodes, 2)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestWrapEmpty(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#nf1").Wrap("#doesnt-exist")
|
|
|
|
origHtml, _ := Doc2().Html()
|
|
newHtml, _ := doc.Html()
|
|
|
|
if origHtml != newHtml {
|
|
t.Error("Expected the two documents to be identical.")
|
|
}
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestWrapHtml(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find(".odd").WrapHtml(wrapHtml)
|
|
nf2 := doc.Find("#ins #nf2")
|
|
assertLength(t, nf2.Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestWrapSelection(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#nf1").WrapSelection(doc.Find("#nf2"))
|
|
nf1 := doc.Find("#foot #nf2 #nf1")
|
|
assertLength(t, nf1.Nodes, 1)
|
|
|
|
nf2 := doc.Find("#nf2")
|
|
assertLength(t, nf2.Nodes, 2)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestWrapAll(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find(".odd").WrapAll("#nf1")
|
|
nf1 := doc.Find("#main #nf1")
|
|
assertLength(t, nf1.Nodes, 1)
|
|
|
|
sel := nf1.Find("#n2 ~ #n4 ~ #n6 ~ #nf2 ~ #nf4 ~ #nf6")
|
|
assertLength(t, sel.Nodes, 1)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestWrapAllHtml(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find(".odd").WrapAllHtml(wrapHtml)
|
|
nf1 := doc.Find("#main div#ins div p em b #n2 ~ #n4 ~ #n6 ~ #nf2 ~ #nf4 ~ #nf6")
|
|
assertLength(t, nf1.Nodes, 1)
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestWrapInnerNoContent(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find(".one").WrapInner(".two")
|
|
|
|
twos := doc.Find(".two")
|
|
assertLength(t, twos.Nodes, 4)
|
|
assertLength(t, doc.Find(".one .two").Nodes, 2)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestWrapInnerWithContent(t *testing.T) {
|
|
doc := Doc3Clone()
|
|
doc.Find(".one").WrapInner(".two")
|
|
|
|
twos := doc.Find(".two")
|
|
assertLength(t, twos.Nodes, 4)
|
|
assertLength(t, doc.Find(".one .two").Nodes, 2)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestWrapInnerNoWrapper(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find(".one").WrapInner(".not-exist")
|
|
|
|
twos := doc.Find(".two")
|
|
assertLength(t, twos.Nodes, 2)
|
|
assertLength(t, doc.Find(".one").Nodes, 2)
|
|
assertLength(t, doc.Find(".one .two").Nodes, 0)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestWrapInnerHtml(t *testing.T) {
|
|
doc := Doc2Clone()
|
|
doc.Find("#foot").WrapInnerHtml(wrapHtml)
|
|
|
|
foot := doc.Find("#foot div#ins div p em b #nf1 ~ #nf2 ~ #nf3")
|
|
assertLength(t, foot.Nodes, 1)
|
|
|
|
printSel(t, doc.Selection)
|
|
}
|
|
|
|
func TestParsingRespectsVaryingContext(t *testing.T) {
|
|
docA := loadString(t, `
|
|
<html>
|
|
<body>
|
|
<a class="x"></a>
|
|
</body>
|
|
</html>`)
|
|
docTable := loadString(t, `
|
|
<html>
|
|
<body>
|
|
<table class="x"></table>
|
|
</body>
|
|
</html>`)
|
|
docBoth := loadString(t, `
|
|
<html>
|
|
<body>
|
|
<table class="x"></table>
|
|
<a class="x"></a>
|
|
</body>
|
|
</html>`)
|
|
|
|
sA := docA.Find(".x").AppendHtml("<tr><td>Hello</td></tr>")
|
|
sTable := docTable.Find(".x").AppendHtml("<tr><td>Hello</td></tr>")
|
|
sBoth := docBoth.Find(".x").AppendHtml("<tr><td>Hello</td></tr>")
|
|
|
|
printSel(t, docA.Selection)
|
|
printSel(t, docTable.Selection)
|
|
printSel(t, docBoth.Selection)
|
|
|
|
oA, _ := sA.Html()
|
|
oTable, _ := sTable.Html()
|
|
|
|
if oA == oTable {
|
|
t.Errorf("Expected inner html of <a> and <table> to not be equal, but got %s and %s", oA, oTable)
|
|
}
|
|
|
|
oBothTable, _ := sBoth.First().Html()
|
|
if oBothTable != oTable {
|
|
t.Errorf("Expected inner html of <table> and <table> in doc containing both tags to be equal, but got %s and %s",
|
|
oTable,
|
|
oBothTable)
|
|
}
|
|
|
|
oBothA, _ := sBoth.Last().Html()
|
|
if oBothA != oA {
|
|
t.Errorf("Expected inner html of <a> and <a> in doc containing both tags to be equal, but got %s and %s",
|
|
oA,
|
|
oBothA)
|
|
}
|
|
}
|
|
|
|
func TestHtmlWithNonElementNode(t *testing.T) {
|
|
const data = `
|
|
<html>
|
|
<head>
|
|
</head>
|
|
<body>
|
|
<p>
|
|
This is <span>some</span><b>text</b>.
|
|
</p>
|
|
</body>
|
|
</html>
|
|
`
|
|
|
|
cases := map[string]func(*Selection, string) *Selection{
|
|
"AfterHtml": (*Selection).AfterHtml,
|
|
"AppendHtml": (*Selection).AppendHtml,
|
|
"BeforeHtml": (*Selection).BeforeHtml,
|
|
"PrependHtml": (*Selection).PrependHtml,
|
|
"ReplaceWithHtml": (*Selection).ReplaceWithHtml,
|
|
"SetHtml": (*Selection).SetHtml,
|
|
}
|
|
for nm, fn := range cases {
|
|
// this test is only to make sure that the HTML parsing/manipulation
|
|
// methods do not raise panics when executed over Selections that contain
|
|
// non-Element nodes.
|
|
t.Run(nm, func(t *testing.T) {
|
|
doc := loadString(t, data)
|
|
sel := doc.Find("p").Contents()
|
|
func() {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}()
|
|
fn(sel, "<div></div>")
|
|
}()
|
|
|
|
// print the resulting document in verbose mode
|
|
h, err := OuterHtml(doc.Selection)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
t.Log(h)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFormAncestorCache(t *testing.T) {
|
|
const htmlTemplate = `<html><head></head><body>` +
|
|
`<div id="wrapper-out"><div id="p-out"><div id="target-out" class="target"><span>c1</span></div></div></div>` +
|
|
`<form id="wrapper-in"><div id="p-in"><div id="target-in" class="target"><span>c2</span></div></div></form>` +
|
|
`</body></html>`
|
|
|
|
const insertFragment = `<form><input type="text"/></form>`
|
|
const wrapFragment = `<form><div class="wrapper"><span></span></div></form>`
|
|
|
|
cases := []struct {
|
|
name string
|
|
fragment string
|
|
fn func(*Selection, string) *Selection
|
|
}{
|
|
{"AppendHtml", insertFragment, (*Selection).AppendHtml},
|
|
{"PrependHtml", insertFragment, (*Selection).PrependHtml},
|
|
{"SetHtml", insertFragment, (*Selection).SetHtml},
|
|
{"BeforeHtml", insertFragment, (*Selection).BeforeHtml},
|
|
{"AfterHtml", insertFragment, (*Selection).AfterHtml},
|
|
{"ReplaceWithHtml", insertFragment, (*Selection).ReplaceWithHtml},
|
|
{"WrapHtml", wrapFragment, (*Selection).WrapHtml},
|
|
{"WrapInnerHtml", wrapFragment, (*Selection).WrapInnerHtml},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Control: apply to target-out only
|
|
docCtrlOut := loadString(t, htmlTemplate)
|
|
tc.fn(docCtrlOut.Find("#target-out"), tc.fragment)
|
|
ctrlOutHTML, err := docCtrlOut.Find("#p-out").Html()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Control: apply to target-in only
|
|
docCtrlIn := loadString(t, htmlTemplate)
|
|
tc.fn(docCtrlIn.Find("#target-in"), tc.fragment)
|
|
ctrlInHTML, err := docCtrlIn.Find("#p-in").Html()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Batch 1: outside element first [target-out, target-in]
|
|
docOutFirst := loadString(t, htmlTemplate)
|
|
selOutFirst := docOutFirst.Find("#target-out").AddNodes(docOutFirst.Find("#target-in").Get(0))
|
|
tc.fn(selOutFirst, tc.fragment)
|
|
outFirst_OutHTML, _ := docOutFirst.Find("#p-out").Html()
|
|
outFirst_InHTML, _ := docOutFirst.Find("#p-in").Html()
|
|
|
|
if outFirst_OutHTML != ctrlOutHTML {
|
|
t.Errorf("outside-first target-out: got %q, want %q", outFirst_OutHTML, ctrlOutHTML)
|
|
}
|
|
if outFirst_InHTML != ctrlInHTML {
|
|
t.Errorf("outside-first target-in: got %q, want %q", outFirst_InHTML, ctrlInHTML)
|
|
}
|
|
|
|
// Batch 2: inside element first [target-in, target-out]
|
|
docInFirst := loadString(t, htmlTemplate)
|
|
selInFirst := docInFirst.Find("#target-in").AddNodes(docInFirst.Find("#target-out").Get(0))
|
|
tc.fn(selInFirst, tc.fragment)
|
|
inFirst_OutHTML, _ := docInFirst.Find("#p-out").Html()
|
|
inFirst_InHTML, _ := docInFirst.Find("#p-in").Html()
|
|
|
|
if inFirst_OutHTML != ctrlOutHTML {
|
|
t.Errorf("inside-first target-out: got %q, want %q", inFirst_OutHTML, ctrlOutHTML)
|
|
}
|
|
if inFirst_InHTML != ctrlInHTML {
|
|
t.Errorf("inside-first target-in: got %q, want %q", inFirst_InHTML, ctrlInHTML)
|
|
}
|
|
|
|
// Empty selection control
|
|
docEmpty := loadString(t, htmlTemplate)
|
|
emptySel := docEmpty.Find(".nonexistent")
|
|
tc.fn(emptySel, tc.fragment)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAppendHtmlFormAncestorContext(t *testing.T) {
|
|
doc := loadString(t, `<html><body>
|
|
<div id="out"><div class="target" id="t-out"></div></div>
|
|
<form id="f"><div class="target" id="t-in"></div></form>
|
|
</body></html>`)
|
|
|
|
doc.Find(".target").AppendHtml(`<form><input type="text" name="foo"/></form>`)
|
|
|
|
assertLength(t, doc.Find("#t-out form").Nodes, 1)
|
|
assertLength(t, doc.Find("#t-out form input").Nodes, 1)
|
|
assertLength(t, doc.Find("#t-in form").Nodes, 0)
|
|
assertLength(t, doc.Find("#t-in input").Nodes, 1)
|
|
}
|
|
|
|
func TestPrependHtmlFormAncestorContext(t *testing.T) {
|
|
doc := loadString(t, `<html><body>
|
|
<div id="out"><div class="target" id="t-out"><p>existing</p></div></div>
|
|
<form id="f"><div class="target" id="t-in"><p>existing</p></div></form>
|
|
</body></html>`)
|
|
|
|
doc.Find(".target").PrependHtml(`<form><input type="text" name="foo"/></form>`)
|
|
|
|
assertLength(t, doc.Find("#t-out form").Nodes, 1)
|
|
assertLength(t, doc.Find("#t-out form input").Nodes, 1)
|
|
assertLength(t, doc.Find("#t-in form").Nodes, 0)
|
|
assertLength(t, doc.Find("#t-in input").Nodes, 1)
|
|
}
|
|
|
|
func TestSetHtmlFormAncestorContext(t *testing.T) {
|
|
doc := loadString(t, `<html><body>
|
|
<div id="out"><div class="target" id="t-out"><p>old</p></div></div>
|
|
<form id="f"><div class="target" id="t-in"><p>old</p></div></form>
|
|
</body></html>`)
|
|
|
|
doc.Find(".target").SetHtml(`<form><input type="text" name="foo"/></form>`)
|
|
|
|
assertLength(t, doc.Find("#t-out form").Nodes, 1)
|
|
assertLength(t, doc.Find("#t-out form input").Nodes, 1)
|
|
assertLength(t, doc.Find("#t-in form").Nodes, 0)
|
|
assertLength(t, doc.Find("#t-in input").Nodes, 1)
|
|
}
|