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: ->