# frozen_string_literal: true
module Capybara
module Node
module Finders
##
#
# Find an {Capybara::Node::Element} based on the given arguments. +find+ will raise an error if the element
# is not found.
#
# @!macro waiting_behavior
# If the driver is capable of executing JavaScript, +$0+ will wait for a set amount of time
# and continuously retry finding the element until either the element is found or the time
# expires. The length of time +find+ will wait is controlled through {Capybara.default_max_wait_time}
# and defaults to 2 seconds.
# @option options [false, Numeric] wait (Capybara.default_max_wait_time) Maximum time to wait for matching element to appear.
#
# +find+ takes the same options as +all+.
#
# page.find('#foo').find('.bar')
# page.find(:xpath, '//div[contains(., "bar")]')
# page.find('li', :text => 'Quox').click_link('Delete')
#
# @param (see Capybara::Node::Finders#all)
#
# @option options [Boolean] match The matching strategy to use.
#
# @return [Capybara::Node::Element] The found element
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
#
def find(*args)
query = Capybara::Queries::SelectorQuery.new(*args)
synchronize(query.wait) do
if query.match == :smart or query.match == :prefer_exact
result = query.resolve_for(self, true)
result = query.resolve_for(self, false) if result.size == 0 && !query.exact?
else
result = query.resolve_for(self)
end
if query.match == :one or query.match == :smart and result.size > 1
raise Capybara::Ambiguous.new("Ambiguous match, found #{result.size} elements matching #{query.description}")
end
if result.size == 0
raise Capybara::ElementNotFound.new("Unable to find #{query.description}")
end
result.first
end.tap(&:allow_reload!)
end
##
#
# Find a form field on the page. The field can be found by its name, id or label text.
#
# @overload find_field([locator], options={})
# @param [String] locator name, id, placeholder or text of associated label element
#
# @macro waiting_behavior
#
#
# @option options [Boolean] checked Match checked field?
# @option options [Boolean] unchecked Match unchecked field?
# @option options [Boolean, Symbol] disabled (false) Match disabled field?
# * true - only finds a disabled field
# * false - only finds an enabled field
# * :all - finds either an enabled or disabled field
# @option options [Boolean] readonly Match readonly field?
# @option options [String] with Value of field to match on
# @option options [String] type Type of field to match on
# @option options [Boolean] multiple Match fields that can have multiple values?
# @return [Capybara::Node::Element] The found element
#
def find_field(locator=nil, options={})
locator, options = nil, locator if locator.is_a? Hash
find(:field, locator, options)
end
alias_method :field_labeled, :find_field
##
#
# Find a link on the page. The link can be found by its id or text.
#
# @overload find_link([locator], options={})
# @param [String] locator id, title, text, or alt of enclosed img element
#
# @macro waiting_behavior
#
# @option options [String,Regexp] href Value to match against the links href
# @return [Capybara::Node::Element] The found element
#
def find_link(locator=nil, options={})
locator, options = nil, locator if locator.is_a? Hash
find(:link, locator, options)
end
##
#
# Find a button on the page.
# This can be any \ element of type submit, reset, image, button or it can be a
# \