Method: Capybara::Node::Base#synchronize

Defined in:
lib/capybara/node/base.rb

#synchronize(seconds = nil, errors: nil) ⇒ Object

This method is Capybara's primary defence against asynchronicity problems. It works by attempting to run a given block of code until it succeeds. The exact behaviour of this method depends on a number of factors. Basically there are certain exceptions which, when raised from the block, instead of bubbling up, are caught, and the block is re-run.

Certain drivers, such as RackTest, have no support for asynchronous processes, these drivers run the block, and any error raised bubbles up immediately. This allows faster turn around in the case where an expectation fails.

Only exceptions that are ElementNotFound or any subclass thereof cause the block to be rerun. Drivers may specify additional exceptions which also cause reruns. This usually occurs when a node is manipulated which no longer exists on the page. For example, the Selenium driver specifies Selenium::WebDriver::Error::ObsoleteElementError.

As long as any of these exceptions are thrown, the block is re-run, until a certain amount of time passes. The amount of time defaults to Capybara.default_max_wait_time and can be overridden through the seconds argument. This time is compared with the system time to see how much time has passed. On rubies/platforms which don't support access to a monotonic process clock if the return value of Time.now is stubbed out, Capybara will raise Capybara::FrozenInTime.

Parameters:

  • seconds (Integer) (defaults to: nil)

    (current sessions default_max_wait_time) Maximum number of seconds to retry this block

  • errors (Array<Exception>) (defaults to: nil)

    (driver.invalid_element_errors + [Capybara::ElementNotFound]) exception types that cause the block to be rerun

Returns:

  • (Object)

    The result of the given block

Raises:



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/capybara/node/base.rb', line 76

def synchronize(seconds = nil, errors: nil)
  return yield if session.synchronized

  seconds = session_options.default_max_wait_time if [nil, true].include? seconds
  interval = session_options.default_retry_interval
  session.synchronized = true
  timer = Capybara::Helpers.timer(expire_in: seconds)
  begin
    yield
  rescue StandardError => e
    session.raise_server_error!
    raise e unless catch_error?(e, errors)

    if driver.wait?
      raise e if timer.expired?

      sleep interval
      reload if session_options.automatic_reload
    else
      old_base = @base
      reload if session_options.automatic_reload
      raise e if old_base == @base
    end
    retry
  ensure
    session.synchronized = false
  end
end