Merge pull request #1763 from jnicklas/custom_filter_block
support custom filter block in finders/matchers/assertions
This commit is contained in:
commit
6000e0d332
|
@ -28,8 +28,8 @@ module Capybara
|
||||||
# @return [Capybara::Node::Element] The found element
|
# @return [Capybara::Node::Element] The found element
|
||||||
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
# @raise [Capybara::ElementNotFound] If the element can't be found before time expires
|
||||||
#
|
#
|
||||||
def find(*args)
|
def find(*args, &optional_filter_block)
|
||||||
query = Capybara::Queries::SelectorQuery.new(*args)
|
query = Capybara::Queries::SelectorQuery.new(*args, &optional_filter_block)
|
||||||
synchronize(query.wait) do
|
synchronize(query.wait) do
|
||||||
if (query.match == :smart or query.match == :prefer_exact) and query.supports_exact?
|
if (query.match == :smart or query.match == :prefer_exact) and query.supports_exact?
|
||||||
result = query.resolve_for(self, true)
|
result = query.resolve_for(self, true)
|
||||||
|
@ -74,9 +74,9 @@ module Capybara
|
||||||
# @return [Capybara::Node::Element] The found element
|
# @return [Capybara::Node::Element] The found element
|
||||||
#
|
#
|
||||||
|
|
||||||
def find_field(locator=nil, options={})
|
def find_field(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
find(:field, locator, options)
|
find(:field, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
alias_method :field_labeled, :find_field
|
alias_method :field_labeled, :find_field
|
||||||
|
|
||||||
|
@ -96,9 +96,9 @@ module Capybara
|
||||||
# @option options [String, Array<String>] class Match links that match the class(es) provided
|
# @option options [String, Array<String>] class Match links that match the class(es) provided
|
||||||
# @return [Capybara::Node::Element] The found element
|
# @return [Capybara::Node::Element] The found element
|
||||||
#
|
#
|
||||||
def find_link(locator=nil, options={})
|
def find_link(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
find(:link, locator, options)
|
find(:link, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -125,9 +125,9 @@ module Capybara
|
||||||
# @option options [String, Array<String>] class Match links that match the class(es) provided
|
# @option options [String, Array<String>] class Match links that match the class(es) provided
|
||||||
# @return [Capybara::Node::Element] The found element
|
# @return [Capybara::Node::Element] The found element
|
||||||
#
|
#
|
||||||
def find_button(locator=nil, options={})
|
def find_button(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
find(:button, locator, options)
|
find(:button, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -140,11 +140,12 @@ module Capybara
|
||||||
#
|
#
|
||||||
# @return [Capybara::Node::Element] The found element
|
# @return [Capybara::Node::Element] The found element
|
||||||
#
|
#
|
||||||
def find_by_id(id, options={})
|
def find_by_id(id, options={}, &optional_filter_block)
|
||||||
find(:id, id, options)
|
find(:id, id, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
# @!method all([kind = Capybara.default_selector], locator = nil, options = {})
|
||||||
#
|
#
|
||||||
# Find all elements on the page matching the given selector
|
# Find all elements on the page matching the given selector
|
||||||
# and options.
|
# and options.
|
||||||
|
@ -184,26 +185,29 @@ module Capybara
|
||||||
# See {Capybara::Helpers#matches_count?} for additional information about
|
# See {Capybara::Helpers#matches_count?} for additional information about
|
||||||
# count matching.
|
# count matching.
|
||||||
#
|
#
|
||||||
# @overload all([kind], locator, options)
|
# @param [Symbol] kind Optional selector type (:css, :xpath, :field, etc.) - Defaults to Capybara.default_selector
|
||||||
# @param [:css, :xpath] kind The type of selector
|
# @param [String] locator The selector
|
||||||
# @param [String] locator The selector
|
# @option options [String, Regexp] text Only find elements which contain this text or match this regexp
|
||||||
# @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:
|
||||||
# @option options [Boolean, Symbol] visible Only find elements with the specified visibility:
|
|
||||||
# * true - only finds visible elements.
|
# * true - only finds visible elements.
|
||||||
# * false - finds invisible _and_ visible elements.
|
# * false - finds invisible _and_ visible elements.
|
||||||
# * :all - same as false; finds visible and invisible elements.
|
# * :all - same as false; finds visible and invisible elements.
|
||||||
# * :hidden - only finds invisible elements.
|
# * :hidden - only finds invisible elements.
|
||||||
# * :visible - same as true; only finds visible elements.
|
# * :visible - same as true; only finds visible elements.
|
||||||
# @option options [Integer] count Exact number of matches that are expected to be found
|
# @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] 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 [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 [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 [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
|
# @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?
|
||||||
# @return [Capybara::Result] A collection of found elements
|
# @return [Capybara::Result] A collection of found elements
|
||||||
#
|
#
|
||||||
def all(*args)
|
def all(*args, &optional_filter_block)
|
||||||
query = Capybara::Queries::SelectorQuery.new(*args)
|
query = Capybara::Queries::SelectorQuery.new(*args, &optional_filter_block)
|
||||||
synchronize(query.wait) do
|
synchronize(query.wait) do
|
||||||
result = query.resolve_for(self)
|
result = query.resolve_for(self)
|
||||||
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
|
raise Capybara::ExpectationNotMet, result.failure_message unless result.matches_count?
|
||||||
|
@ -227,15 +231,16 @@ module Capybara
|
||||||
# @param [Hash] options Additional options; see {#all}
|
# @param [Hash] options Additional options; see {#all}
|
||||||
# @return [Capybara::Node::Element] The found element or nil
|
# @return [Capybara::Node::Element] The found element or nil
|
||||||
#
|
#
|
||||||
def first(*args)
|
def first(*args, &optional_filter_block)
|
||||||
if Capybara.wait_on_first_by_default
|
if Capybara.wait_on_first_by_default
|
||||||
options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
||||||
args.push({minimum: 1}.merge(options))
|
args.push({minimum: 1}.merge(options))
|
||||||
end
|
end
|
||||||
all(*args).first
|
all(*args, &optional_filter_block).first
|
||||||
rescue Capybara::ExpectationNotMet
|
rescue Capybara::ExpectationNotMet
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,8 +36,8 @@ module Capybara
|
||||||
# @option args [Range] :between (nil) Range of times that should contain number of times text occurs
|
# @option args [Range] :between (nil) Range of times that should contain number of times text occurs
|
||||||
# @return [Boolean] If the expression exists
|
# @return [Boolean] If the expression exists
|
||||||
#
|
#
|
||||||
def has_selector?(*args)
|
def has_selector?(*args, &optional_filter_block)
|
||||||
assert_selector(*args)
|
assert_selector(*args, &optional_filter_block)
|
||||||
rescue Capybara::ExpectationNotMet
|
rescue Capybara::ExpectationNotMet
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
@ -50,83 +50,12 @@ module Capybara
|
||||||
# @param (see Capybara::Node::Finders#has_selector?)
|
# @param (see Capybara::Node::Finders#has_selector?)
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
#
|
#
|
||||||
def has_no_selector?(*args)
|
def has_no_selector?(*args, &optional_filter_block)
|
||||||
assert_no_selector(*args)
|
assert_no_selector(*args, &optional_filter_block)
|
||||||
rescue Capybara::ExpectationNotMet
|
rescue Capybara::ExpectationNotMet
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Checks if the current node matches given selector
|
|
||||||
#
|
|
||||||
# @param (see Capybara::Node::Finders#has_selector?)
|
|
||||||
# @return [Boolean]
|
|
||||||
#
|
|
||||||
def matches_selector?(*args)
|
|
||||||
assert_matches_selector(*args)
|
|
||||||
rescue Capybara::ExpectationNotMet
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Checks if the current node matches given XPath expression
|
|
||||||
#
|
|
||||||
# @param [String, XPath::Expression] xpath The XPath expression to match against the current code
|
|
||||||
# @return [Boolean]
|
|
||||||
#
|
|
||||||
def matches_xpath?(xpath, options={})
|
|
||||||
matches_selector?(:xpath, xpath, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Checks if the current node matches given CSS selector
|
|
||||||
#
|
|
||||||
# @param [String] css The CSS selector to match against the current code
|
|
||||||
# @return [Boolean]
|
|
||||||
#
|
|
||||||
def matches_css?(css, options={})
|
|
||||||
matches_selector?(:css, css, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Checks if the current node does not match given selector
|
|
||||||
# Usage is identical to Capybara::Node::Matchers#has_selector?
|
|
||||||
#
|
|
||||||
# @param (see Capybara::Node::Finders#has_selector?)
|
|
||||||
# @return [Boolean]
|
|
||||||
#
|
|
||||||
def not_matches_selector?(*args)
|
|
||||||
assert_not_matches_selector(*args)
|
|
||||||
rescue Capybara::ExpectationNotMet
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Checks if the current node does not match given XPath expression
|
|
||||||
#
|
|
||||||
# @param [String, XPath::Expression] xpath The XPath expression to match against the current code
|
|
||||||
# @return [Boolean]
|
|
||||||
#
|
|
||||||
def not_matches_xpath?(xpath, options={})
|
|
||||||
not_matches_selector?(:xpath, xpath, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Checks if the current node does not match given CSS selector
|
|
||||||
#
|
|
||||||
# @param [String] css The CSS selector to match against the current code
|
|
||||||
# @return [Boolean]
|
|
||||||
#
|
|
||||||
def not_matches_css?(css, options={})
|
|
||||||
not_matches_selector?(:css, css, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
# Asserts that a given selector is on the page or a descendant of the current node.
|
# Asserts that a given selector is on the page or a descendant of the current node.
|
||||||
|
@ -160,8 +89,8 @@ module Capybara
|
||||||
# @option options [Integer] :count (nil) Number of times the expression should occur
|
# @option options [Integer] :count (nil) Number of times the expression should occur
|
||||||
# @raise [Capybara::ExpectationNotMet] If the selector does not exist
|
# @raise [Capybara::ExpectationNotMet] If the selector does not exist
|
||||||
#
|
#
|
||||||
def assert_selector(*args)
|
def assert_selector(*args, &optional_filter_block)
|
||||||
query = Capybara::Queries::SelectorQuery.new(*args)
|
query = Capybara::Queries::SelectorQuery.new(*args, &optional_filter_block)
|
||||||
synchronize(query.wait) do
|
synchronize(query.wait) do
|
||||||
result = query.resolve_for(self)
|
result = query.resolve_for(self)
|
||||||
unless result.matches_count? && ((!result.empty?) || query.expects_none?)
|
unless result.matches_count? && ((!result.empty?) || query.expects_none?)
|
||||||
|
@ -187,8 +116,8 @@ module Capybara
|
||||||
# @param (see Capybara::Node::Finders#assert_selector)
|
# @param (see Capybara::Node::Finders#assert_selector)
|
||||||
# @raise [Capybara::ExpectationNotMet] If the selector exists
|
# @raise [Capybara::ExpectationNotMet] If the selector exists
|
||||||
#
|
#
|
||||||
def assert_no_selector(*args)
|
def assert_no_selector(*args, &optional_filter_block)
|
||||||
query = Capybara::Queries::SelectorQuery.new(*args)
|
query = Capybara::Queries::SelectorQuery.new(*args, &optional_filter_block)
|
||||||
synchronize(query.wait) do
|
synchronize(query.wait) do
|
||||||
result = query.resolve_for(self)
|
result = query.resolve_for(self)
|
||||||
if result.matches_count? && ((!result.empty?) || query.expects_none?)
|
if result.matches_count? && ((!result.empty?) || query.expects_none?)
|
||||||
|
@ -199,45 +128,6 @@ module Capybara
|
||||||
end
|
end
|
||||||
alias_method :refute_selector, :assert_no_selector
|
alias_method :refute_selector, :assert_no_selector
|
||||||
|
|
||||||
##
|
|
||||||
#
|
|
||||||
# Asserts that the current_node matches a given selector
|
|
||||||
#
|
|
||||||
# node.assert_matches_selector('p#foo')
|
|
||||||
# node.assert_matches_selector(:xpath, '//p[@id="foo"]')
|
|
||||||
# node.assert_matches_selector(:foo)
|
|
||||||
#
|
|
||||||
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
|
||||||
# such as :text and :visible.
|
|
||||||
#
|
|
||||||
# node.assert_matches_selector('li', :text => 'Horse', :visible => true)
|
|
||||||
#
|
|
||||||
# @param (see Capybara::Node::Finders#all)
|
|
||||||
# @raise [Capybara::ExpectationNotMet] If the selector does not match
|
|
||||||
#
|
|
||||||
def assert_matches_selector(*args)
|
|
||||||
query = Capybara::Queries::MatchQuery.new(*args)
|
|
||||||
synchronize(query.wait) do
|
|
||||||
result = query.resolve_for(self.query_scope)
|
|
||||||
unless result.include? self
|
|
||||||
raise Capybara::ExpectationNotMet, "Item does not match the provided selector"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
def assert_not_matches_selector(*args)
|
|
||||||
query = Capybara::Queries::MatchQuery.new(*args)
|
|
||||||
synchronize(query.wait) do
|
|
||||||
result = query.resolve_for(self.query_scope)
|
|
||||||
if result.include? self
|
|
||||||
raise Capybara::ExpectationNotMet, 'Item matched the provided selector'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
alias_method :refute_matches_selector, :assert_not_matches_selector
|
|
||||||
|
|
||||||
##
|
##
|
||||||
#
|
#
|
||||||
# Checks if a given XPath expression is on the page or a descendant of the current node.
|
# Checks if a given XPath expression is on the page or a descendant of the current node.
|
||||||
|
@ -267,8 +157,8 @@ module Capybara
|
||||||
# @option options [Integer] :count (nil) Number of times the expression should occur
|
# @option options [Integer] :count (nil) Number of times the expression should occur
|
||||||
# @return [Boolean] If the expression exists
|
# @return [Boolean] If the expression exists
|
||||||
#
|
#
|
||||||
def has_xpath?(path, options={})
|
def has_xpath?(path, options={}, &optional_filter_block)
|
||||||
has_selector?(:xpath, path, options)
|
has_selector?(:xpath, path, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -279,8 +169,8 @@ module Capybara
|
||||||
# @param (see Capybara::Node::Finders#has_xpath?)
|
# @param (see Capybara::Node::Finders#has_xpath?)
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
#
|
#
|
||||||
def has_no_xpath?(path, options={})
|
def has_no_xpath?(path, options={}, &optional_filter_block)
|
||||||
has_no_selector?(:xpath, path, options)
|
has_no_selector?(:xpath, path, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -306,8 +196,8 @@ module Capybara
|
||||||
# @option options [Integer] :count (nil) Number of times the selector should occur
|
# @option options [Integer] :count (nil) Number of times the selector should occur
|
||||||
# @return [Boolean] If the selector exists
|
# @return [Boolean] If the selector exists
|
||||||
#
|
#
|
||||||
def has_css?(path, options={})
|
def has_css?(path, options={}, &optional_filter_block)
|
||||||
has_selector?(:css, path, options)
|
has_selector?(:css, path, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -318,8 +208,8 @@ module Capybara
|
||||||
# @param (see Capybara::Node::Finders#has_css?)
|
# @param (see Capybara::Node::Finders#has_css?)
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
#
|
#
|
||||||
def has_no_css?(path, options={})
|
def has_no_css?(path, options={}, &optional_filter_block)
|
||||||
has_no_selector?(:css, path, options)
|
has_no_selector?(:css, path, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -332,9 +222,9 @@ module Capybara
|
||||||
# @option options [String, Regexp] :href The value the href attribute must be
|
# @option options [String, Regexp] :href The value the href attribute must be
|
||||||
# @return [Boolean] Whether it exists
|
# @return [Boolean] Whether it exists
|
||||||
#
|
#
|
||||||
def has_link?(locator=nil, options={})
|
def has_link?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_selector?(:link, locator, options)
|
has_selector?(:link, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -345,9 +235,9 @@ module Capybara
|
||||||
# @param (see Capybara::Node::Finders#has_link?)
|
# @param (see Capybara::Node::Finders#has_link?)
|
||||||
# @return [Boolean] Whether it doesn't exist
|
# @return [Boolean] Whether it doesn't exist
|
||||||
#
|
#
|
||||||
def has_no_link?(locator=nil, options={})
|
def has_no_link?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_no_selector?(:link, locator, options)
|
has_no_selector?(:link, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -358,9 +248,9 @@ module Capybara
|
||||||
# @param [String] locator The text, value or id of a button to check for
|
# @param [String] locator The text, value or id of a button to check for
|
||||||
# @return [Boolean] Whether it exists
|
# @return [Boolean] Whether it exists
|
||||||
#
|
#
|
||||||
def has_button?(locator=nil, options={})
|
def has_button?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_selector?(:button, locator, options)
|
has_selector?(:button, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -371,9 +261,9 @@ module Capybara
|
||||||
# @param [String] locator The text, value or id of a button to check for
|
# @param [String] locator The text, value or id of a button to check for
|
||||||
# @return [Boolean] Whether it doesn't exist
|
# @return [Boolean] Whether it doesn't exist
|
||||||
#
|
#
|
||||||
def has_no_button?(locator=nil, options={})
|
def has_no_button?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_no_selector?(:button, locator, options)
|
has_no_selector?(:button, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -398,9 +288,9 @@ module Capybara
|
||||||
# @option options [String] :type The type attribute of the field
|
# @option options [String] :type The type attribute of the field
|
||||||
# @return [Boolean] Whether it exists
|
# @return [Boolean] Whether it exists
|
||||||
#
|
#
|
||||||
def has_field?(locator=nil, options={})
|
def has_field?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_selector?(:field, locator, options)
|
has_selector?(:field, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -413,9 +303,9 @@ module Capybara
|
||||||
# @option options [String] :type The type attribute of the field
|
# @option options [String] :type The type attribute of the field
|
||||||
# @return [Boolean] Whether it doesn't exist
|
# @return [Boolean] Whether it doesn't exist
|
||||||
#
|
#
|
||||||
def has_no_field?(locator=nil, options={})
|
def has_no_field?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_no_selector?(:field, locator, options)
|
has_no_selector?(:field, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -427,9 +317,9 @@ module Capybara
|
||||||
# @param [String] locator The label, name or id of a checked field
|
# @param [String] locator The label, name or id of a checked field
|
||||||
# @return [Boolean] Whether it exists
|
# @return [Boolean] Whether it exists
|
||||||
#
|
#
|
||||||
def has_checked_field?(locator=nil, options={})
|
def has_checked_field?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_selector?(:field, locator, options.merge(:checked => true))
|
has_selector?(:field, locator, options.merge(:checked => true), &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -441,7 +331,7 @@ module Capybara
|
||||||
# @param [String] locator The label, name or id of a checked field
|
# @param [String] locator The label, name or id of a checked field
|
||||||
# @return [Boolean] Whether it doesn't exist
|
# @return [Boolean] Whether it doesn't exist
|
||||||
#
|
#
|
||||||
def has_no_checked_field?(locator=nil, options={})
|
def has_no_checked_field?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_no_selector?(:field, locator, options.merge(:checked => true))
|
has_no_selector?(:field, locator, options.merge(:checked => true))
|
||||||
end
|
end
|
||||||
|
@ -455,9 +345,9 @@ module Capybara
|
||||||
# @param [String] locator The label, name or id of an unchecked field
|
# @param [String] locator The label, name or id of an unchecked field
|
||||||
# @return [Boolean] Whether it exists
|
# @return [Boolean] Whether it exists
|
||||||
#
|
#
|
||||||
def has_unchecked_field?(locator=nil, options={})
|
def has_unchecked_field?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_selector?(:field, locator, options.merge(:unchecked => true))
|
has_selector?(:field, locator, options.merge(:unchecked => true), &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -469,9 +359,9 @@ module Capybara
|
||||||
# @param [String] locator The label, name or id of an unchecked field
|
# @param [String] locator The label, name or id of an unchecked field
|
||||||
# @return [Boolean] Whether it doesn't exist
|
# @return [Boolean] Whether it doesn't exist
|
||||||
#
|
#
|
||||||
def has_no_unchecked_field?(locator=nil, options={})
|
def has_no_unchecked_field?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_no_selector?(:field, locator, options.merge(:unchecked => true))
|
has_no_selector?(:field, locator, options.merge(:unchecked => true), &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -502,9 +392,9 @@ module Capybara
|
||||||
# @option options [String, Array] :selected Options which should be selected
|
# @option options [String, Array] :selected Options which should be selected
|
||||||
# @return [Boolean] Whether it exists
|
# @return [Boolean] Whether it exists
|
||||||
#
|
#
|
||||||
def has_select?(locator=nil, options={})
|
def has_select?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_selector?(:select, locator, options)
|
has_selector?(:select, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -515,9 +405,9 @@ module Capybara
|
||||||
# @param (see Capybara::Node::Matchers#has_select?)
|
# @param (see Capybara::Node::Matchers#has_select?)
|
||||||
# @return [Boolean] Whether it doesn't exist
|
# @return [Boolean] Whether it doesn't exist
|
||||||
#
|
#
|
||||||
def has_no_select?(locator=nil, options={})
|
def has_no_select?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_no_selector?(:select, locator, options)
|
has_no_selector?(:select, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -530,9 +420,9 @@ module Capybara
|
||||||
# @param [String] locator The id or caption of a table
|
# @param [String] locator The id or caption of a table
|
||||||
# @return [Boolean] Whether it exist
|
# @return [Boolean] Whether it exist
|
||||||
#
|
#
|
||||||
def has_table?(locator=nil, options={})
|
def has_table?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_selector?(:table, locator, options)
|
has_selector?(:table, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -543,11 +433,122 @@ module Capybara
|
||||||
# @param (see Capybara::Node::Matchers#has_table?)
|
# @param (see Capybara::Node::Matchers#has_table?)
|
||||||
# @return [Boolean] Whether it doesn't exist
|
# @return [Boolean] Whether it doesn't exist
|
||||||
#
|
#
|
||||||
def has_no_table?(locator=nil, options={})
|
def has_no_table?(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
has_no_selector?(:table, locator, options)
|
has_no_selector?(:table, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Asserts that the current_node matches a given selector
|
||||||
|
#
|
||||||
|
# node.assert_matches_selector('p#foo')
|
||||||
|
# node.assert_matches_selector(:xpath, '//p[@id="foo"]')
|
||||||
|
# node.assert_matches_selector(:foo)
|
||||||
|
#
|
||||||
|
# It also accepts all options that {Capybara::Node::Finders#all} accepts,
|
||||||
|
# such as :text and :visible.
|
||||||
|
#
|
||||||
|
# node.assert_matches_selector('li', :text => 'Horse', :visible => true)
|
||||||
|
#
|
||||||
|
# @param (see Capybara::Node::Finders#all)
|
||||||
|
# @raise [Capybara::ExpectationNotMet] If the selector does not match
|
||||||
|
#
|
||||||
|
def assert_matches_selector(*args, &optional_filter_block)
|
||||||
|
query = Capybara::Queries::MatchQuery.new(*args, &optional_filter_block)
|
||||||
|
synchronize(query.wait) do
|
||||||
|
result = query.resolve_for(self.query_scope)
|
||||||
|
unless result.include? self
|
||||||
|
raise Capybara::ExpectationNotMet, "Item does not match the provided selector"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_not_matches_selector(*args, &optional_filter_block)
|
||||||
|
query = Capybara::Queries::MatchQuery.new(*args)
|
||||||
|
synchronize(query.wait) do
|
||||||
|
result = query.resolve_for(self.query_scope)
|
||||||
|
if result.include? self
|
||||||
|
raise Capybara::ExpectationNotMet, 'Item matched the provided selector'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
alias_method :refute_matches_selector, :assert_not_matches_selector
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Checks if the current node matches given selector
|
||||||
|
#
|
||||||
|
# @param (see Capybara::Node::Finders#has_selector?)
|
||||||
|
# @return [Boolean]
|
||||||
|
#
|
||||||
|
def matches_selector?(*args, &optional_filter_block)
|
||||||
|
assert_matches_selector(*args, &optional_filter_block)
|
||||||
|
rescue Capybara::ExpectationNotMet
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Checks if the current node matches given XPath expression
|
||||||
|
#
|
||||||
|
# @param [String, XPath::Expression] xpath The XPath expression to match against the current code
|
||||||
|
# @return [Boolean]
|
||||||
|
#
|
||||||
|
def matches_xpath?(xpath, options={}, &optional_filter_block)
|
||||||
|
matches_selector?(:xpath, xpath, options, &optional_filter_block)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Checks if the current node matches given CSS selector
|
||||||
|
#
|
||||||
|
# @param [String] css The CSS selector to match against the current code
|
||||||
|
# @return [Boolean]
|
||||||
|
#
|
||||||
|
def matches_css?(css, options={}, &optional_filter_block)
|
||||||
|
matches_selector?(:css, css, options)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Checks if the current node does not match given selector
|
||||||
|
# Usage is identical to Capybara::Node::Matchers#has_selector?
|
||||||
|
#
|
||||||
|
# @param (see Capybara::Node::Finders#has_selector?)
|
||||||
|
# @return [Boolean]
|
||||||
|
#
|
||||||
|
def not_matches_selector?(*args, &optional_filter_block)
|
||||||
|
assert_not_matches_selector(*args, &optional_filter_block)
|
||||||
|
rescue Capybara::ExpectationNotMet
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Checks if the current node does not match given XPath expression
|
||||||
|
#
|
||||||
|
# @param [String, XPath::Expression] xpath The XPath expression to match against the current code
|
||||||
|
# @return [Boolean]
|
||||||
|
#
|
||||||
|
def not_matches_xpath?(xpath, options={}, &optional_filter_block)
|
||||||
|
not_matches_selector?(:xpath, xpath, options, &optional_filter_block)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
#
|
||||||
|
# Checks if the current node does not match given CSS selector
|
||||||
|
#
|
||||||
|
# @param [String] css The CSS selector to match against the current code
|
||||||
|
# @return [Boolean]
|
||||||
|
#
|
||||||
|
def not_matches_css?(css, options={}, &optional_filter_block)
|
||||||
|
not_matches_selector?(:css, css, options, &optional_filter_block)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
# Asserts that the page or current node has the given text content,
|
# Asserts that the page or current node has the given text content,
|
||||||
# ignoring any HTML tags.
|
# ignoring any HTML tags.
|
||||||
|
@ -643,6 +644,7 @@ module Capybara
|
||||||
def ==(other)
|
def ==(other)
|
||||||
self.eql?(other) || (other.respond_to?(:base) && base == other.base)
|
self.eql?(other) || (other.respond_to?(:base) && base == other.base)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,8 +7,9 @@ module Capybara
|
||||||
VALID_KEYS = COUNT_KEYS + [:text, :id, :class, :visible, :exact, :match, :wait, :filter_set]
|
VALID_KEYS = COUNT_KEYS + [:text, :id, :class, :visible, :exact, :match, :wait, :filter_set]
|
||||||
VALID_MATCH = [:first, :smart, :prefer_exact, :one]
|
VALID_MATCH = [:first, :smart, :prefer_exact, :one]
|
||||||
|
|
||||||
def initialize(*args)
|
def initialize(*args, &filter_block)
|
||||||
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
@options = if args.last.is_a?(Hash) then args.pop.dup else {} end
|
||||||
|
@filter_block = filter_block
|
||||||
|
|
||||||
if args[0].is_a?(Symbol)
|
if args[0].is_a?(Symbol)
|
||||||
@selector = Selector.all.fetch(args.shift) do |selector_type|
|
@selector = Selector.all.fetch(args.shift) do |selector_type|
|
||||||
|
@ -45,6 +46,7 @@ module Capybara
|
||||||
@description << " with id #{options[:id]}" if options[:id]
|
@description << " with id #{options[:id]}" if options[:id]
|
||||||
@description << " with classes #{Array(options[:class]).join(',')}]" if options[:class]
|
@description << " with classes #{Array(options[:class]).join(',')}]" if options[:class]
|
||||||
@description << selector.description(options)
|
@description << selector.description(options)
|
||||||
|
@description << " that also matches the custom filter block" if @filter_block
|
||||||
@description
|
@description
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -59,7 +61,7 @@ module Capybara
|
||||||
when :hidden then return false if node.visible?
|
when :hidden then return false if node.visible?
|
||||||
end
|
end
|
||||||
|
|
||||||
query_filters.all? do |name, filter|
|
res = query_filters.all? do |name, filter|
|
||||||
if options.has_key?(name)
|
if options.has_key?(name)
|
||||||
filter.matches?(node, options[name])
|
filter.matches?(node, options[name])
|
||||||
elsif filter.default?
|
elsif filter.default?
|
||||||
|
@ -68,6 +70,9 @@ module Capybara
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
res &&= @filter_block.call(node) unless @filter_block.nil?
|
||||||
|
res
|
||||||
end
|
end
|
||||||
|
|
||||||
def visible
|
def visible
|
||||||
|
|
|
@ -16,8 +16,9 @@ module Capybara
|
||||||
class HaveSelector < Matcher
|
class HaveSelector < Matcher
|
||||||
attr_reader :failure_message, :failure_message_when_negated
|
attr_reader :failure_message, :failure_message_when_negated
|
||||||
|
|
||||||
def initialize(*args)
|
def initialize(*args, &filter_block)
|
||||||
@args = args
|
@args = args
|
||||||
|
@filter_block = filter_block
|
||||||
end
|
end
|
||||||
|
|
||||||
def matches?(actual)
|
def matches?(actual)
|
||||||
|
@ -39,7 +40,7 @@ module Capybara
|
||||||
end
|
end
|
||||||
|
|
||||||
def query
|
def query
|
||||||
@query ||= Capybara::Queries::SelectorQuery.new(*@args)
|
@query ||= Capybara::Queries::SelectorQuery.new(*@args, &@filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# RSpec 2 compatibility:
|
# RSpec 2 compatibility:
|
||||||
|
@ -221,8 +222,8 @@ module Capybara
|
||||||
alias_method :failure_message_for_should_not, :failure_message_when_negated
|
alias_method :failure_message_for_should_not, :failure_message_when_negated
|
||||||
end
|
end
|
||||||
|
|
||||||
def have_selector(*args)
|
def have_selector(*args, &optional_filter_block)
|
||||||
HaveSelector.new(*args)
|
HaveSelector.new(*args, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def match_selector(*args)
|
def match_selector(*args)
|
||||||
|
@ -233,16 +234,16 @@ module Capybara
|
||||||
::RSpec::Matchers.define_negated_matcher :not_match_selector, :match_selector if defined?(::RSpec::Expectations::Version) && (Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.1'))
|
::RSpec::Matchers.define_negated_matcher :not_match_selector, :match_selector if defined?(::RSpec::Expectations::Version) && (Gem::Version.new(RSpec::Expectations::Version::STRING) >= Gem::Version.new('3.1'))
|
||||||
|
|
||||||
|
|
||||||
def have_xpath(xpath, options={})
|
def have_xpath(xpath, options={}, &optional_filter_block)
|
||||||
HaveSelector.new(:xpath, xpath, options)
|
HaveSelector.new(:xpath, xpath, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def match_xpath(xpath, options={})
|
def match_xpath(xpath, options={})
|
||||||
MatchSelector.new(:xpath, xpath, options)
|
MatchSelector.new(:xpath, xpath, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def have_css(css, options={})
|
def have_css(css, options={}, &optional_filter_block)
|
||||||
HaveSelector.new(:css, css, options)
|
HaveSelector.new(:css, css, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def match_css(css, options={})
|
def match_css(css, options={})
|
||||||
|
@ -262,39 +263,39 @@ module Capybara
|
||||||
HaveCurrentPath.new(path, options)
|
HaveCurrentPath.new(path, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def have_link(locator=nil, options={})
|
def have_link(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
HaveSelector.new(:link, locator, options)
|
HaveSelector.new(:link, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def have_button(locator=nil, options={})
|
def have_button(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
HaveSelector.new(:button, locator, options)
|
HaveSelector.new(:button, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def have_field(locator=nil, options={})
|
def have_field(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
HaveSelector.new(:field, locator, options)
|
HaveSelector.new(:field, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def have_checked_field(locator=nil, options={})
|
def have_checked_field(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
HaveSelector.new(:field, locator, options.merge(:checked => true))
|
HaveSelector.new(:field, locator, options.merge(:checked => true), &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def have_unchecked_field(locator=nil, options={})
|
def have_unchecked_field(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
HaveSelector.new(:field, locator, options.merge(:unchecked => true))
|
HaveSelector.new(:field, locator, options.merge(:unchecked => true), &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def have_select(locator=nil, options={})
|
def have_select(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
HaveSelector.new(:select, locator, options)
|
HaveSelector.new(:select, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def have_table(locator=nil, options={})
|
def have_table(locator=nil, options={}, &optional_filter_block)
|
||||||
locator, options = nil, locator if locator.is_a? Hash
|
locator, options = nil, locator if locator.is_a? Hash
|
||||||
HaveSelector.new(:table, locator, options)
|
HaveSelector.new(:table, locator, options, &optional_filter_block)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -306,5 +307,6 @@ module Capybara
|
||||||
def become_closed(options = {})
|
def become_closed(options = {})
|
||||||
BecomeClosed.new(options)
|
BecomeClosed.new(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,6 +48,13 @@ Capybara::SpecHelper.spec '#match_selector?' do
|
||||||
cbox = @session.find(:css, '#form_pets_dog')
|
cbox = @session.find(:css, '#form_pets_dog')
|
||||||
expect(cbox.matches_selector?(:checkbox, id: 'form_pets_dog', option: 'dog', name: 'form[pets][]', checked: true)).to be true
|
expect(cbox.matches_selector?(:checkbox, id: 'form_pets_dog', option: 'dog', name: 'form[pets][]', checked: true)).to be true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'should accept a custom filter block' do
|
||||||
|
@session.visit('/form')
|
||||||
|
cbox = @session.find(:css, '#form_pets_dog')
|
||||||
|
expect(cbox.matches_selector?(:checkbox){ |node| node[:id] == "form_pets_dog"}).to be true
|
||||||
|
expect(cbox.matches_selector?(:checkbox){ |node| node[:id] != "form_pets_dog"}).to be false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Capybara::SpecHelper.spec '#not_matches_selector?' do
|
Capybara::SpecHelper.spec '#not_matches_selector?' do
|
||||||
|
|
|
@ -8,7 +8,6 @@ Capybara::SpecHelper.spec '#find_field' do
|
||||||
expect(@session.find_field('Dog').value).to eq('dog')
|
expect(@session.find_field('Dog').value).to eq('dog')
|
||||||
expect(@session.find_field('form_description').text).to eq('Descriptive text goes here')
|
expect(@session.find_field('form_description').text).to eq('Descriptive text goes here')
|
||||||
expect(@session.find_field('Region')[:name]).to eq('form[region]')
|
expect(@session.find_field('Region')[:name]).to eq('form[region]')
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "aria_label attribute with Capybara.enable_aria_label" do
|
context "aria_label attribute with Capybara.enable_aria_label" do
|
||||||
|
@ -107,4 +106,9 @@ Capybara::SpecHelper.spec '#find_field' do
|
||||||
expect(@session.find_field(with: 'dog')['id']).to eq "form_pets_dog"
|
expect(@session.find_field(with: 'dog')['id']).to eq "form_pets_dog"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should accept an optional filter block" do
|
||||||
|
# this would be better done with the :with option but this is just a test
|
||||||
|
expect(@session.find_field('form[pets][]'){ |node| node.value == 'dog' }[:id]).to eq "form_pets_dog"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -399,6 +399,10 @@ Capybara::SpecHelper.spec '#find' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "supports a custom filter block" do
|
||||||
|
expect(@session.find(:css, 'input'){|node| node.disabled? }[:name]).to eq('disabled_text')
|
||||||
|
end
|
||||||
|
|
||||||
context "within a scope" do
|
context "within a scope" do
|
||||||
before do
|
before do
|
||||||
@session.visit('/with_scope')
|
@session.visit('/with_scope')
|
||||||
|
|
Loading…
Reference in New Issue