mirror of
https://github.com/teamcapybara/capybara.git
synced 2022-11-09 12:08:07 -05:00
Support easier full text matching
This commit is contained in:
parent
f6bbc6b639
commit
e85cce5778
11 changed files with 96 additions and 12 deletions
|
@ -29,6 +29,7 @@ module Capybara
|
|||
attr_accessor :raise_server_errors, :server_errors
|
||||
attr_writer :default_driver, :current_driver, :javascript_driver, :session_name, :server_host
|
||||
attr_reader :save_and_open_page_path
|
||||
attr_accessor :exact_text
|
||||
attr_accessor :app
|
||||
|
||||
##
|
||||
|
@ -495,6 +496,7 @@ Capybara.configure do |config|
|
|||
config.automatic_reload = true
|
||||
config.match = :smart
|
||||
config.exact = false
|
||||
config.exact_text = false
|
||||
config.raise_server_errors = true
|
||||
config.server_errors = [StandardError]
|
||||
config.visible_text_only = false
|
||||
|
|
|
@ -28,8 +28,14 @@ module Capybara
|
|||
# @param [String] text Text to escape
|
||||
# @return [String] Escaped text
|
||||
#
|
||||
def to_regexp(text, options=nil)
|
||||
text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(normalize_whitespace(text)), options)
|
||||
def to_regexp(text, regexp_options=nil, exact=false)
|
||||
if text.is_a?(Regexp)
|
||||
text
|
||||
else
|
||||
escaped = Regexp.escape(normalize_whitespace(text))
|
||||
escaped = "\\A#{escaped}\\z" if exact
|
||||
Regexp.new(escaped, regexp_options)
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -7,10 +7,11 @@ module Capybara
|
|||
#
|
||||
# @!macro title_query_params
|
||||
# @overload $0(string, options = {})
|
||||
# @param string [String] The string that title should include
|
||||
# @param string [String] The string that title should include #
|
||||
# @overload $0(regexp, options = {})
|
||||
# @param regexp [Regexp] The regexp that title should match to
|
||||
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for title to eq/match given string/regexp argument
|
||||
# @option options [Boolean] :exact (false) When passed a string should the match be exact or just substring
|
||||
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
||||
# @return [true]
|
||||
#
|
||||
|
|
|
@ -188,6 +188,7 @@ module Capybara
|
|||
# @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 [String, Boolean] exact_text (Capybara.exact_text) When String the string the elements contained text must match exactly, when Boolean controls whether the :text option must match exactly
|
||||
# @option options [Boolean, Symbol] visible Only find elements with the specified visibility:
|
||||
# * true - only finds visible elements.
|
||||
# * false - finds invisible _and_ visible elements.
|
||||
|
|
|
@ -546,6 +546,7 @@ module Capybara
|
|||
# @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
|
||||
# @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
|
||||
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for text to eq/match given string/regexp argument
|
||||
# @option options [Boolean] :exact (Capybara.exact_text) Whether text must be an exact match or just substring
|
||||
# @overload $0(text, options = {})
|
||||
# @param [String, Regexp] text The string/regexp to check for. If it's a string, text is expected to include it. If it's a regexp, text is expected to match it.
|
||||
# @option options [Integer] :count (nil) Number of times the text is expected to occur
|
||||
|
@ -553,6 +554,7 @@ module Capybara
|
|||
# @option options [Integer] :maximum (nil) Maximum number of times the text is expected to occur
|
||||
# @option options [Range] :between (nil) Range of times that is expected to contain number of times text occurs
|
||||
# @option options [Numeric] :wait (Capybara.default_max_wait_time) Maximum time that Capybara will wait for text to eq/match given string/regexp argument
|
||||
# @option options [Boolean] :exact (Capybara.exact_text) Whether text must be an exact match or just substring
|
||||
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
|
||||
# @return [true]
|
||||
#
|
||||
|
|
|
@ -4,7 +4,7 @@ module Capybara
|
|||
class SelectorQuery < Queries::BaseQuery
|
||||
attr_accessor :selector, :locator, :options, :expression, :find, :negative
|
||||
|
||||
VALID_KEYS = COUNT_KEYS + [:text, :id, :class, :visible, :exact, :match, :wait, :filter_set]
|
||||
VALID_KEYS = COUNT_KEYS + [:text, :id, :class, :visible, :exact, :exact_text, :match, :wait, :filter_set]
|
||||
VALID_MATCH = [:first, :smart, :prefer_exact, :one]
|
||||
|
||||
def initialize(*args, &filter_block)
|
||||
|
@ -42,7 +42,8 @@ module Capybara
|
|||
|
||||
def description
|
||||
@description = String.new("#{label} #{locator.inspect}")
|
||||
@description << " with text #{options[:text].inspect}" if options[:text]
|
||||
@description << " with#{" exact" if exact_text === true} text #{options[:text].inspect}" if options[:text]
|
||||
@description << " with exact text #{options[:exact_text]}" if options[:exact_text].is_a?(String)
|
||||
@description << " with id #{options[:id]}" if options[:id]
|
||||
@description << " with classes #{Array(options[:class]).join(',')}]" if options[:class]
|
||||
@description << selector.description(options)
|
||||
|
@ -52,7 +53,22 @@ module Capybara
|
|||
|
||||
def matches_filters?(node)
|
||||
if options[:text]
|
||||
regexp = options[:text].is_a?(Regexp) ? options[:text] : Regexp.escape(options[:text].to_s)
|
||||
regexp = if options[:text].is_a?(Regexp)
|
||||
options[:text]
|
||||
else
|
||||
if exact_text === true
|
||||
"\\A#{Regexp.escape(options[:text].to_s)}\\z"
|
||||
else
|
||||
Regexp.escape(options[:text].to_s)
|
||||
end
|
||||
end
|
||||
text_visible = visible
|
||||
text_visible = :all if text_visible == :hidden
|
||||
return false if not node.text(text_visible).match(regexp)
|
||||
end
|
||||
|
||||
if exact_text.is_a?(String)
|
||||
regexp = "\\A#{Regexp.escape(options[:exact_text])}\\z"
|
||||
text_visible = visible
|
||||
text_visible = :all if text_visible == :hidden
|
||||
return false if not node.text(text_visible).match(regexp)
|
||||
|
@ -187,6 +203,10 @@ module Capybara
|
|||
warn "The :exact option only has an effect on queries using the XPath#is method. Using it with the query \"#{expression.to_s}\" has no effect."
|
||||
end
|
||||
end
|
||||
|
||||
def exact_text
|
||||
exact_text = options.fetch(:exact_text, Capybara.exact_text)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,8 +10,8 @@ module Capybara
|
|||
unless @expected_text.is_a?(Regexp)
|
||||
@expected_text = Capybara::Helpers.normalize_whitespace(@expected_text)
|
||||
end
|
||||
@search_regexp = Capybara::Helpers.to_regexp(@expected_text)
|
||||
@options ||= {}
|
||||
@search_regexp = Capybara::Helpers.to_regexp(@expected_text, nil, exact?)
|
||||
assert_valid_keys
|
||||
end
|
||||
|
||||
|
@ -33,12 +33,16 @@ module Capybara
|
|||
if @expected_text.is_a?(Regexp)
|
||||
"text matching #{@expected_text.inspect}"
|
||||
else
|
||||
"text #{@expected_text.inspect}"
|
||||
"#{"exact " if exact?}text #{@expected_text.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def exact?
|
||||
options.fetch(:exact, Capybara.exact_text)
|
||||
end
|
||||
|
||||
def build_message(report_on_invisible)
|
||||
message = String.new()
|
||||
unless (COUNT_KEYS & @options.keys).empty?
|
||||
|
@ -70,7 +74,7 @@ module Capybara
|
|||
end
|
||||
|
||||
def valid_keys
|
||||
COUNT_KEYS + [:wait]
|
||||
COUNT_KEYS + [:wait, :exact]
|
||||
end
|
||||
|
||||
def check_visible_text?
|
||||
|
|
|
@ -9,7 +9,7 @@ module Capybara
|
|||
unless @expected_title.is_a?(Regexp)
|
||||
@expected_title = Capybara::Helpers.normalize_whitespace(@expected_title)
|
||||
end
|
||||
@search_regexp = Capybara::Helpers.to_regexp(@expected_title)
|
||||
@search_regexp = Capybara::Helpers.to_regexp(@expected_title, nil, options.fetch(:exact, false))
|
||||
assert_valid_keys
|
||||
end
|
||||
|
||||
|
@ -34,7 +34,7 @@ module Capybara
|
|||
end
|
||||
|
||||
def valid_keys
|
||||
[:wait]
|
||||
[:wait, :exact]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -77,6 +77,27 @@ Capybara::SpecHelper.spec '#has_selector?' do
|
|||
expect(@session).to have_selector(:css, "p a#foo", 'extra')
|
||||
end
|
||||
end
|
||||
|
||||
context "with exact_text" do
|
||||
context "string" do
|
||||
it "should only match elements that match exactly" do
|
||||
expect(@session).to have_selector(:id, "h2one", exact_text: "Header Class Test One")
|
||||
expect(@session).to have_no_selector(:id, "h2one", exact_text: "Header Class Test")
|
||||
end
|
||||
end
|
||||
|
||||
context "boolean" do
|
||||
it "should only match elements that match exactly when true" do
|
||||
expect(@session).to have_selector(:id, "h2one", text: "Header Class Test One", exact_text: true)
|
||||
expect(@session).to have_no_selector(:id, "h2one", text: "Header Class Test", exact_text: true)
|
||||
end
|
||||
|
||||
it "should match substrings when false" do
|
||||
expect(@session).to have_selector(:id, "h2one", text: "Header Class Test One", exact_text: false)
|
||||
expect(@session).to have_selector(:id, "h2one", text: "Header Class Test", exact_text: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Capybara::SpecHelper.spec '#has_no_selector?' do
|
||||
|
|
|
@ -96,6 +96,18 @@ Capybara::SpecHelper.spec '#has_text?' do
|
|||
expect(@session).not_to have_text(/xxxxyzzz/)
|
||||
end
|
||||
|
||||
context "with exact: true option" do
|
||||
it "should be true if text matches exactly" do
|
||||
@session.visit('/with_html')
|
||||
expect(@session.find(:id, "h2one")).to have_text("Header Class Test One", exact: true)
|
||||
end
|
||||
|
||||
it "should be false if text doesn't match exactly" do
|
||||
@session.visit('/with_html')
|
||||
expect(@session.find(:id, "h2one")).not_to have_text("Header Class Test On", exact: true)
|
||||
end
|
||||
end
|
||||
|
||||
it "should escape any characters that would have special meaning in a regexp" do
|
||||
@session.visit('/with_html')
|
||||
expect(@session).not_to have_text('.orem')
|
||||
|
@ -205,7 +217,7 @@ Capybara::SpecHelper.spec '#has_text?' do
|
|||
it "should raise an error if an invalid option is passed" do
|
||||
@session.visit('/with_html')
|
||||
expect do
|
||||
expect(@session).to have_text('Lorem', exact: true)
|
||||
expect(@session).to have_text('Lorem', invalid: true)
|
||||
end.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,6 +21,21 @@ Capybara::SpecHelper.spec '#has_title?' do
|
|||
it "should be false if the page has not the given title" do
|
||||
expect(@session).not_to have_title('monkey')
|
||||
end
|
||||
|
||||
it "should default to exact: false matching" do
|
||||
expect(@session).to have_title('with_js', exact: false)
|
||||
expect(@session).to have_title('with_', exact: false)
|
||||
end
|
||||
|
||||
it "should match exactly if exact: true option passed" do
|
||||
expect(@session).to have_title('with_js', exact: true)
|
||||
expect(@session).not_to have_title('with_', exact: true)
|
||||
end
|
||||
|
||||
it "should match partial if exact: false option passed" do
|
||||
expect(@session).to have_title('with_js', exact: false)
|
||||
expect(@session).to have_title('with_', exact: false)
|
||||
end
|
||||
end
|
||||
|
||||
Capybara::SpecHelper.spec '#has_no_title?' do
|
||||
|
|
Loading…
Add table
Reference in a new issue