diff --git a/CHANGELOG.md b/CHANGELOG.md index 2068525..36a939c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ `current_title` deprecated in Ferrum 0.21 [rubycdp/ferrum#687] - `:js_errors` is handled by Cuprite instead of being passed to Ferrum, which deprecates it. Behavior is the same [rubycdp/ferrum#688] +- `:pending_connection_errors` is handled by Cuprite instead of being passed to Ferrum, which deprecates it. `visit` + raises `Capybara::Cuprite::PendingConnectionsError`, a subclass of Ferrum's, and rescuing Ferrum's warns + [rubycdp/ferrum#689] ### Fixed diff --git a/docs/2-customization.md b/docs/2-customization.md index a5cf418..eef5e70 100644 --- a/docs/2-customization.md +++ b/docs/2-customization.md @@ -21,6 +21,8 @@ Cuprite-specific options are: * options `Hash` * `:js_errors` (Boolean) - Re-raise JavaScript errors from the page as `Ferrum::JavaScriptError` in Ruby, `false` by default. See [JavaScript errors](/docs/cuprite/javascript#javascript-errors). + * `:pending_connection_errors` (Boolean) - Raise `Capybara::Cuprite::PendingConnectionsError` from + `visit`, naming the requests still pending, when the page doesn't load in time, `true` by default. * `:screen_size` (Array) - Size used by `maximize_window`, `[1366, 768]` by default. * `:raise_on_unhandled_modal` (Boolean) - What to do when a JavaScript dialog is opened but not handled by `accept_*`/`dismiss_*`. When `false` (default) a warning is printed, when `true` @@ -41,7 +43,6 @@ Cuprite-specific options are: Cuprite changes a few Ferrum defaults: * `:save_path` - defaults to `Capybara.save_path` if it's set. -* `:pending_connection_errors` - `true` by default. * `:browser_options` - `"remote-allow-origins" => "*"` is always added, so that [debug](/docs/cuprite/debugging) can open DevTools, and so is `"disable-web-security" => nil`, so that tests can reach into cross-origin frames. diff --git a/lib/capybara/cuprite/browser.rb b/lib/capybara/cuprite/browser.rb index 8161160..6d8db60 100644 --- a/lib/capybara/cuprite/browser.rb +++ b/lib/capybara/cuprite/browser.rb @@ -10,9 +10,10 @@ class Browser < Ferrum::Browser def initialize(options = nil) device = options&.dig(:emulate) options = Devices.fetch(device).except(:user_agent).merge(options) if device - super(options&.except(:js_errors)) + super(options&.except(:js_errors, :pending_connection_errors)) @options.raise_on_js_errors = options&.dig(:js_errors) + @options.raise_on_pending_connections = options.nil? || options.fetch(:pending_connection_errors, true) @options.raise_on_unhandled_modal = options&.dig(:raise_on_unhandled_modal) @options.url_blacklist = prepare_wildcards(options&.dig(:url_blacklist)) @options.url_whitelist = prepare_wildcards(options&.dig(:url_whitelist)) diff --git a/lib/capybara/cuprite/driver.rb b/lib/capybara/cuprite/driver.rb index 4804a1f..a927b48 100644 --- a/lib/capybara/cuprite/driver.rb +++ b/lib/capybara/cuprite/driver.rb @@ -47,8 +47,6 @@ def initialize(app, options = {}) @screen_size ||= DEFAULT_MAXIMIZE_SCREEN_SIZE @options[:save_path] ||= File.expand_path(Capybara.save_path) if Capybara.save_path - @options[:pending_connection_errors] = true unless @options.key?(:pending_connection_errors) - # It's set for debug() to make devtools tab open correctly. @options[:browser_options] ||= {} unless @options[:browser_options][:"remote-allow-origins"] diff --git a/lib/capybara/cuprite/errors.rb b/lib/capybara/cuprite/errors.rb index 61c0843..37eae8d 100644 --- a/lib/capybara/cuprite/errors.rb +++ b/lib/capybara/cuprite/errors.rb @@ -52,6 +52,37 @@ def initialize(message) end end + FERRUM_PENDING_CONNECTIONS_ERROR = Ferrum.const_defined?(:PendingConnectionsError, false) + + class PendingConnectionsError < (FERRUM_PENDING_CONNECTIONS_ERROR ? Ferrum::PendingConnectionsError : Ferrum::StatusError) + attr_reader :url, :pendings + + def initialize(url, pendings = []) + super(url) + @url = url + @pendings = pendings + end + + def message + message = "Request to #{@url} reached server, but there are still pending connections" + @pendings.empty? ? message : "#{message}: #{@pendings.join(', ')}" + end + end + + module DeprecatedPendingConnectionsError + def ===(other) + matched = super + if matched && equal?(Ferrum::PendingConnectionsError) && other.is_a?(Cuprite::PendingConnectionsError) + warn "Ferrum::PendingConnectionsError is deprecated, use Capybara::Cuprite::PendingConnectionsError", + uplevel: 1 + end + matched + end + end + + Ferrum::PendingConnectionsError.singleton_class.prepend(DeprecatedPendingConnectionsError) if + FERRUM_PENDING_CONNECTIONS_ERROR + class ObsoleteNode < ClientError attr_reader :node diff --git a/lib/capybara/cuprite/options.rb b/lib/capybara/cuprite/options.rb index da67114..ba1b75f 100644 --- a/lib/capybara/cuprite/options.rb +++ b/lib/capybara/cuprite/options.rb @@ -4,7 +4,8 @@ module Ferrum class Browser class Options attr_writer :window_size - attr_accessor :url_blacklist, :url_whitelist, :raise_on_unhandled_modal, :raise_on_js_errors + attr_accessor :url_blacklist, :url_whitelist, :raise_on_unhandled_modal, :raise_on_js_errors, + :raise_on_pending_connections def mobile @options.fetch(:mobile, nil) diff --git a/lib/capybara/cuprite/page.rb b/lib/capybara/cuprite/page.rb index 22c2149..b79103e 100644 --- a/lib/capybara/cuprite/page.rb +++ b/lib/capybara/cuprite/page.rb @@ -11,6 +11,16 @@ class Page < Ferrum::Page include Frames include Modals + def go_to(url = nil) + frame_id = super + return frame_id if frame_id || !@options.raise_on_pending_connections + + pendings = network.traffic.select(&:pending?).map(&:url).compact + raise PendingConnectionsError.new(combine_url!(url), pendings) + end + alias goto go_to + alias go go_to + def set_viewport(width: 0, height: 0, scale_factor: @options.scale_factor, mobile: @options.mobile) super end diff --git a/spec/features/driver_spec.rb b/spec/features/driver_spec.rb index f403e71..142809d 100644 --- a/spec/features/driver_spec.rb +++ b/spec/features/driver_spec.rb @@ -773,6 +773,26 @@ def create_screenshot(file, *args) @session.driver.browser.timeout = old_timeout end + it "warns when Ferrum::PendingConnectionsError is rescued" do + @driver.browser.page + old_timeout = @driver.browser.timeout + @driver.browser.timeout = 0.1 + expect do + @driver.visit(session_url("/cuprite/really_slow")) + rescue Ferrum::PendingConnectionsError + nil + end.to output(/#{__FILE__}:\d+: warning: Ferrum::PendingConnectionsError is deprecated/).to_stderr + ensure + @driver.browser.timeout = old_timeout + end + + it "does not report open resources when pending_connection_errors is disabled" do + driver = Capybara::Cuprite::Driver.new(@session.app, pending_connection_errors: false, timeout: 0.5) + expect { driver.visit(session_url("/cuprite/really_slow")) }.not_to raise_error + ensure + driver&.quit + end + it "does not report open resources where there are none" do old_timeout = @session.driver.browser.timeout begin