lib/capybara/poltergeist/client/browser.coffee in poltergeist-0.4.0 vs lib/capybara/poltergeist/client/browser.coffee in poltergeist-0.5.0
- old
+ new
@@ -1,61 +1,83 @@
class Poltergeist.Browser
constructor: (@owner) ->
- @state = 'default'
+ @state = 'default'
+ @page_id = 0
+
this.resetPage()
resetPage: ->
@page.release() if @page?
-
@page = new Poltergeist.WebPage
@page.onLoadStarted = =>
@state = 'loading' if @state == 'clicked'
@page.onLoadFinished = (status) =>
if @state == 'loading'
- @owner.sendResponse(status)
+ this.sendResponse(status)
@state = 'default'
+ @page.onInitialized = =>
+ @page_id += 1
+
+ sendResponse: (response) ->
+ errors = @page.errors()
+
+ if errors.length > 0
+ @page.clearErrors()
+ @owner.sendError(new Poltergeist.JavascriptError(errors))
+ else
+ @owner.sendResponse(response)
+
+ node: (page_id, id) ->
+ if page_id == @page_id
+ @page.get(id)
+ else
+ throw new Poltergeist.ObsoleteNode
+
visit: (url) ->
@state = 'loading'
@page.open(url)
current_url: ->
- @owner.sendResponse @page.currentUrl()
+ this.sendResponse @page.currentUrl()
body: ->
- @owner.sendResponse @page.content()
+ this.sendResponse @page.content()
source: ->
- @owner.sendResponse @page.source()
+ this.sendResponse @page.source()
- find: (selector, id) ->
- @owner.sendResponse @page.find(selector, id)
+ find: (selector) ->
+ this.sendResponse(page_id: @page_id, ids: @page.find(selector))
- text: (id) ->
- @owner.sendResponse @page.get(id).text()
+ find_within: (page_id, id, selector) ->
+ this.sendResponse this.node(page_id, id).find(selector)
- attribute: (id, name) ->
- @owner.sendResponse @page.get(id).getAttribute(name)
+ text: (page_id, id) ->
+ this.sendResponse this.node(page_id, id).text()
- value: (id) ->
- @owner.sendResponse @page.get(id).value()
+ attribute: (page_id, id, name) ->
+ this.sendResponse this.node(page_id, id).getAttribute(name)
- set: (id, value) ->
- @page.get(id).set(value)
- @owner.sendResponse(true)
+ value: (page_id, id) ->
+ this.sendResponse this.node(page_id, id).value()
+ set: (page_id, id, value) ->
+ this.node(page_id, id).set(value)
+ this.sendResponse(true)
+
# PhantomJS only allows us to reference the element by CSS selector, not XPath,
# so we have to add an attribute to the element to identify it, then remove it
# afterwards.
#
# PhantomJS does not support multiple-file inputs, so we have to blatently cheat
# by temporarily changing it to a single-file input. This obviously could break
# things in various ways, which is not ideal, but it works in the simplest case.
- select_file: (id, value) ->
- element = @page.get(id)
+ select_file: (page_id, id, value) ->
+ element = this.node(page_id, id)
multiple = element.isMultiple()
element.removeAttribute('multiple') if multiple
element.setAttribute('_poltergeist_selected', '')
@@ -63,65 +85,65 @@
@page.uploadFile('[_poltergeist_selected]', value)
element.removeAttribute('_poltergeist_selected')
element.setAttribute('multiple', 'multiple') if multiple
- @owner.sendResponse(true)
+ this.sendResponse(true)
- select: (id, value) ->
- @owner.sendResponse @page.get(id).select(value)
+ select: (page_id, id, value) ->
+ this.sendResponse this.node(page_id, id).select(value)
- tag_name: (id) ->
- @owner.sendResponse @page.get(id).tagName()
+ tag_name: (page_id, id) ->
+ this.sendResponse this.node(page_id, id).tagName()
- visible: (id) ->
- @owner.sendResponse @page.get(id).isVisible()
+ visible: (page_id, id) ->
+ this.sendResponse this.node(page_id, id).isVisible()
evaluate: (script) ->
- @owner.sendResponse JSON.parse(@page.evaluate("function() { return JSON.stringify(#{script}) }"))
+ this.sendResponse JSON.parse(@page.evaluate("function() { return JSON.stringify(#{script}) }"))
execute: (script) ->
@page.execute("function() { #{script} }")
- @owner.sendResponse(true)
+ this.sendResponse(true)
push_frame: (id) ->
@page.pushFrame(id)
- @owner.sendResponse(true)
+ this.sendResponse(true)
pop_frame: ->
@page.popFrame()
- @owner.sendResponse(true)
+ this.sendResponse(true)
- click: (id) ->
+ click: (page_id, id) ->
# If the click event triggers onLoadStarted, we will transition to the 'loading'
# state and wait for onLoadFinished before sending a response.
@state = 'clicked'
- @page.get(id).click()
+ this.node(page_id, id).click()
# Use a timeout in order to let the stack clear, so that the @page.onLoadStarted
# callback can (possibly) fire, before we decide whether to send a response.
setTimeout(
=>
if @state == 'clicked'
@state = 'default'
- @owner.sendResponse(true)
+ this.sendResponse(true)
,
10
)
- drag: (id, other_id) ->
- @page.get(id).dragTo(@page.get(other_id))
- @owner.sendResponse(true)
+ drag: (page_id, id, other_id) ->
+ this.node(page_id, id).dragTo(@page.get(other_id))
+ this.sendResponse(true)
- trigger: (id, event) ->
- @page.get(id).trigger(event)
- @owner.sendResponse(event)
+ trigger: (page_id, id, event) ->
+ this.node(page_id, id).trigger(event)
+ this.sendResponse(event)
reset: ->
this.resetPage()
- @owner.sendResponse(true)
+ this.sendResponse(true)
render: (path, full) ->
dimensions = @page.validatedDimensions()
document = dimensions.document
viewport = dimensions.viewport
@@ -133,14 +155,14 @@
@page.setScrollPosition(left: dimensions.left, top: dimensions.top)
else
@page.setClipRect(left: 0, top: 0, width: viewport.width, height: viewport.height)
@page.render(path)
- @owner.sendResponse(true)
+ this.sendResponse(true)
resize: (width, height) ->
@page.setViewportSize(width: width, height: height)
- @owner.sendResponse(true)
+ this.sendResponse(true)
exit: ->
phantom.exit()
noop: ->