diff --git a/lib/capybara/poltergeist/browser.rb b/lib/capybara/poltergeist/browser.rb index fd3a6da..ec76591 100644 --- a/lib/capybara/poltergeist/browser.rb +++ b/lib/capybara/poltergeist/browser.rb @@ -1,8 +1,14 @@ +require "capybara/poltergeist/errors" require 'json' require 'time' module Capybara::Poltergeist class Browser + ERROR_MAPPINGS = { + "Poltergeist.JavascriptError" => JavascriptError, + "Poltergeist.FrameNotFound" => FrameNotFound + } + attr_reader :server, :client, :logger def initialize(server, client, logger = nil) @@ -193,14 +199,11 @@ module Capybara::Poltergeist log json.inspect if json['error'] - if json['error']['name'] == 'Poltergeist.JavascriptError' - raise JavascriptError.new(json['error']) - else - raise BrowserError.new(json['error']) - end + klass = ERROR_MAPPINGS[json['error']['name']] || BrowserError + raise klass.new(json['error']) + else + json['response'] end - json['response'] - rescue DeadClient restart raise diff --git a/lib/capybara/poltergeist/client/browser.coffee b/lib/capybara/poltergeist/client/browser.coffee index d855c06..75cda21 100644 --- a/lib/capybara/poltergeist/client/browser.coffee +++ b/lib/capybara/poltergeist/client/browser.coffee @@ -145,16 +145,17 @@ class Poltergeist.Browser @page.execute("function() { #{script} }") this.sendResponse(true) - push_frame: (name) -> + push_frame: (name, timeout = new Date().getTime() + 2000) -> if @page.pushFrame(name) if @page.currentUrl() == 'about:blank' this.setState '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) + if new Date().getTime() < timeout + setTimeout((=> this.push_frame(name, timeout)), 50) + else + @owner.sendError(new Poltergeist.FrameNotFound(name)) pop_frame: -> this.sendResponse(@page.popFrame()) diff --git a/lib/capybara/poltergeist/client/compiled/browser.js b/lib/capybara/poltergeist/client/compiled/browser.js index cc5d1f2..8a24a08 100644 --- a/lib/capybara/poltergeist/client/compiled/browser.js +++ b/lib/capybara/poltergeist/client/compiled/browser.js @@ -182,8 +182,11 @@ Poltergeist.Browser = (function() { return this.sendResponse(true); }; - Browser.prototype.push_frame = function(name) { + Browser.prototype.push_frame = function(name, timeout) { var _this = this; + if (timeout == null) { + timeout = new Date().getTime() + 2000; + } if (this.page.pushFrame(name)) { if (this.page.currentUrl() === 'about:blank') { return this.setState('awaiting_frame_load'); @@ -191,9 +194,13 @@ Poltergeist.Browser = (function() { return this.sendResponse(true); } } else { - return setTimeout((function() { - return _this.push_frame(name); - }), 50); + if (new Date().getTime() < timeout) { + return setTimeout((function() { + return _this.push_frame(name, timeout); + }), 50); + } else { + return this.owner.sendError(new Poltergeist.FrameNotFound(name)); + } } }; diff --git a/lib/capybara/poltergeist/client/compiled/main.js b/lib/capybara/poltergeist/client/compiled/main.js index 77cb5e5..e1ecdb2 100644 --- a/lib/capybara/poltergeist/client/compiled/main.js +++ b/lib/capybara/poltergeist/client/compiled/main.js @@ -86,6 +86,24 @@ Poltergeist.ObsoleteNode = (function(_super) { })(Poltergeist.Error); +Poltergeist.FrameNotFound = (function(_super) { + + __extends(FrameNotFound, _super); + + function FrameNotFound(frameName) { + this.frameName = frameName; + } + + FrameNotFound.prototype.name = "Poltergeist.FrameNotFound"; + + FrameNotFound.prototype.args = function() { + return [this.frameName]; + }; + + return FrameNotFound; + +})(Poltergeist.Error); + Poltergeist.ClickFailed = (function(_super) { __extends(ClickFailed, _super); diff --git a/lib/capybara/poltergeist/client/main.coffee b/lib/capybara/poltergeist/client/main.coffee index cb732cf..116767e 100644 --- a/lib/capybara/poltergeist/client/main.coffee +++ b/lib/capybara/poltergeist/client/main.coffee @@ -50,6 +50,11 @@ class Poltergeist.ObsoleteNode extends Poltergeist.Error args: -> [] toString: -> this.name +class Poltergeist.FrameNotFound extends Poltergeist.Error + constructor: (@frameName) -> + name: "Poltergeist.FrameNotFound" + args: -> [@frameName] + class Poltergeist.ClickFailed extends Poltergeist.Error constructor: (@selector, @position) -> name: "Poltergeist.ClickFailed" diff --git a/lib/capybara/poltergeist/driver.rb b/lib/capybara/poltergeist/driver.rb index 84408e8..88b9628 100644 --- a/lib/capybara/poltergeist/driver.rb +++ b/lib/capybara/poltergeist/driver.rb @@ -132,7 +132,6 @@ module Capybara::Poltergeist end def within_frame(name, &block) - raise NotImplementedError browser.within_frame(name, &block) end diff --git a/lib/capybara/poltergeist/errors.rb b/lib/capybara/poltergeist/errors.rb index 731158c..85ea02b 100644 --- a/lib/capybara/poltergeist/errors.rb +++ b/lib/capybara/poltergeist/errors.rb @@ -54,6 +54,16 @@ module Capybara end end + class FrameNotFound < ClientError + def name + response['args'].first + end + + def message + "The frame '#{name}' was not found." + end + end + class NodeError < ClientError attr_reader :node diff --git a/spec/integration/session_spec.rb b/spec/integration/session_spec.rb index e2d568d..ef3097e 100644 --- a/spec/integration/session_spec.rb +++ b/spec/integration/session_spec.rb @@ -410,6 +410,14 @@ describe Capybara::Session do log.text.should == "one" end end + + it "doesn't wait forever for the frame to load" do + @session.visit '/' + + expect { + @session.within_frame('omg') { } + }.to raise_error(Capybara::Poltergeist::FrameNotFound) + end end # see https://github.com/jonleighton/poltergeist/issues/115