From 2e869bb9b71394c10429b45a5338fe7342f1eacb Mon Sep 17 00:00:00 2001 From: Oliver Peate Date: Fri, 17 Mar 2017 14:54:36 +0000 Subject: [PATCH] Allow JavaScript errors to be raised as exceptions (#988) When configured, all driver commands (except reading console messages) will check for JavaScript errors. The ConsoleMessages command is excluded from the check to prevent recursion, and maintain the ease of debugging JavaScript errors interactively. --- README.md | 3 ++ lib/capybara/webkit/browser.rb | 26 +++++++++++++++- lib/capybara/webkit/configuration.rb | 5 ++- lib/capybara/webkit/driver.rb | 4 +++ lib/capybara/webkit/errors.rb | 9 ++++++ spec/browser_spec.rb | 16 ++++++++++ spec/driver_spec.rb | 46 ++++++++++++++++++++++++++++ spec/support/app_runner.rb | 1 + 8 files changed, 108 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d864474..c87ba9e 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,9 @@ Capybara::Webkit.configure do |config| user: "proxy", pass: "secret" ) + + # Raise JavaScript errors as exceptions + config.raise_javascript_errors = true end ``` diff --git a/lib/capybara/webkit/browser.rb b/lib/capybara/webkit/browser.rb index 9aab4b5..e2c966e 100644 --- a/lib/capybara/webkit/browser.rb +++ b/lib/capybara/webkit/browser.rb @@ -5,6 +5,7 @@ module Capybara::Webkit class Browser def initialize(connection) @connection = connection + apply_defaults end def authenticate(username, password) @@ -36,6 +37,7 @@ module Capybara::Webkit end def reset! + apply_defaults command("Reset") end @@ -99,6 +101,14 @@ module Capybara::Webkit command("SetSkipImageLoading", skip_image_loading) end + def set_raise_javascript_errors(is_enabled) + @raise_javascript_errors = is_enabled + end + + def raise_javascript_errors? + @raise_javascript_errors + end + def window_focus(selector) command("WindowFocus", selector) end @@ -209,7 +219,9 @@ module Capybara::Webkit @connection.print arg.to_s end check - read_response + response = read_response + check_javascript_errors(name) + response rescue SystemCallError => exception @connection.restart raise(Capybara::Webkit::CrashError, <<-MESSAGE.strip) @@ -295,6 +307,10 @@ https://github.com/thoughtbot/capybara-webkit/wiki/Reporting-Crashes private + def apply_defaults + @raise_javascript_errors = false + end + def check result = @connection.gets result.strip! if result @@ -308,6 +324,14 @@ https://github.com/thoughtbot/capybara-webkit/wiki/Reporting-Crashes result end + def check_javascript_errors(command_name) + return if command_name == "ConsoleMessages" + + if raise_javascript_errors? && error_messages.any? + raise JavaScriptError, error_messages + end + end + def read_response response_length = @connection.gets.to_i if response_length > 0 diff --git a/lib/capybara/webkit/configuration.rb b/lib/capybara/webkit/configuration.rb index 2adeeba..41254b5 100644 --- a/lib/capybara/webkit/configuration.rb +++ b/lib/capybara/webkit/configuration.rb @@ -30,6 +30,7 @@ module Capybara attr_accessor :stderr attr_accessor :timeout attr_writer :skip_image_loading + attr_accessor :raise_javascript_errors def initialize @allowed_urls = [] @@ -41,6 +42,7 @@ module Capybara @skip_image_loading = false @stderr = $stderr @timeout = -1 + @raise_javascript_errors = false end def allow_url(url) @@ -93,7 +95,8 @@ module Capybara proxy: proxy, skip_image_loading: skip_image_loading?, stderr: stderr, - timeout: timeout + timeout: timeout, + raise_javascript_errors: raise_javascript_errors, } end end diff --git a/lib/capybara/webkit/driver.rb b/lib/capybara/webkit/driver.rb index b16d4e6..ce9dfa6 100644 --- a/lib/capybara/webkit/driver.rb +++ b/lib/capybara/webkit/driver.rb @@ -398,6 +398,10 @@ module Capybara::Webkit @browser.timeout = @options[:timeout] end + if @options.has_key? :raise_javascript_errors + @browser.set_raise_javascript_errors(@options[:raise_javascript_errors]) + end + Array(@options[:allowed_urls]).each { |url| @browser.allow_url(url) } Array(@options[:blocked_urls]).each { |url| @browser.block_url(url) } end diff --git a/lib/capybara/webkit/errors.rb b/lib/capybara/webkit/errors.rb index 06681fa..3b0c30e 100644 --- a/lib/capybara/webkit/errors.rb +++ b/lib/capybara/webkit/errors.rb @@ -44,4 +44,13 @@ module Capybara::Webkit Capybara::Webkit.const_get @class_name end end + + class JavaScriptError < StandardError + def initialize(errors) + @javascript_errors = errors + super(errors.join(",")) + end + + attr_reader :javascript_errors + end end diff --git a/spec/browser_spec.rb b/spec/browser_spec.rb index a74096b..2d075bf 100644 --- a/spec/browser_spec.rb +++ b/spec/browser_spec.rb @@ -43,4 +43,20 @@ describe Capybara::Webkit::Browser do end end end + + describe "#reset!" do + it "resets to the default state" do + connection = double("connection", puts: nil, print: nil) + allow(connection).to receive(:gets).and_return("ok\n", "{}\n") + + browser = Capybara::Webkit::Browser.new(connection) + browser.set_raise_javascript_errors(true) + + expect(browser.raise_javascript_errors?).to be true + + browser.reset! + + expect(browser.raise_javascript_errors?).to be false + end + end end diff --git a/spec/driver_spec.rb b/spec/driver_spec.rb index 00917c4..f7df360 100644 --- a/spec/driver_spec.rb +++ b/spec/driver_spec.rb @@ -3440,4 +3440,50 @@ CACHE MANIFEST def driver_url(driver, path) URI.parse(driver.current_url).merge(path).to_s end + + context "page with JavaScript errors" do + let(:driver) do + driver_for_app do + get "/" do + <<-HTML + + + + + + + HTML + end + end + end + + it "raises errors as an exception, when configured" do + configure do |config| + config.raise_javascript_errors = true + end + + expected_error = Capybara::Webkit::JavaScriptError + expected_message = "ReferenceError: Can't find variable: undefinedFunc" + + expect { visit("/") }.to raise_error(expected_error) do |error| + expect(error.javascript_errors.first[:message]).to eq expected_message + end + expect { driver.find_css("h1") }.to raise_error(expected_error) + end + + it "does not raise an exception when fetching the error messages" do + configure do |config| + config.raise_javascript_errors = true + end + + expect { driver.error_messages }.to_not raise_error + end + + it "does not raise errors as an exception by default" do + expect { visit("/") }.to_not raise_error + expect(driver.error_messages).to_not be_empty + end + end end diff --git a/spec/support/app_runner.rb b/spec/support/app_runner.rb index e79a767..28a1c41 100644 --- a/spec/support/app_runner.rb +++ b/spec/support/app_runner.rb @@ -21,6 +21,7 @@ module AppRunner end self.browser = $webkit_browser + self.browser.reset! self.configuration = Capybara::Webkit::Configuration.new end