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

- old
+ new

@@ -1,51 +1,77 @@ class Poltergeist.Browser constructor: (@owner, width, height) -> - @width = width || 1024 - @height = height || 768 - @state = 'default' - @page_id = 0 + @width = width || 1024 + @height = height || 768 + @state = 'default' + @page_stack = [] + @page_id = 0 this.resetPage() resetPage: -> - @page.release() if @page? - @page = new Poltergeist.WebPage(@width, @height) + if @page? + @page.release() + phantom.clearCookies() + @page = new Poltergeist.WebPage + @page.setViewportSize(width: @width, height: @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) + this.sendResponse(status: status, click: @last_click) @state = 'default' + else if @state == 'awaiting_frame_load' + this.sendResponse(true) + @state = 'default' @page.onInitialized = => @page_id += 1 + @page.onPageCreated = (sub_page) => + if @state == 'awaiting_sub_page' + name = @page_name + @state = 'default' + @page_name = null + + # At this point subpage isn't fully initialized, so we can't check + # its name. Instead, we just schedule another attempt to push the + # window. + setTimeout((=> this.push_window(name)), 0) + sendResponse: (response) -> errors = @page.errors() if errors.length > 0 @page.clearErrors() - throw new Poltergeist.JavascriptError(errors) + @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, headers) -> - @state = 'loading' - @page.open(url, operation: "get", headers: headers) + visit: (url) -> + @state = 'loading' + prev_url = @page.currentUrl() + @page.open(url) + + if /#/.test(url) && prev_url.split('#')[0] == url.split('#')[0] + # hashchange occurred, so there will be no onLoadFinished + @state = 'default' + this.sendResponse 'success' + current_url: -> this.sendResponse @page.currentUrl() status_code: -> this.sendResponse @page.statusCode() @@ -101,31 +127,61 @@ execute: (script) -> @page.execute("function() { #{script} }") this.sendResponse(true) - push_frame: (id) -> - @page.pushFrame(id) - this.sendResponse(true) + push_frame: (name) -> + if @page.pushFrame(name) + if @page.currentUrl() == 'about:blank' + @state = 'awaiting_frame_load' + else + this.sendResponse(true) + else + # There's currently no PhantomJS callback available for frame creation, + # so we have to poll + setTimeout((=> this.push_frame(name)), 50) pop_frame: -> - @page.popFrame() + this.sendResponse(@page.popFrame()) + + push_window: (name) -> + sub_page = @page.getPage(name) + + if sub_page + if sub_page.currentUrl() == 'about:blank' + sub_page.onLoadFinished = => + sub_page.onLoadFinished = null + this.push_window(name) + else + @page_stack.push(@page) + @page = sub_page + @page_id += 1 + this.sendResponse(true) + else + @page_name = name + @state = 'awaiting_sub_page' + + pop_window: -> + prev_page = @page_stack.pop() + @page = prev_page if prev_page this.sendResponse(true) click: (page_id, id) -> # Get the node before changing state, in case there is an exception node = this.node(page_id, id) # If the click event triggers onNavigationRequested, we will transition to the 'loading' # state and wait for onLoadFinished before sending a response. @state = 'clicked' - node.click() + @last_click = node.click() - if @state != 'loading' - @state = 'default' - this.sendResponse(true) + setTimeout => + if @state != 'loading' + @state = 'default' + this.sendResponse(@last_click) + , 5 drag: (page_id, id, other_id) -> this.node(page_id, id).dragTo this.node(page_id, other_id) this.sendResponse(true) @@ -160,9 +216,31 @@ @page.setViewportSize(width: width, height: height) this.sendResponse(true) network_traffic: -> this.sendResponse(@page.networkTraffic()) + + set_headers: (headers) -> + # Workaround for https://code.google.com/p/phantomjs/issues/detail?id=745 + @page.setUserAgent(headers['User-Agent']) if headers['User-Agent'] + @page.setCustomHeaders(headers) + this.sendResponse(true) + + response_headers: -> + this.sendResponse(@page.responseHeaders()) + + cookies: -> + this.sendResponse(@page.cookies()) + + # We're using phantom.addCookie so that cookies can be set + # before the first page load has taken place. + set_cookie: (cookie) -> + phantom.addCookie(cookie) + this.sendResponse(true) + + remove_cookie: (name) -> + @page.deleteCookie(name) + this.sendResponse(true) exit: -> phantom.exit() noop: ->