Skip to content

Commit

Permalink
Added browser.loadCSS and browser.htmlParser options.
Browse files Browse the repository at this point in the history
Switched default parser to htmlparser.

Few more tests passing.
  • Loading branch information
assaf committed Aug 24, 2011
1 parent f230c4d commit 2022e1b
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 28 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
@@ -1,6 +1,17 @@
zombie.js-changelog(7) -- Changelog
===================================

### Version 0.10.0 Pending

Added `browser.loadCSS` option. Set this to load external stylesheets.
Defaults to `true`.

Added `browser.htmlParser` option. Tells JSDOM which HTML5 parser to
use. Use `null` for the default parser.

Changed the default parser from `HTML5` to `htmlparser`.


### Version 0.9.7 2011-07-28

Fixed: require.paths is deprecated [#158]
Expand Down
1 change: 0 additions & 1 deletion package.json
Expand Up @@ -37,7 +37,6 @@
"node": ">= 0.4.0"
},
"dependencies": {
"html5": "~0.3.0",
"jsdom": "~0.2.3",
"mime": "~1.2.2",
"websocket-client": "~1.0.0"
Expand Down
48 changes: 27 additions & 21 deletions spec/browser-spec.coffee
@@ -1,5 +1,6 @@
require "./helpers"
{ vows: vows, assert: assert, zombie: zombie, brains: brains } = require("vows")
Browser = zombie.Browser
jsdom = require("jsdom")

brains.get "/static", (req, res)-> res.send """
Expand Down Expand Up @@ -85,7 +86,8 @@ brains.get "/soup", (req, res)-> res.send """
<p>And another
"""

brains.get "/useragent", (req, res)-> res.send "<body>#{req.headers["user-agent"]}</body>"
brains.get "/useragent", (req, res)->
res.send "<html><body>#{req.headers["user-agent"]}</body></html>"

brains.get "/iframe", (req, res)-> res.send """
<html>
Expand Down Expand Up @@ -115,17 +117,17 @@ vows.describe("Browser").addBatch(
"successful":
topic: ->
brains.ready =>
browser = new zombie.Browser
browser = new Browser
browser.visit "http://localhost:3003/scripted", =>
@callback null, arguments
"should pass three arguments to callback": (args)-> assert.length args, 3
"should not include an error": (args)-> assert.isNull args[0]
"should pass browser to callback": (args)-> assert.ok args[1] instanceof zombie.Browser
"should pass browser to callback": (args)-> assert.ok args[1] instanceof Browser
"should pass status code to callback": (args)-> assert.equal args[2], 200
"error":
topic: ->
brains.ready =>
browser = new zombie.Browser
browser = new Browser
browser.visit "http://localhost:3003/missing", =>
@callback null, arguments
"should pass single argument to callback": (args)-> assert.length args, 1
Expand All @@ -140,14 +142,14 @@ vows.describe("Browser").addBatch(
"successful":
topic: ->
brains.ready =>
browser = new zombie.Browser
browser = new Browser
browser.on "loaded", (browser)=> @callback null, browser
browser.window.location = "http://localhost:3003/"
"should fire load event": (browser)-> assert.ok browser.visit
"error":
topic: ->
brains.ready =>
browser = new zombie.Browser
browser = new Browser
browser.on "error", (err)=> @callback null, err
browser.window.location = "http://localhost:3003/deadend"
"should fire onerror event": (err)->
Expand All @@ -156,7 +158,7 @@ vows.describe("Browser").addBatch(
"wait over":
topic: ->
brains.ready =>
browser = new zombie.Browser
browser = new Browser
browser.on "done", (browser)=> @callback null, browser
browser.window.location = "http://localhost:3003/"
browser.wait()
Expand All @@ -167,15 +169,17 @@ vows.describe("Browser").addBatch(
"query text":
topic: (browser)-> browser
"should query from document": (browser)-> assert.equal browser.text(".now"), "Walking Aimlessly"
"should query from context (exists)": (browser)-> assert.equal browser.text(".now", browser.body), "Walking Aimlessly"
"should query from context (unrelated)": (browser)-> assert.equal browser.text(".now", browser.querySelector("#main")), ""
"should query from context (exists)": (browser)-> assert.equal browser.text(".now"), "Walking Aimlessly"
"should query from context (unrelated)": (browser)->
assert.equal browser.text(".now", browser.querySelector("#main")), ""
"should combine multiple elements": (browser)-> assert.equal browser.text("form label"), "Email Password "
"query html":
topic: (browser)-> browser
"should query from document": (browser)-> assert.equal browser.html(".now"), "<div class=\"now\">Walking Aimlessly</div>"
"should query from context (exists)": (browser)-> assert.equal browser.html(".now", browser.body), "<div class=\"now\">Walking Aimlessly</div>"
"should query from context (unrelated)": (browser)-> assert.equal browser.html(".now", browser.querySelector("#main")), ""
"should combine multiple elements": (browser)-> assert.equal browser.html("title, #main a"), "<title>The Living</title><a href=\"/dead\">Kill</a>"
"should combine multiple elements": (browser)->
assert.equal browser.html("title, #main a"), "<title>The Living</title><a href=\"/dead\">Kill</a>"

"click link":
zombie.wants "http://localhost:3003/living"
Expand All @@ -185,25 +189,27 @@ vows.describe("Browser").addBatch(
"should run all events": (_, browser)-> assert.equal browser.document.title, "The Dead"
"should return status code": (_, browser, status)-> assert.equal status, 200

"tag soup":
zombie.wants "http://localhost:3003/soup"
"should parse to complete HTML": (browser)->
assert.ok browser.querySelector("html head")
assert.equal browser.text("html body h1"), "Tag soup"
"should close tags": (browser)->
paras = browser.querySelectorAll("body p").toArray().map((e)-> e.textContent.trim())
assert.deepEqual paras, ["One paragraph", "And another"]
"tag soup using HTML5 parser":
topic: ->
browser = new Browser
browser.wants "http://localhost:3003/soup", { htmlParser: require("html5").HTML5 }, @callback
"should parse to complete HTML": (browser)->
assert.ok browser.querySelector("html head")
assert.equal browser.text("html body h1"), "Tag soup"
"should close tags": (browser)->
paras = browser.querySelectorAll("body p").toArray().map((e)-> e.textContent.trim())
assert.deepEqual paras, ["One paragraph", "And another"]

"with options":
topic: ->
browser = new zombie.Browser
browser = new Browser
browser.wants "http://localhost:3003/scripted", { runScripts: false }, @callback
"should set options for the duration of the request": (browser)-> assert.equal browser.document.title, "Whatever"
"should reset options following the request": (browser)-> assert.isTrue browser.runScripts

"user agent":
topic: ->
browser = new zombie.Browser
browser = new Browser
browser.wants "http://localhost:3003/useragent", @callback
"should send own version to server": (browser)-> assert.match browser.text("body"), /Zombie.js\/\d\.\d/
"should be accessible from navigator": (browser)-> assert.match browser.window.navigator.userAgent, /Zombie.js\/\d\.\d/
Expand Down Expand Up @@ -239,7 +245,7 @@ vows.describe("Browser").addBatch(

"fork":
topic: ->
browser = new zombie.Browser
browser = new Browser
browser.visit("http://localhost:3003/living")
browser.wait()
browser.cookies("www.localhost").update("foo=bar; domain=.localhost")
Expand Down
6 changes: 4 additions & 2 deletions spec/helpers.coffee
Expand Up @@ -2,6 +2,7 @@ require.paths.unshift __dirname + "/../node_modules"
fs = require("fs")
express = require("express")
zombie = require("../src/index")
Browser = zombie.Browser
debug = process.env.DEBUG || process.env.TRAVIS


Expand Down Expand Up @@ -58,7 +59,8 @@ brains.ready = (callback)->
zombie.wants = (url, context)->
topic = context.topic
context.topic = ->
new zombie.Browser().wants url, {}, (err, browser)=>
browser = new Browser
browser.wants url, {}, (err, browser)=>
if topic
try
value = topic.call(this, browser)
Expand All @@ -71,7 +73,7 @@ zombie.wants = (url, context)->
return
return context

zombie.Browser.prototype.wants = (url, options, callback)->
Browser.prototype.wants = (url, options, callback)->
brains.ready =>
options.debug = debug
@visit url, options, (err, browser)=>
Expand Down
13 changes: 11 additions & 2 deletions src/zombie/browser.coffee
Expand Up @@ -32,12 +32,21 @@ class Browser extends require("events").EventEmitter
# Options
# -------

@OPTIONS = ["debug", "runScripts", "userAgent"]
OPTIONS = ["debug", "htmlParser", "loadCSS", "runScripts", "userAgent"]

# ### debug
#
# True to have Zombie report what it's doing.
@debug = false
# ### htmlParser
#
# Which parser to use (null for default). For example:
# zombie.htmlParser = require("html5").HTML5
@htmlParser = null
# ### loadCSS
#
# True to load external stylesheets.
@loadCSS = true
# ### runScripts
#
# Run scripts included in or loaded from the page. Defaults to true.
Expand Down Expand Up @@ -65,7 +74,7 @@ class Browser extends require("events").EventEmitter
# Sets the browser options.
if options
for k,v of options
if @OPTIONS.indexOf(k) >= 0
if OPTIONS.indexOf(k) >= 0
@[k] = v
else
throw "I don't recognize the option #{k}"
Expand Down
7 changes: 5 additions & 2 deletions src/zombie/history.coffee
Expand Up @@ -71,16 +71,19 @@ class History
QuerySelector: true
MutationEvents: "2.0"
ProcessExternalResources: []
FetchExternalResources: ["css", "frame"]
parser: require("html5").HTML5
FetchExternalResources: ["frame"]
parser: browser.htmlParser
url: URL.format(url)
if browser.runScripts
options.features.ProcessExternalResources.push "script"
options.features.FetchExternalResources.push "script"
if browser.loadCSS
options.features.FetchExternalResources.push "css"
document = jsdom.jsdom(null, jsdom.dom.level3.core, options)
browser.window.document = document
document.window = document.parentWindow = browser.window
document.fixQueue()
document.fixQuerySelector()

headers = if headers then JSON.parse(JSON.stringify(headers)) else {}
referer = stack[index-1]?.url
Expand Down
8 changes: 8 additions & 0 deletions src/zombie/jsdom_patches.coffee
Expand Up @@ -117,3 +117,11 @@ core.HTMLDocument.prototype.fixQueue = ->
item.err = err
item.data = data
item.check()


# JSDOM el.querySelectorAll selects from the parent.
Sizzle = require("jsdom/lib/jsdom/selectors/sizzle").Sizzle
core.HTMLDocument.prototype.fixQuerySelector = ->
core.Element.prototype.querySelectorAll = (selector)->
new core.NodeList(@ownerDocument, => Sizzle(selector, this))

0 comments on commit 2022e1b

Please sign in to comment.