mirror of
https://github.com/PuerkitoBio/goquery.git
synced 2024-04-21 12:31:36 +00:00
add tests for End() rollbacks, doc
This commit is contained in:
@@ -37,8 +37,8 @@ Coming soon...
|
||||
## TODOs
|
||||
|
||||
* Implement NextUntil() and PrevUntil().
|
||||
* Check each method, make sure it uses only ElementNodes except when explicitly specified (i.e.: `Contents()`). Cascadia's selectors act only on elements.
|
||||
* Tests to validate that all methods returning a new `*Selection` "rollback" correctly to the previous Selection when calling `.End()`.
|
||||
* Fix Prev...() functions to return nodes in the same order as jQuery (starting with the immediately preceding node, up until first child of the parent).
|
||||
* Tests to validate that all methods returning a new `*Selection` "rollback" correctly to the previous Selection when calling `.End()`. Done for array, expand and filter.
|
||||
* Benchmarks so that future changes have a baseline to compare to.
|
||||
* Add jQuery's `Closest()`? Other missing functions?
|
||||
* Support negative indices in `Slice()`, like jQuery.
|
||||
|
||||
@@ -47,20 +47,8 @@ func (this *Selection) Get(index int) *html.Node {
|
||||
// Index() returns the position of the first element within the Selection object
|
||||
// relative to its sibling elements.
|
||||
func (this *Selection) Index() int {
|
||||
// TODO : Eventually refactor with prevAll(), like jQuery's code
|
||||
if len(this.Nodes) > 0 {
|
||||
n := this.Nodes[0]
|
||||
if p := n.Parent; p != nil {
|
||||
var i = 0
|
||||
for _, c := range p.Child {
|
||||
if c == n {
|
||||
// This is the index of the element
|
||||
return i
|
||||
} else if c.Type == html.ElementNode {
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
||||
return newSingleSelection(this.Nodes[0], this.document).PrevAll().Length()
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@ func TestFirstEmpty(t *testing.T) {
|
||||
Doc().Root.Find(".pvk-zzcontentzz").First()
|
||||
}
|
||||
|
||||
func TestFirstRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.First().End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestLast(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content").Last()
|
||||
AssertLength(t, sel.Nodes, 1)
|
||||
@@ -25,6 +31,12 @@ func TestLast(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLastRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.Last().End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestEq(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content").Eq(1)
|
||||
AssertLength(t, sel.Nodes, 1)
|
||||
@@ -41,6 +53,12 @@ func TestEqNegative(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.Eq(1).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestSlice(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content").Slice(0, 2)
|
||||
|
||||
@@ -52,6 +70,12 @@ func TestSliceOutOfBounds(t *testing.T) {
|
||||
Doc().Root.Find(".pvk-content").Slice(2, 12)
|
||||
}
|
||||
|
||||
func TestSliceRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.Slice(0, 2).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
node := sel.Get(1)
|
||||
|
||||
@@ -51,6 +51,11 @@ The various methods are split into files based on the category of behavior:
|
||||
- Last()
|
||||
- Slice()
|
||||
|
||||
* expand.go : methods that expand or augment the selection's set.
|
||||
- Add...()
|
||||
- AndSelf()
|
||||
- Union(), which is an alias for AddSelection()
|
||||
|
||||
* filter.go : filtering methods, that reduce the selection's set.
|
||||
- End()
|
||||
- Filter...()
|
||||
@@ -58,15 +63,9 @@ The various methods are split into files based on the category of behavior:
|
||||
- Intersection(), which is an alias of FilterSelection()
|
||||
- Not...()
|
||||
|
||||
* expand.go : methods that expand or augment the selection's set.
|
||||
- Add...()
|
||||
- AndSelf()
|
||||
- Union(), which is an alias for AddSelection()
|
||||
|
||||
* query.go : methods that query, or reflect, a node's identity.
|
||||
- Contains()
|
||||
- HasClass()
|
||||
- Is...()
|
||||
* iteration.go : methods to loop over the selection's nodes.
|
||||
- Each()
|
||||
- Map()
|
||||
|
||||
* property.go : methods that inspect and get the node's properties values.
|
||||
- Attr()
|
||||
@@ -75,6 +74,11 @@ The various methods are split into files based on the category of behavior:
|
||||
- Size(), which is an alias for Length()
|
||||
- Text()
|
||||
|
||||
* query.go : methods that query, or reflect, a node's identity.
|
||||
- Contains()
|
||||
- HasClass()
|
||||
- Is...()
|
||||
|
||||
* traversal.go : methods to traverse the HTML document tree.
|
||||
- Children...()
|
||||
- Contents()
|
||||
@@ -84,21 +88,8 @@ The various methods are split into files based on the category of behavior:
|
||||
- Prev...()
|
||||
- Siblings...()
|
||||
|
||||
* iteration.go : methods to loop over the selection's nodes.
|
||||
- Each()
|
||||
- Map()
|
||||
|
||||
* type.go : definition of the types exposed by GoQuery.
|
||||
- Document
|
||||
- Selection
|
||||
*/
|
||||
package goquery
|
||||
|
||||
// DONE array.go : Positional Manipulation: First(), Last(), Eq(), Get(), Index(), Slice()
|
||||
// DONE filter.go : Filtering: Filter(), Not(), Has(), End()
|
||||
// DONE expand.go : "Expanding": Add(), AndSelf()
|
||||
// DONE query.go : Reflect (query) node: Is(), Contains(), HasClass()
|
||||
// DONE property.go : Inspect node: Html(), Text(), Attr(), Length(), Size()
|
||||
// traversal.go : Traversal: Contents(), Find(), Children(), Parents...(), Next...(), Prev...(), Siblings()
|
||||
// DONE iteration.go : Iteration: Each(), Map()
|
||||
// DONE type.go : Selection and Document
|
||||
|
||||
@@ -9,6 +9,12 @@ func TestAdd(t *testing.T) {
|
||||
AssertLength(t, sel.Nodes, 19)
|
||||
}
|
||||
|
||||
func TestAddRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.Add("a").End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestAddSelection(t *testing.T) {
|
||||
sel := Doc().Root.Find("div.row-fluid")
|
||||
sel2 := Doc().Root.Find("a")
|
||||
@@ -24,6 +30,13 @@ func TestAddSelectionNil(t *testing.T) {
|
||||
AssertLength(t, sel.Nodes, 9)
|
||||
}
|
||||
|
||||
func TestAddSelectionRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.Find("a")
|
||||
sel2 = sel.AddSelection(sel2).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestAddNodes(t *testing.T) {
|
||||
sel := Doc().Root.Find("div.pvk-gutter")
|
||||
sel2 := Doc().Root.Find(".pvk-content")
|
||||
@@ -36,7 +49,20 @@ func TestAddNodesNone(t *testing.T) {
|
||||
AssertLength(t, sel.Nodes, 6)
|
||||
}
|
||||
|
||||
func TestAddNodesRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.Find("a")
|
||||
sel2 = sel.AddNodes(sel2.Nodes...).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestAndSelf(t *testing.T) {
|
||||
sel := Doc().Root.Find(".span12").Last().AndSelf()
|
||||
AssertLength(t, sel.Nodes, 2)
|
||||
}
|
||||
|
||||
func TestAndSelfRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.Find("a").AndSelf().End().End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,12 @@ func TestFilterNone(t *testing.T) {
|
||||
AssertLength(t, sel.Nodes, 0)
|
||||
}
|
||||
|
||||
func TestFilterRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.Filter(".alert").End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestFilterFunction(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content").FilterFunction(func(i int, s *Selection) bool {
|
||||
return i > 0
|
||||
@@ -21,12 +27,26 @@ func TestFilterFunction(t *testing.T) {
|
||||
AssertLength(t, sel.Nodes, 2)
|
||||
}
|
||||
|
||||
func TestFilterFunctionRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.FilterFunction(func(i int, s *Selection) bool {
|
||||
return i > 0
|
||||
}).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestFilterNode(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.FilterNodes(sel.Nodes[2])
|
||||
AssertLength(t, sel2.Nodes, 1)
|
||||
}
|
||||
|
||||
func TestFilterNodeRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.FilterNodes(sel.Nodes[2]).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestFilterSelection(t *testing.T) {
|
||||
sel := Doc().Root.Find(".link")
|
||||
sel2 := Doc().Root.Find("a[ng-click]")
|
||||
@@ -34,6 +54,13 @@ func TestFilterSelection(t *testing.T) {
|
||||
AssertLength(t, sel3.Nodes, 1)
|
||||
}
|
||||
|
||||
func TestFilterSelectionRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".link")
|
||||
sel2 := Doc().Root.Find("a[ng-click]")
|
||||
sel2 = sel.FilterSelection(sel2).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestFilterSelectionNil(t *testing.T) {
|
||||
var sel2 *Selection
|
||||
|
||||
@@ -47,6 +74,12 @@ func TestNot(t *testing.T) {
|
||||
AssertLength(t, sel.Nodes, 1)
|
||||
}
|
||||
|
||||
func TestNotRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".span12")
|
||||
sel2 := sel.Not(".alert").End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestNotNone(t *testing.T) {
|
||||
sel := Doc().Root.Find(".span12").Not(".zzalert")
|
||||
AssertLength(t, sel.Nodes, 2)
|
||||
@@ -59,12 +92,26 @@ func TestNotFunction(t *testing.T) {
|
||||
AssertLength(t, sel.Nodes, 1)
|
||||
}
|
||||
|
||||
func TestNotFunctionRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.NotFunction(func(i int, s *Selection) bool {
|
||||
return i > 0
|
||||
}).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestNotNode(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.NotNodes(sel.Nodes[2])
|
||||
AssertLength(t, sel2.Nodes, 2)
|
||||
}
|
||||
|
||||
func TestNotNodeRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-content")
|
||||
sel2 := sel.NotNodes(sel.Nodes[2]).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestNotSelection(t *testing.T) {
|
||||
sel := Doc().Root.Find(".link")
|
||||
sel2 := Doc().Root.Find("a[ng-click]")
|
||||
@@ -72,18 +119,38 @@ func TestNotSelection(t *testing.T) {
|
||||
AssertLength(t, sel3.Nodes, 6)
|
||||
}
|
||||
|
||||
func TestNotSelectionRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".link")
|
||||
sel2 := Doc().Root.Find("a[ng-click]")
|
||||
sel2 = sel.NotSelection(sel2).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestIntersection(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-gutter")
|
||||
sel2 := Doc().Root.Find("div").Intersection(sel)
|
||||
AssertLength(t, sel2.Nodes, 6)
|
||||
}
|
||||
|
||||
func TestIntersectionRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".pvk-gutter")
|
||||
sel2 := Doc().Root.Find("div")
|
||||
sel2 = sel.Intersection(sel2).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestHas(t *testing.T) {
|
||||
sel := Doc().Root.Find(".container-fluid").Has(".center-content")
|
||||
AssertLength(t, sel.Nodes, 2)
|
||||
// Has() returns the high-level .container-fluid div, and the one that is the immediate parent of center-content
|
||||
}
|
||||
|
||||
func TestHasRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".container-fluid")
|
||||
sel2 := sel.Has(".center-content").End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestHasNodes(t *testing.T) {
|
||||
sel := Doc().Root.Find(".container-fluid")
|
||||
sel2 := Doc().Root.Find(".center-content")
|
||||
@@ -92,6 +159,13 @@ func TestHasNodes(t *testing.T) {
|
||||
// Has() returns the high-level .container-fluid div, and the one that is the immediate parent of center-content
|
||||
}
|
||||
|
||||
func TestHasNodesRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find(".container-fluid")
|
||||
sel2 := Doc().Root.Find(".center-content")
|
||||
sel2 = sel.HasNodes(sel2.Nodes...).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestHasSelection(t *testing.T) {
|
||||
sel := Doc().Root.Find("p")
|
||||
sel2 := Doc().Root.Find("small")
|
||||
@@ -99,6 +173,13 @@ func TestHasSelection(t *testing.T) {
|
||||
AssertLength(t, sel.Nodes, 1)
|
||||
}
|
||||
|
||||
func TestHasSelectionRollback(t *testing.T) {
|
||||
sel := Doc().Root.Find("p")
|
||||
sel2 := Doc().Root.Find("small")
|
||||
sel2 = sel.HasSelection(sel2).End()
|
||||
AssertEqual(t, sel, sel2)
|
||||
}
|
||||
|
||||
func TestEnd(t *testing.T) {
|
||||
sel := Doc().Root.Find("p").Has("small").End()
|
||||
AssertLength(t, sel.Nodes, 4)
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package goquery
|
||||
|
||||
// Each() iterates over a Selection object, executing a function for each
|
||||
// matched element.
|
||||
// matched element. It returns the current Selection object.
|
||||
func (this *Selection) Each(f func(int, *Selection)) *Selection {
|
||||
for i, n := range this.Nodes {
|
||||
f(i, newSingleSelection(n, this.document))
|
||||
|
||||
+2
-2
@@ -20,6 +20,7 @@ func (this *Selection) Attr(attrName string) (val string, exists bool) {
|
||||
func (this *Selection) Text() string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
// Slightly optimized vs calling Each(): no single selection object created
|
||||
for _, n := range this.Nodes {
|
||||
buf.WriteString(getNodeText(n))
|
||||
}
|
||||
@@ -37,7 +38,7 @@ func (this *Selection) Length() int {
|
||||
}
|
||||
|
||||
// Html() gets the HTML contents of the first element in the set of matched
|
||||
// elements.
|
||||
// elements. It includes text and comment nodes.
|
||||
func (this *Selection) Html() (ret string, e error) {
|
||||
// Since there is no .innerHtml, the HTML content must be re-created from
|
||||
// the nodes usint html.Render().
|
||||
@@ -59,7 +60,6 @@ func (this *Selection) Html() (ret string, e error) {
|
||||
// Get the specified node's text content.
|
||||
func getNodeText(node *html.Node) string {
|
||||
if node.Type == html.TextNode {
|
||||
//ret = strings.Trim(node.Data, " \t\r\n")
|
||||
// Keep newlines and spaces, like jQuery
|
||||
return node.Data
|
||||
} else if len(node.Child) > 0 {
|
||||
|
||||
@@ -39,19 +39,19 @@ func (this *Selection) Is(selector string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Is() checks the current matched set of elements against a predicate and
|
||||
// IsFunction() checks the current matched set of elements against a predicate and
|
||||
// returns true if at least one of these elements matches.
|
||||
func (this *Selection) IsFunction(f func(int, *Selection) bool) bool {
|
||||
return this.FilterFunction(f).Length() > 0
|
||||
}
|
||||
|
||||
// Is() checks the current matched set of elements against a Selection object
|
||||
// IsSelection() checks the current matched set of elements against a Selection object
|
||||
// and returns true if at least one of these elements matches.
|
||||
func (this *Selection) IsSelection(s *Selection) bool {
|
||||
return this.FilterSelection(s).Length() > 0
|
||||
}
|
||||
|
||||
// Is() checks the current matched set of elements against the specified nodes
|
||||
// IsNodes() checks the current matched set of elements against the specified nodes
|
||||
// and returns true if at least one of these elements matches.
|
||||
func (this *Selection) IsNodes(nodes ...*html.Node) bool {
|
||||
return this.FilterNodes(nodes...).Length() > 0
|
||||
|
||||
+10
-4
@@ -10,11 +10,13 @@ type siblingType int
|
||||
// Sibling type, used internally when iterating over children at the same
|
||||
// level (siblings) to specify which nodes are requested.
|
||||
const (
|
||||
siblintPrevAll siblingType = iota - 2
|
||||
siblingPrevUntil siblingType = iota - 3
|
||||
siblingPrevAll
|
||||
siblingPrev
|
||||
siblingAll
|
||||
siblingNext
|
||||
siblingNextAll
|
||||
siblingNextUntil
|
||||
siblingAllIncludingNonElements
|
||||
)
|
||||
|
||||
@@ -206,14 +208,14 @@ func (this *Selection) PrevFiltered(selector string) *Selection {
|
||||
// PrevAll() gets all the preceding siblings of each element in the
|
||||
// Selection. It returns a new Selection object containing the matched elements.
|
||||
func (this *Selection) PrevAll() *Selection {
|
||||
return pushStack(this, getSiblingNodes(this.Nodes, siblintPrevAll))
|
||||
return pushStack(this, getSiblingNodes(this.Nodes, siblingPrevAll))
|
||||
}
|
||||
|
||||
// PrevAllFiltered() gets all the preceding siblings of each element in the
|
||||
// Selection filtered by a selector. It returns a new Selection object
|
||||
// containing the matched elements.
|
||||
func (this *Selection) PrevAllFiltered(selector string) *Selection {
|
||||
return filterAndPush(this, getSiblingNodes(this.Nodes, siblintPrevAll), selector)
|
||||
return filterAndPush(this, getSiblingNodes(this.Nodes, siblingPrevAll), selector)
|
||||
}
|
||||
|
||||
// Filter and push filters the nodes based on a selector, and pushes the results
|
||||
@@ -314,7 +316,11 @@ func getChildrenWithSiblingType(parent *html.Node, st siblingType, skipNode *htm
|
||||
|
||||
// If child is not the current node, check if sibling type requires
|
||||
// to add it to the result.
|
||||
if c != skipNode && (st == siblingAll || st == siblingAllIncludingNonElements || (st == siblintPrevAll && !nFound) || (st == siblingNextAll && nFound)) {
|
||||
if c != skipNode &&
|
||||
(st == siblingAll ||
|
||||
st == siblingAllIncludingNonElements ||
|
||||
(st == siblingPrevAll && !nFound) ||
|
||||
(st == siblingNextAll && nFound)) {
|
||||
result = append(result, c)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,12 @@ func AssertPanic(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func AssertEqual(t *testing.T, s1 *Selection, s2 *Selection) {
|
||||
if s1 != s2 {
|
||||
t.Error("Expected selection objects to be the same.")
|
||||
}
|
||||
}
|
||||
|
||||
func EnsureDocLoaded() {
|
||||
if f, e := os.Open("./testdata/page.html"); e != nil {
|
||||
panic(e.Error())
|
||||
|
||||
Reference in New Issue
Block a user