lib/capybara/poltergeist/client/browser.coffee in poltergeist-0.5.0 vs lib/capybara/poltergeist/client/browser.coffee in poltergeist-0.6.0
- old
+ new
@@ -27,16 +27,30 @@
@page.clearErrors()
@owner.sendError(new Poltergeist.JavascriptError(errors))
else
@owner.sendResponse(response)
- node: (page_id, id) ->
+ getNode: (page_id, id, callback) ->
if page_id == @page_id
- @page.get(id)
+ callback.call this, @page.get(id)
else
- throw new Poltergeist.ObsoleteNode
+ @owner.sendError(new Poltergeist.ObsoleteNode)
+ nodeCall: (page_id, id, fn, args...) ->
+ callback = args.pop()
+
+ this.getNode(
+ page_id, id,
+ (node) ->
+ result = node[fn](args...)
+
+ if result instanceof Poltergeist.ObsoleteNode
+ @owner.sendError(result)
+ else
+ callback.call(this, result, node)
+ )
+
visit: (url) ->
@state = 'loading'
@page.open(url)
current_url: ->
@@ -50,55 +64,54 @@
find: (selector) ->
this.sendResponse(page_id: @page_id, ids: @page.find(selector))
find_within: (page_id, id, selector) ->
- this.sendResponse this.node(page_id, id).find(selector)
+ this.nodeCall(page_id, id, 'find', selector, this.sendResponse)
text: (page_id, id) ->
- this.sendResponse this.node(page_id, id).text()
+ this.nodeCall(page_id, id, 'text', this.sendResponse)
attribute: (page_id, id, name) ->
- this.sendResponse this.node(page_id, id).getAttribute(name)
+ this.nodeCall(page_id, id, 'getAttribute', name, this.sendResponse)
value: (page_id, id) ->
- this.sendResponse this.node(page_id, id).value()
+ this.nodeCall(page_id, id, 'value', this.sendResponse)
set: (page_id, id, value) ->
- this.node(page_id, id).set(value)
- this.sendResponse(true)
+ this.nodeCall(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: (page_id, id, value) ->
- element = this.node(page_id, id)
+ this.nodeCall(
+ page_id, id, 'isMultiple',
+ (multiple, node) ->
+ node.removeAttribute('multiple') if multiple
+ node.setAttribute('_poltergeist_selected', '')
- multiple = element.isMultiple()
+ @page.uploadFile('[_poltergeist_selected]', value)
- element.removeAttribute('multiple') if multiple
- element.setAttribute('_poltergeist_selected', '')
+ node.removeAttribute('_poltergeist_selected')
+ node.setAttribute('multiple', 'multiple') if multiple
- @page.uploadFile('[_poltergeist_selected]', value)
+ this.sendResponse(true)
+ )
- element.removeAttribute('_poltergeist_selected')
- element.setAttribute('multiple', 'multiple') if multiple
-
- this.sendResponse(true)
-
select: (page_id, id, value) ->
- this.sendResponse this.node(page_id, id).select(value)
+ this.nodeCall(page_id, id, 'select', value, this.sendResponse)
tag_name: (page_id, id) ->
- this.sendResponse this.node(page_id, id).tagName()
+ this.nodeCall(page_id, id, 'tagName', this.sendResponse)
visible: (page_id, id) ->
- this.sendResponse this.node(page_id, id).isVisible()
+ this.nodeCall(page_id, id, 'isVisible', this.sendResponse)
evaluate: (script) ->
this.sendResponse JSON.parse(@page.evaluate("function() { return JSON.stringify(#{script}) }"))
execute: (script) ->
@@ -112,33 +125,46 @@
pop_frame: ->
@page.popFrame()
this.sendResponse(true)
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'
+ # We just check the node is not obsolete before proceeding. If it is,
+ # the callback will not fire.
+ this.nodeCall(
+ page_id, id, 'isObsolete',
+ (obsolete, node) ->
+ # If the click event triggers onLoadStarted, we will transition to the 'loading'
+ # state and wait for onLoadFinished before sending a response.
+ @state = 'clicked'
- this.node(page_id, id).click()
+ click = node.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'
- this.sendResponse(true)
- ,
- 10
+ # 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'
+
+ if click instanceof Poltergeist.ClickFailed
+ @owner.sendError(click)
+ else
+ this.sendResponse(true)
+ ,
+ 10
+ )
)
drag: (page_id, id, other_id) ->
- this.node(page_id, id).dragTo(@page.get(other_id))
- this.sendResponse(true)
+ this.nodeCall(
+ page_id, id, 'isObsolete'
+ (obsolete, node) ->
+ node.dragTo(@page.get(other_id))
+ this.sendResponse(true)
+ )
trigger: (page_id, id, event) ->
- this.node(page_id, id).trigger(event)
- this.sendResponse(event)
+ this.nodeCall(page_id, id, 'trigger', event, -> this.sendResponse(event))
reset: ->
this.resetPage()
this.sendResponse(true)