2016-03-07 19:52:19 -05:00
|
|
|
# frozen_string_literal: true
|
2010-07-09 20:20:32 -04:00
|
|
|
module Capybara
|
2010-11-21 08:37:36 -05:00
|
|
|
module Node
|
2010-07-09 20:20:32 -04:00
|
|
|
module Finders
|
2010-07-17 13:05:00 -04:00
|
|
|
|
|
|
|
##
|
|
|
|
#
|
2015-02-25 23:16:38 -05:00
|
|
|
# Find an {Capybara::Node::Element} based on the given arguments. +find+ will raise an error if the element
|
2012-11-20 00:53:13 -05:00
|
|
|
# is not found.
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
2015-08-25 16:35:43 -04:00
|
|
|
# @!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.
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
2010-07-19 14:18:16 -04:00
|
|
|
# +find+ takes the same options as +all+.
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
2010-07-19 14:18:16 -04:00
|
|
|
# page.find('#foo').find('.bar')
|
2011-06-27 19:01:46 -04:00
|
|
|
# page.find(:xpath, '//div[contains(., "bar")]')
|
2010-07-19 14:18:16 -04:00
|
|
|
# page.find('li', :text => 'Quox').click_link('Delete')
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
|
|
|
# @param (see Capybara::Node::Finders#all)
|
2015-08-25 16:35:43 -04:00
|
|
|
#
|
2013-02-25 14:34:58 -05:00
|
|
|
# @option options [Boolean] match The matching strategy to use.
|
2013-02-24 11:47:53 -05:00
|
|
|
#
|
2015-02-25 23:16:38 -05:00
|
|
|
# @return [Capybara::Node::Element] The found element
|
2013-02-25 14:34:58 -05:00
|
|
|
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
2016-09-23 18:03:36 -04:00
|
|
|
def find(*args, &optional_filter_block)
|
|
|
|
query = Capybara::Queries::SelectorQuery.new(*args, &optional_filter_block)
|
2013-02-25 14:34:58 -05:00
|
|
|
synchronize(query.wait) do
|
2016-08-24 17:07:05 -04:00
|
|
|
if (query.match == :smart or query.match == :prefer_exact) and query.supports_exact?
|
2014-02-16 12:13:58 -05:00
|
|
|
result = query.resolve_for(self, true)
|
2016-08-05 17:44:33 -04:00
|
|
|
result = query.resolve_for(self, false) if result.empty? && !query.exact?
|
2013-02-15 14:32:05 -05:00
|
|
|
else
|
2014-02-16 12:13:58 -05:00
|
|
|
result = query.resolve_for(self)
|
2013-02-15 14:32:05 -05:00
|
|
|
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
|
2016-08-05 17:44:33 -04:00
|
|
|
if result.empty?
|
2013-02-15 14:32:05 -05:00
|
|
|
raise Capybara::ElementNotFound.new("Unable to find #{query.description}")
|
|
|
|
end
|
|
|
|
result.first
|
|
|
|
end.tap(&:allow_reload!)
|
2010-07-09 20:20:32 -04:00
|
|
|
end
|
2010-07-19 14:40:28 -04:00
|
|
|
|
2010-07-17 13:05:00 -04:00
|
|
|
##
|
|
|
|
#
|
|
|
|
# Find a form field on the page. The field can be found by its name, id or label text.
|
|
|
|
#
|
2016-04-13 16:50:37 -04:00
|
|
|
# @overload find_field([locator], options={})
|
|
|
|
# @param [String] locator name, id, placeholder or text of associated label element
|
|
|
|
#
|
|
|
|
# @macro waiting_behavior
|
|
|
|
#
|
2015-08-25 16:35:43 -04:00
|
|
|
#
|
2016-07-28 04:25:24 -04:00
|
|
|
# @option options [Boolean] checked Match checked field?
|
|
|
|
# @option options [Boolean] unchecked Match unchecked field?
|
2016-04-13 16:50:37 -04:00
|
|
|
# @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
|
2016-07-28 04:25:24 -04:00
|
|
|
# @option options [Boolean] readonly Match readonly field?
|
|
|
|
# @option options [String, Regexp] with Value of field to match on
|
|
|
|
# @option options [String] type Type of field to match on
|
2016-04-14 14:22:51 -04:00
|
|
|
# @option options [Boolean] multiple Match fields that can have multiple values?
|
2016-04-27 01:44:48 -04:00
|
|
|
# @option options [String] id Match fields that match the id attribute
|
|
|
|
# @option options [String] name Match fields that match the name attribute
|
|
|
|
# @option options [String] placeholder Match fields that match the placeholder attribute
|
2016-09-07 03:34:15 -04:00
|
|
|
# @option options [String, Array<String>] Match fields that match the class(es) passed
|
2015-02-25 23:16:38 -05:00
|
|
|
# @return [Capybara::Node::Element] The found element
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
2016-04-13 16:50:37 -04:00
|
|
|
|
2016-09-23 18:03:36 -04:00
|
|
|
def find_field(locator=nil, options={}, &optional_filter_block)
|
2016-04-13 16:50:37 -04:00
|
|
|
locator, options = nil, locator if locator.is_a? Hash
|
2016-09-23 18:03:36 -04:00
|
|
|
find(:field, locator, options, &optional_filter_block)
|
2010-07-09 20:20:32 -04:00
|
|
|
end
|
|
|
|
alias_method :field_labeled, :find_field
|
|
|
|
|
2010-07-17 13:05:00 -04:00
|
|
|
##
|
|
|
|
#
|
|
|
|
# Find a link on the page. The link can be found by its id or text.
|
|
|
|
#
|
2016-04-13 16:50:37 -04:00
|
|
|
# @overload find_link([locator], options={})
|
|
|
|
# @param [String] locator id, title, text, or alt of enclosed img element
|
|
|
|
#
|
|
|
|
# @macro waiting_behavior
|
2015-08-25 16:35:43 -04:00
|
|
|
#
|
2016-04-13 16:50:37 -04:00
|
|
|
# @option options [String,Regexp] href Value to match against the links href
|
2016-09-07 03:34:15 -04:00
|
|
|
# @option options [String] id Match links with the id provided
|
|
|
|
# @option options [String] title Match links with the title provided
|
|
|
|
# @option options [String] alt Match links with a contained img element whose alt matches
|
|
|
|
# @option options [String, Array<String>] class Match links that match the class(es) provided
|
2015-02-25 23:16:38 -05:00
|
|
|
# @return [Capybara::Node::Element] The found element
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
2016-09-23 18:03:36 -04:00
|
|
|
def find_link(locator=nil, options={}, &optional_filter_block)
|
2016-04-13 16:50:37 -04:00
|
|
|
locator, options = nil, locator if locator.is_a? Hash
|
2016-09-23 18:03:36 -04:00
|
|
|
find(:link, locator, options, &optional_filter_block)
|
2010-07-09 20:20:32 -04:00
|
|
|
end
|
|
|
|
|
2010-07-17 13:05:00 -04:00
|
|
|
##
|
|
|
|
#
|
2015-08-25 17:50:44 -04:00
|
|
|
# Find a button on the page.
|
|
|
|
# This can be any \<input> element of type submit, reset, image, button or it can be a
|
|
|
|
# \<button> element. All buttons can be found by their id, value, or title. \<button> elements can also be found
|
|
|
|
# by their text content, and image \<input> elements by their alt attribute
|
2015-08-25 16:35:43 -04:00
|
|
|
#
|
2016-04-13 16:50:37 -04:00
|
|
|
# @overload find_button([locator], options={})
|
|
|
|
# @param [String] locator id, value, title, text content, alt of image
|
|
|
|
#
|
|
|
|
# @overload find_button(options={})
|
|
|
|
#
|
|
|
|
# @macro waiting_behavior
|
|
|
|
#
|
|
|
|
# @option options [Boolean, Symbol] disabled (false) Match disabled button?
|
|
|
|
# * true - only finds a disabled button
|
|
|
|
# * false - only finds an enabled button
|
|
|
|
# * :all - finds either an enabled or disabled button
|
2016-09-07 03:34:15 -04:00
|
|
|
# @option options [String] id Match buttons with the id provided
|
|
|
|
# @option options [String] title Match buttons with the title provided
|
|
|
|
# @option options [String] value Match buttons with the value provided
|
|
|
|
# @option options [String, Array<String>] class Match links that match the class(es) provided
|
2015-02-25 23:16:38 -05:00
|
|
|
# @return [Capybara::Node::Element] The found element
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
2016-09-23 18:03:36 -04:00
|
|
|
def find_button(locator=nil, options={}, &optional_filter_block)
|
2016-04-13 16:50:37 -04:00
|
|
|
locator, options = nil, locator if locator.is_a? Hash
|
2016-09-23 18:03:36 -04:00
|
|
|
find(:button, locator, options, &optional_filter_block)
|
2010-07-09 20:20:32 -04:00
|
|
|
end
|
|
|
|
|
2010-07-17 13:05:00 -04:00
|
|
|
##
|
|
|
|
#
|
|
|
|
# Find a element on the page, given its id.
|
|
|
|
#
|
2015-08-25 16:35:43 -04:00
|
|
|
# @macro waiting_behavior
|
|
|
|
#
|
2016-04-13 16:50:37 -04:00
|
|
|
# @param [String] id id of element
|
2015-08-25 16:35:43 -04:00
|
|
|
#
|
2015-02-25 23:16:38 -05:00
|
|
|
# @return [Capybara::Node::Element] The found element
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
2016-09-23 18:03:36 -04:00
|
|
|
def find_by_id(id, options={}, &optional_filter_block)
|
|
|
|
find(:id, id, options, &optional_filter_block)
|
2010-07-09 20:20:32 -04:00
|
|
|
end
|
|
|
|
|
2010-07-17 13:05:00 -04:00
|
|
|
##
|
2016-09-23 18:03:36 -04:00
|
|
|
# @!method all([kind = Capybara.default_selector], locator = nil, options = {})
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
|
|
|
# Find all elements on the page matching the given selector
|
|
|
|
# and options.
|
|
|
|
#
|
|
|
|
# Both XPath and CSS expressions are supported, but Capybara
|
|
|
|
# does not try to automatically distinguish between them. The
|
|
|
|
# following statements are equivalent:
|
|
|
|
#
|
|
|
|
# page.all(:css, 'a#person_123')
|
|
|
|
# page.all(:xpath, '//a[@id="person_123"]')
|
|
|
|
#
|
|
|
|
#
|
|
|
|
# If the type of selector is left out, Capybara uses
|
2010-08-27 14:52:06 -04:00
|
|
|
# {Capybara.default_selector}. It's set to :css by default.
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
|
|
|
# page.all("a#person_123")
|
|
|
|
#
|
|
|
|
# Capybara.default_selector = :xpath
|
|
|
|
# page.all('//a[@id="person_123"]')
|
|
|
|
#
|
|
|
|
# The set of found elements can further be restricted by specifying
|
|
|
|
# options. It's possible to select elements by their text or visibility:
|
|
|
|
#
|
|
|
|
# page.all('a', :text => 'Home')
|
|
|
|
# page.all('#menu li', :visible => true)
|
|
|
|
#
|
2014-01-17 14:00:45 -05:00
|
|
|
# By default if no elements are found, an empty array is returned;
|
2015-08-25 16:35:43 -04:00
|
|
|
# however, expectations can be set on the number of elements to be found which
|
|
|
|
# will trigger Capybara's waiting behavior for the expectations to match.The
|
|
|
|
# expectations can be set using
|
2014-01-17 14:00:45 -05:00
|
|
|
#
|
|
|
|
# page.assert_selector('p#foo', :count => 4)
|
|
|
|
# page.assert_selector('p#foo', :maximum => 10)
|
|
|
|
# page.assert_selector('p#foo', :minimum => 1)
|
|
|
|
# page.assert_selector('p#foo', :between => 1..10)
|
|
|
|
#
|
|
|
|
# See {Capybara::Helpers#matches_count?} for additional information about
|
|
|
|
# count matching.
|
|
|
|
#
|
2016-09-23 18:03:36 -04:00
|
|
|
# @param [Symbol] kind Optional selector type (:css, :xpath, :field, etc.) - Defaults to Capybara.default_selector
|
|
|
|
# @param [String] locator The selector
|
|
|
|
# @option options [String, Regexp] text Only find elements which contain this text or match this regexp
|
|
|
|
# @option options [Boolean, Symbol] visible Only find elements with the specified visibility:
|
2014-10-22 00:57:30 -04:00
|
|
|
# * true - only finds visible elements.
|
|
|
|
# * false - finds invisible _and_ visible elements.
|
|
|
|
# * :all - same as false; finds visible and invisible elements.
|
|
|
|
# * :hidden - only finds invisible elements.
|
|
|
|
# * :visible - same as true; only finds visible elements.
|
2016-09-23 18:03:36 -04:00
|
|
|
# @option options [Integer] count Exact number of matches that are expected to be found
|
|
|
|
# @option options [Integer] maximum Maximum number of matches that are expected to be found
|
|
|
|
# @option options [Integer] minimum Minimum number of matches that are expected to be found
|
|
|
|
# @option options [Range] between Number of matches found must be within the given range
|
|
|
|
# @option options [Boolean] exact Control whether `is` expressions in the given XPath match exactly or partially
|
|
|
|
# @option options [Integer] wait (Capybara.default_max_wait_time) The time to wait for element count expectations to become true
|
|
|
|
# @overload all([kind = Capybara.default_selector], locator = nil, options = {})
|
|
|
|
# @overload all([kind = Capybara.default_selector], locator = nil, options = {}, &filter_block)
|
|
|
|
# @yieldparam element [Capybara::Node::Element] The element being considered for inclusion in the results
|
|
|
|
# @yieldreturn [Boolean] Should the element be considered in the results?
|
2013-01-28 18:58:15 -05:00
|
|
|
# @return [Capybara::Result] A collection of found elements
|
2010-07-17 13:05:00 -04:00
|
|
|
#
|
2016-09-23 18:03:36 -04:00
|
|
|
def all(*args, &optional_filter_block)
|
|
|
|
query = Capybara::Queries::SelectorQuery.new(*args, &optional_filter_block)
|
2014-01-17 14:00:45 -05:00
|
|
|
synchronize(query.wait) do
|
2014-02-16 12:13:58 -05:00
|
|
|
result = query.resolve_for(self)
|
|
|
|
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
|
2014-01-17 14:00:45 -05:00
|
|
|
result
|
|
|
|
end
|
2010-12-22 22:24:20 -05:00
|
|
|
end
|
2015-04-23 14:11:57 -04:00
|
|
|
alias_method :find_all, :all
|
2010-07-09 20:20:32 -04:00
|
|
|
|
2010-12-22 22:24:20 -05:00
|
|
|
##
|
|
|
|
#
|
|
|
|
# Find the first element on the page matching the given selector
|
2015-08-25 16:35:43 -04:00
|
|
|
# and options, or nil if no element matches. By default no waiting
|
|
|
|
# behavior occurs, however if {Capybara.wait_on_first_by_default} is set to true
|
|
|
|
# it will trigger Capybara's waiting behavior for a minimum of 1 matching element to be found and
|
|
|
|
# return the first. Waiting behavior can also be triggered by passing in any of the count
|
|
|
|
# expectation options.
|
2010-12-22 22:24:20 -05:00
|
|
|
#
|
2011-12-28 16:31:49 -05:00
|
|
|
# @overload first([kind], locator, options)
|
|
|
|
# @param [:css, :xpath] kind The type of selector
|
|
|
|
# @param [String] locator The selector
|
2013-03-28 22:15:07 -04:00
|
|
|
# @param [Hash] options Additional options; see {#all}
|
2015-02-25 23:16:38 -05:00
|
|
|
# @return [Capybara::Node::Element] The found element or nil
|
2010-12-22 22:24:20 -05:00
|
|
|
#
|
2016-09-23 18:03:36 -04:00
|
|
|
def first(*args, &optional_filter_block)
|
2015-04-21 13:52:49 -04:00
|
|
|
if Capybara.wait_on_first_by_default
|
|
|
|
options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
|
|
|
args.push({minimum: 1}.merge(options))
|
|
|
|
end
|
2016-09-23 18:03:36 -04:00
|
|
|
all(*args, &optional_filter_block).first
|
2015-04-21 13:52:49 -04:00
|
|
|
rescue Capybara::ExpectationNotMet
|
|
|
|
nil
|
2010-12-22 22:24:20 -05:00
|
|
|
end
|
2016-09-23 18:03:36 -04:00
|
|
|
|
2010-07-09 20:20:32 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|