class Capybara::Node::Base

A {Capybara::Node::Base} represents either an element on a page through the subclass {Capybara::Node::Element} or a document through {Capybara::Node::Document}.

Both types of Node share the same methods, used for interacting with the elements on the page. These methods are divided into three categories, finders, actions and matchers. These are found in the modules {Capybara::Node::Finders}, {Capybara::Node::Actions} and {Capybara::Node::Matchers} respectively.

A {Capybara::Session} exposes all methods from {Capybara::Node::Document} directly:

session = Capybara::Session.new(:rack_test, my_app)
session.visit('/')
session.fill_in('Foo', with: 'Bar')    # from Capybara::Node::Actions
bar = session.find('#bar')                # from Capybara::Node::Finders
bar.select('Baz', from: 'Quox')        # from Capybara::Node::Actions
session.has_css?('#foobar')               # from Capybara::Node::Matchers

Attributes

base[R]
query_scope[R]
session[R]

Public Class Methods

new(session, base) click to toggle source
# File lib/capybara/node/base.rb, line 32
def initialize(session, base)
  @session = session
  @base = base
end

Public Instance Methods

find_css(css, **options) click to toggle source

@api private

# File lib/capybara/node/base.rb, line 105
def find_css(css, **options)
  if base.method(:find_css).arity == 1
    base.find_css(css)
  else
    base.find_css(css, **options)
  end
end
find_xpath(xpath, **options) click to toggle source

@api private

# File lib/capybara/node/base.rb, line 114
def find_xpath(xpath, **options)
  if base.method(:find_xpath).arity == 1
    base.find_xpath(xpath)
  else
    base.find_xpath(xpath, **options)
  end
end
reload() click to toggle source

overridden in subclasses, e.g. Capybara::Node::Element

# File lib/capybara/node/base.rb, line 38
def reload
  self
end
session_options() click to toggle source

@api private

# File lib/capybara/node/base.rb, line 123
def session_options
  session.config
end
synchronize(seconds = nil, errors: nil) { || ... } click to toggle source

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 {Capybara::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`.

@param [Integer] seconds (current sessions default_max_wait_time) Maximum number of seconds to retry this block @param [Array<Exception>] errors (driver.invalid_element_errors +

[Capybara::ElementNotFound]) exception types that cause the block to be rerun

@return [Object] The result of the given block @raise [Capybara::FrozenInTime] If the return value of `Time.now` appears stuck

# 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
  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(0.01)
      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
to_capybara_node() click to toggle source
# File lib/capybara/node/base.rb, line 127
def to_capybara_node
  self
end

Protected Instance Methods

catch_error?(error, errors = nil) click to toggle source
# File lib/capybara/node/base.rb, line 133
def catch_error?(error, errors = nil)
  errors ||= (driver.invalid_element_errors + [Capybara::ElementNotFound])
  errors.any? { |type| error.is_a?(type) }
end
driver() click to toggle source
# File lib/capybara/node/base.rb, line 138
def driver
  session.driver
end