diff --git a/lib/capybara/helpers.rb b/lib/capybara/helpers.rb index 326fa95a..36f4414b 100644 --- a/lib/capybara/helpers.rb +++ b/lib/capybara/helpers.rb @@ -74,5 +74,30 @@ module Capybara else def monotonic_time; Time.now.to_f; end end + + def timer(expire_in:) + Timer.new(expire_in) + end + + class Timer + def initialize(expire_in) + @start = current + @expire_in = expire_in + end + + def expired? + current - @start >= @expire_in + end + + def stalled? + @start == current + end + + private + + def current + Capybara::Helpers.monotonic_time + end + end end end diff --git a/lib/capybara/node/base.rb b/lib/capybara/node/base.rb index 0ea4b2c1..9cf5a3bf 100644 --- a/lib/capybara/node/base.rb +++ b/lib/capybara/node/base.rb @@ -78,15 +78,15 @@ module Capybara yield else session.synchronized = true - start_time = Capybara::Helpers.monotonic_time + timer = Capybara::Helpers.timer(expire_in: seconds) begin yield rescue StandardError => e session.raise_server_error! raise e unless driver.wait? && catch_error?(e, errors) - raise e if (Capybara::Helpers.monotonic_time - start_time) >= seconds + raise e if timer.expired? sleep(0.05) - raise Capybara::FrozenInTime, "Time appears to be frozen. Capybara does not work with libraries which freeze time, consider using time travelling instead" if Capybara::Helpers.monotonic_time == start_time + raise Capybara::FrozenInTime, "Time appears to be frozen. Capybara does not work with libraries which freeze time, consider using time travelling instead" if timer.stalled? reload if session_options.automatic_reload retry ensure diff --git a/lib/capybara/node/element.rb b/lib/capybara/node/element.rb index 59d7fcff..39844b76 100644 --- a/lib/capybara/node/element.rb +++ b/lib/capybara/node/element.rb @@ -398,7 +398,6 @@ module Capybara JS end - def reload if @allow_reload begin diff --git a/lib/capybara/rspec/matchers.rb b/lib/capybara/rspec/matchers.rb index e96d3b74..de099289 100644 --- a/lib/capybara/rspec/matchers.rb +++ b/lib/capybara/rspec/matchers.rb @@ -237,9 +237,9 @@ module Capybara def matches?(window) @window = window @wait_time = Capybara::Queries::BaseQuery.wait(@options, window.session.config.default_max_wait_time) - start_time = Capybara::Helpers.monotonic_time + timer = Capybara::Helpers.timer(expire_in: @wait_time) while window.exists? - return false if (Capybara::Helpers.monotonic_time - start_time) > @wait_time + return false if timer.expired? sleep 0.05 end true diff --git a/lib/capybara/selenium/driver.rb b/lib/capybara/selenium/driver.rb index 69c5e378..26531095 100644 --- a/lib/capybara/selenium/driver.rb +++ b/lib/capybara/selenium/driver.rb @@ -129,7 +129,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base end navigated = false - start_time = Capybara::Helpers.monotonic_time + timer = Capybara::Helpers.timer(expire_in: 10) begin unless navigated # Only trigger a navigation if we haven't done it already, otherwise it @@ -152,7 +152,7 @@ class Capybara::Selenium::Driver < Capybara::Driver::Base # Ensure the page is empty and trigger an UnhandledAlertError for any modals that appear during unload until find_xpath("/html/body/*").empty? - raise Capybara::ExpectationNotMet, 'Timed out waiting for Selenium session reset' if (Capybara::Helpers.monotonic_time - start_time) >= 10 + raise Capybara::ExpectationNotMet, 'Timed out waiting for Selenium session reset' if timer.expired? sleep 0.05 end rescue Selenium::WebDriver::Error::UnhandledAlertError, Selenium::WebDriver::Error::UnexpectedAlertOpenError diff --git a/lib/capybara/server.rb b/lib/capybara/server.rb index 02f5bc08..6d4ffe48 100644 --- a/lib/capybara/server.rb +++ b/lib/capybara/server.rb @@ -54,11 +54,9 @@ module Capybara end def wait_for_pending_requests - start_time = Capybara::Helpers.monotonic_time + timer = Capybara::Helpers.timer(expire_in: 60) while pending_requests? - if (Capybara::Helpers.monotonic_time - start_time) > 60 - raise "Requests did not finish in 60 seconds" - end + raise "Requests did not finish in 60 seconds" if timer.expired? sleep 0.01 end end @@ -71,11 +69,9 @@ module Capybara Capybara.server.call(middleware, port, host) end - start_time = Capybara::Helpers.monotonic_time + timer = Capybara::Helpers.timer(expire_in: 60) until responsive? - if (Capybara::Helpers.monotonic_time - start_time) > 60 - raise "Rack application timed out during boot" - end + raise "Rack application timed out during boot" if timer.expired? @server_thread.join(0.1) end end