Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Workaround for the tricky getElementById("foo").querySelector("#foo .…

…bar")

behavior that JSDOM doesn't get quite right.
  • Loading branch information...
commit 37f6b053fb781dd971022d04f92070e8257982b6 1 parent 99f6e9e
@assaf authored
View
7 CHANGELOG.md
@@ -10,8 +10,11 @@ callback.
To use promises and duration function, call `wait` with two arguments, second
one being `null`.
- 496 tests
- 12.1 sec to complete
+Workaround for the tricky `getElementById("foo").querySelector("#foo .bar")`
+behavior that JSDOM doesn't get quite right.
+
+ 500 tests
+ 12.3 sec to complete
## Version 1.1.4 2012-05-22
View
3  Makefile
@@ -100,5 +100,6 @@ publish : build doc man7
git push
git tag v$(version)
git push --tags origin master
- make publish-docs clean
+ make publish-docs
+ make clean
View
5 lib/zombie/browser.coffee
@@ -226,18 +226,19 @@ class Browser extends EventEmitter
# Evaluates the CSS selector against the document (or context node) and return array of nodes.
# (Unlike `document.querySelectorAll` that returns a node list).
queryAll: (selector, context)->
- context ||= @document.documentElement
if selector
+ context ||= @document
ret = context.querySelectorAll(selector)
return Array.prototype.slice.call(ret, 0)
else
+ context ||= @document.documentElement
return [context]
# ### browser.query(selector, context?) => Element
#
# Evaluates the CSS selector against the document (or context node) and return an element.
query: (selector, context)->
- context ||= @document.documentElement
+ context ||= @document
if selector
context.querySelector(selector)
else
View
1  lib/zombie/history.coffee
@@ -74,7 +74,6 @@ class History
jsdom_opts =
deferClose: true
features:
- QuerySelector: true
MutationEvents: "2.0"
ProcessExternalResources: []
FetchExternalResources: ["iframe"]
View
41 lib/zombie/jsdom_patches.coffee
@@ -1,6 +1,7 @@
# Fix things that JSDOM doesn't do quite right.
-HTML = require("jsdom").dom.level3.html
-URL = require("url")
+createSizzle = require("../../node_modules/jsdom/lib/jsdom/selectors/sizzle")
+HTML = require("jsdom").dom.level3.html
+URL = require("url")
HTML.HTMLElement.prototype.__defineGetter__ "offsetLeft", -> 0
@@ -173,3 +174,39 @@ HTML.NodeList.prototype.update = ->
@_version = @_element._version
return @_snapshot
+
+
+HTML.HTMLDocument.prototype.querySelector = (selector)->
+ @_sizzle ||= createSizzle(this)
+ return @_sizzle(selector, this)[0]
+HTML.HTMLDocument.prototype.querySelectorAll = (selector)->
+ @_sizzle ||= createSizzle(this)
+ return new HTML.NodeList(@_sizzle(selector, this))
+
+# True if element is child of context node or any of its children.
+descendantOf = (element, context)->
+ parent = element.parentNode
+ if parent
+ return parent == context || descendantOf(parent, context)
+ else
+ return false
+
+# Here comes the tricky part:
+# getDocumentById("foo").querySelectorAll("#foo div")
+# should magically find the div descendant(s) of #foo, although
+# querySelectorAll can never "see" itself.
+descendants = (element, selector)->
+ document = element.ownerDocument
+ document._sizzle ||= createSizzle(document)
+ unless element.parentNode
+ parent = element.ownerDocument.createElement("div")
+ parent.appendChild(element)
+ element = parent
+ return document._sizzle(selector, element.parentNode || element)
+ .filter((node) -> descendantOf(node, element))
+
+
+HTML.Element.prototype.querySelector = (selector)->
+ return descendants(this, selector)[0]
+HTML.Element.prototype.querySelectorAll = (selector)->
+ return new HTML.NodeList(descendants(this, selector))
View
68 test/selection_test.coffee
@@ -3,8 +3,6 @@
describe "Selection", ->
- browser = new Browser()
-
before (done)->
brains.get "/browser/walking", (req, res)->
res.send """
@@ -24,6 +22,7 @@ describe "Selection", ->
</form>
</div>
<div class="now">Walking Aimlessly</div>
+ <button>Do not press!</button>
</body>
</html>
"""
@@ -44,60 +43,83 @@ describe "Selection", ->
$(function() { Sammy("#main").run("#/"); });
"""
- brains.ready ->
- browser.visit "http://localhost:3003/browser/walking", done
+ brains.ready done
+
+ before (done)->
+ @browser = new Browser()
+ @browser.visit("http://localhost:3003/browser/walking")
+ .then(done, done)
describe "queryAll", ->
it "should return array of nodes", ->
- nodes = browser.queryAll(".now")
+ nodes = @browser.queryAll(".now")
assert.equal nodes.length, 1
describe "query method", ->
it "should return single node", ->
- node = browser.query(".now")
+ node = @browser.query(".now")
assert.equal node.tagName, "DIV"
+ describe "the tricky ID", ->
+ before ->
+ @root = @browser.document.getElementById("main")
+
+ it "should find child from id", ->
+ nodes = @root.querySelectorAll("#main button")
+ assert.equal nodes[0].textContent, "Sign Me Up"
+
+ it "should find child from parent", ->
+ nodes = @root.querySelectorAll("button")
+ assert.equal nodes[0].textContent, "Sign Me Up"
+
+ it "should not re-find element itself", ->
+ nodes = @root.querySelectorAll("#main")
+ assert.equal nodes.length, 0
+
+ it "should not find children of siblings", ->
+ nodes = @root.querySelectorAll("button")
+ assert.equal nodes.length, 1
+
+
describe "query text", ->
it "should query from document", ->
- assert.equal browser.text(".now"), "Walking Aimlessly"
+ assert.equal @browser.text(".now"), "Walking Aimlessly"
it "should query from context (exists)", ->
- assert.equal browser.text(".now"), "Walking Aimlessly"
+ assert.equal @browser.text(".now"), "Walking Aimlessly"
it "should query from context (unrelated)", ->
- assert.equal browser.text(".now", browser.querySelector("form")), ""
+ assert.equal @browser.text(".now", @browser.querySelector("form")), ""
it "should combine multiple elements", ->
- assert.equal browser.text("form label"), "Email Password"
+ assert.equal @browser.text("form label"), "Email Password"
describe "query html", ->
it "should query from document", ->
- assert.equal browser.html(".now"), "<div class=\"now\">Walking Aimlessly</div>"
+ assert.equal @browser.html(".now"), "<div class=\"now\">Walking Aimlessly</div>"
it "should query from context (exists)", ->
- assert.equal browser.html(".now", browser.body), "<div class=\"now\">Walking Aimlessly</div>"
+ assert.equal @browser.html(".now", @browser.body), "<div class=\"now\">Walking Aimlessly</div>"
it "should query from context (unrelated)", ->
- assert.equal browser.html(".now", browser.querySelector("form")), ""
+ assert.equal @browser.html(".now", @browser.querySelector("form")), ""
it "should combine multiple elements", ->
- assert.equal browser.html("title, #main a"), "<title>The Living</title><a href=\"/browser/dead\">Kill</a>"
+ assert.equal @browser.html("title, #main a"), "<title>The Living</title><a href=\"/browser/dead\">Kill</a>"
describe "jQuery", ->
- $ = null
-
before ->
- $ = browser.evaluate('window.jQuery')
+ @$ = @browser.evaluate('window.jQuery')
it "should query by id", ->
- assert.equal $('#main').size(), 1
+ assert.equal @$('#main').size(), 1
it "should query by element name", ->
- assert.equal $('form').attr('action'), '#/dead'
+ assert.equal @$('form').attr('action'), '#/dead'
it "should query by element name (multiple)", ->
- assert.equal $('label').size(), 2
+ assert.equal @$('label').size(), 2
it "should query with descendant selectors", ->
- assert.equal $('body #main a').text(), 'Kill'
+ assert.equal @$('body #main a').text(), 'Kill'
it "should query in context", ->
- assert.equal $('body').find('#main a', 'body').text(), 'Kill'
+ assert.equal @$('body').find('#main a', 'body').text(), 'Kill'
it "should query in context with find()", ->
- assert.equal $('body').find('#main a').text(), 'Kill'
+ assert.equal @$('body').find('#main a').text(), 'Kill'
Please sign in to comment.
Something went wrong with that request. Please try again.