lib/capybara/poltergeist/client/browser.coffee in poltergeist-0.6.0 vs lib/capybara/poltergeist/client/browser.coffee in poltergeist-0.7.0

- old
+ new

@@ -1,19 +1,24 @@ class Poltergeist.Browser - constructor: (@owner) -> + constructor: (@owner, width, height) -> + @width = width || 1024 + @height = height || 768 @state = 'default' @page_id = 0 this.resetPage() resetPage: -> @page.release() if @page? - @page = new Poltergeist.WebPage + @page = new Poltergeist.WebPage(@width, @height) @page.onLoadStarted = => @state = 'loading' if @state == 'clicked' + @page.onNavigationRequested = (url, navigation) => + @state = 'loading' if @state == 'clicked' && navigation == 'FormSubmitted' + @page.onLoadFinished = (status) => if @state == 'loading' this.sendResponse(status) @state = 'default' @@ -23,98 +28,78 @@ sendResponse: (response) -> errors = @page.errors() if errors.length > 0 @page.clearErrors() - @owner.sendError(new Poltergeist.JavascriptError(errors)) + throw new Poltergeist.JavascriptError(errors) else @owner.sendResponse(response) - getNode: (page_id, id, callback) -> + node: (page_id, id) -> if page_id == @page_id - callback.call this, @page.get(id) + @page.get(id) else - @owner.sendError(new Poltergeist.ObsoleteNode) + throw 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) -> + visit: (url, headers) -> @state = 'loading' - @page.open(url) + @page.open(url, operation: "get", headers: headers) current_url: -> this.sendResponse @page.currentUrl() + status_code: -> + this.sendResponse @page.statusCode() + body: -> this.sendResponse @page.content() source: -> this.sendResponse @page.source() find: (selector) -> this.sendResponse(page_id: @page_id, ids: @page.find(selector)) find_within: (page_id, id, selector) -> - this.nodeCall(page_id, id, 'find', selector, this.sendResponse) + this.sendResponse this.node(page_id, id).find(selector) text: (page_id, id) -> - this.nodeCall(page_id, id, 'text', this.sendResponse) + this.sendResponse this.node(page_id, id).text() attribute: (page_id, id, name) -> - this.nodeCall(page_id, id, 'getAttribute', name, this.sendResponse) + this.sendResponse this.node(page_id, id).getAttribute(name) value: (page_id, id) -> - this.nodeCall(page_id, id, 'value', this.sendResponse) + this.sendResponse this.node(page_id, id).value() set: (page_id, id, value) -> - this.nodeCall(page_id, id, 'set', value, -> this.sendResponse(true)) + 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: (page_id, id, value) -> - this.nodeCall( - page_id, id, 'isMultiple', - (multiple, node) -> - node.removeAttribute('multiple') if multiple - node.setAttribute('_poltergeist_selected', '') + node = this.node(page_id, id) - @page.uploadFile('[_poltergeist_selected]', value) + node.setAttribute('_poltergeist_selected', '') + @page.uploadFile('[_poltergeist_selected]', value) + node.removeAttribute('_poltergeist_selected') - node.removeAttribute('_poltergeist_selected') - node.setAttribute('multiple', 'multiple') if multiple + this.sendResponse(true) - this.sendResponse(true) - ) - select: (page_id, id, value) -> - this.nodeCall(page_id, id, 'select', value, this.sendResponse) + this.sendResponse this.node(page_id, id).select(value) tag_name: (page_id, id) -> - this.nodeCall(page_id, id, 'tagName', this.sendResponse) + this.sendResponse this.node(page_id, id).tagName() visible: (page_id, id) -> - this.nodeCall(page_id, id, 'isVisible', this.sendResponse) + this.sendResponse this.node(page_id, id).isVisible() evaluate: (script) -> - this.sendResponse JSON.parse(@page.evaluate("function() { return JSON.stringify(#{script}) }")) + this.sendResponse @page.evaluate("function() { return #{script} }") execute: (script) -> @page.execute("function() { #{script} }") this.sendResponse(true) @@ -125,48 +110,34 @@ pop_frame: -> @page.popFrame() this.sendResponse(true) click: (page_id, id) -> - # 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' + # Get the node before changing state, in case there is an exception + node = this.node(page_id, id) - click = node.click() + # If the click event triggers onNavigationRequested, we will transition to the 'loading' + # state and wait for onLoadFinished before sending a response. + @state = 'clicked' - # 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' + node.click() - if click instanceof Poltergeist.ClickFailed - @owner.sendError(click) - else - this.sendResponse(true) - , - 10 - ) - ) + if @state != 'loading' + @state = 'default' + this.sendResponse(true) drag: (page_id, id, other_id) -> - this.nodeCall( - page_id, id, 'isObsolete' - (obsolete, node) -> - node.dragTo(@page.get(other_id)) - this.sendResponse(true) - ) + this.node(page_id, id).dragTo this.node(page_id, other_id) + this.sendResponse(true) trigger: (page_id, id, event) -> - this.nodeCall(page_id, id, 'trigger', event, -> this.sendResponse(event)) + this.node(page_id, id).trigger(event) + this.sendResponse(event) + equals: (page_id, id, other_id) -> + this.sendResponse this.node(page_id, id).isEqual(this.node(page_id, other_id)) + reset: -> this.resetPage() this.sendResponse(true) render: (path, full) -> @@ -187,10 +158,17 @@ resize: (width, height) -> @page.setViewportSize(width: width, height: height) this.sendResponse(true) + network_traffic: -> + this.sendResponse(@page.networkTraffic()) + exit: -> phantom.exit() noop: -> # NOOOOOOP! + + # This command is purely for testing error handling + browser_error: -> + throw new Error('zomg')