Add `...any_of_selectors` assertions and matchers to complement `all_of`/`any_of`
This commit is contained in:
parent
1f2a028167
commit
c2e11c8a00
|
@ -5,6 +5,7 @@ Release date: unreleased
|
|||
|
||||
* :class filter can now check for class names starting with !
|
||||
* Selector `xpath`/`css` expression definitions will get filter names from block parameters if not explicitly provided
|
||||
* `any_of_selectors` assertions and matchers to complement `all_of_selectors` and `none_of_selectors`
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ module Capybara
|
|||
# see {Capybara::Node::Matchers#assert_style}
|
||||
|
||||
%w[assert_selector assert_no_selector
|
||||
assert_all_of_selectors assert_none_of_selectors
|
||||
assert_all_of_selectors assert_none_of_selectors assert_any_of_selectors
|
||||
assert_matches_selector assert_not_matches_selector
|
||||
assert_style].each do |assertion_name|
|
||||
class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
|
||||
|
|
|
@ -16,6 +16,7 @@ module Capybara
|
|||
%W[refute_#{assertion} wont_have_#{assertion}]]
|
||||
end + [%w[assert_all_of_selectors must_have_all_of_selectors],
|
||||
%w[assert_none_of_selectors must_have_none_of_selectors],
|
||||
%w[assert_any_of_selectors must_have_any_of_selectors],
|
||||
%w[assert_style must_have_style]] +
|
||||
%w[selector xpath css].flat_map do |assertion|
|
||||
[%W[assert_matches_#{assertion} must_match_#{assertion}],
|
||||
|
|
|
@ -166,6 +166,38 @@ module Capybara
|
|||
end
|
||||
end
|
||||
|
||||
# Asserts that any of the provided selectors are present on the given page
|
||||
# or descendants of the current node. If options are provided, the assertion
|
||||
# will check that each locator is present with those options as well (other than :wait).
|
||||
#
|
||||
# page.assert_any_of_selectors(:custom, 'Tom', 'Joe', visible: all)
|
||||
# page.assert_any_of_selectors(:css, '#my_div', 'a.not_clicked')
|
||||
#
|
||||
# It accepts all options that {Capybara::Node::Finders#all} accepts,
|
||||
# such as :text and :visible.
|
||||
#
|
||||
# The :wait option applies to all of the selectors as a group, so any of the locators must be present
|
||||
# within :wait (Defaults to Capybara.default_max_wait_time) seconds.
|
||||
#
|
||||
# @overload assert_any_of_selectors([kind = Capybara.default_selector], *locators, **options)
|
||||
#
|
||||
def assert_any_of_selectors(*args, wait: nil, **options, &optional_filter_block)
|
||||
wait = session_options.default_max_wait_time if wait.nil?
|
||||
selector = extract_selector(args)
|
||||
synchronize(wait) do
|
||||
res = args.map do |locator|
|
||||
begin
|
||||
assert_selector(selector, locator, options, &optional_filter_block)
|
||||
break nil
|
||||
rescue Capybara::ExpectationNotMet => e
|
||||
e.message
|
||||
end
|
||||
end
|
||||
raise Capybara::ExpectationNotMet, res.join(' or ') if res
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
#
|
||||
# Asserts that a given selector is not on the page or a descendant of the current node.
|
||||
|
|
|
@ -108,6 +108,20 @@ module Capybara
|
|||
end
|
||||
end
|
||||
|
||||
class HaveAnySelectors < WrappedElementMatcher
|
||||
def element_matches?(el)
|
||||
el.assert_any_of_selectors(*@args, &@filter_block)
|
||||
end
|
||||
|
||||
def does_not_match?(_actual)
|
||||
el.assert_none_of_selectors(*@args, &@filter_block)
|
||||
end
|
||||
|
||||
def description
|
||||
'have any selectors'
|
||||
end
|
||||
end
|
||||
|
||||
class MatchSelector < HaveSelector
|
||||
def element_matches?(el)
|
||||
el.assert_matches_selector(*@args, &@filter_block)
|
||||
|
@ -277,6 +291,12 @@ module Capybara
|
|||
HaveNoSelectors.new(*args, &optional_filter_block)
|
||||
end
|
||||
|
||||
# RSpec matcher for whether the element(s) matching any of a group of selectors exist
|
||||
# See {Capybara::Node::Matcher#assert_any_of_selectors}
|
||||
def have_any_of_selectors(*args, &optional_filter_block)
|
||||
HaveAnySelectors.new(*args, &optional_filter_block)
|
||||
end
|
||||
|
||||
# RSpec matcher for whether the current element matches a given selector
|
||||
# See {Capybara::Node::Matchers#assert_matches_selector}
|
||||
def match_selector(*args, &optional_filter_block)
|
||||
|
|
|
@ -49,7 +49,7 @@ module Capybara
|
|||
has_no_table? has_table? unselect has_select? has_no_select?
|
||||
has_selector? has_no_selector? click_on has_no_checked_field?
|
||||
has_no_unchecked_field? query assert_selector assert_no_selector
|
||||
assert_all_of_selectors assert_none_of_selectors
|
||||
assert_all_of_selectors assert_none_of_selectors assert_any_of_selectors
|
||||
refute_selector assert_text assert_no_text
|
||||
].freeze
|
||||
# @api private
|
||||
|
|
|
@ -113,3 +113,28 @@ Capybara::SpecHelper.spec '#assert_none_of_selectors' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
Capybara::SpecHelper.spec '#assert_any_of_selectors' do
|
||||
before do
|
||||
@session.visit('/with_html')
|
||||
end
|
||||
|
||||
it 'should be true if any of the given selectors are on the page' do
|
||||
@session.assert_any_of_selectors(:css, 'a#foo', 'h2#h2three')
|
||||
@session.assert_any_of_selectors(:css, 'h2#h2three', 'a#foo')
|
||||
end
|
||||
|
||||
it 'should be false if none of the given selectors are on the page' do
|
||||
expect { @session.assert_any_of_selectors(:css, 'h2#h2three', 'h4#h4four') }.to raise_error(Capybara::ElementNotFound)
|
||||
end
|
||||
|
||||
it 'should use default selector' do
|
||||
Capybara.default_selector = :css
|
||||
expect { @session.assert_any_of_selectors('h2#h2three', 'h5#h5five') }.to raise_error(Capybara::ElementNotFound)
|
||||
@session.assert_any_of_selectors('p a#foo', 'h2#h2two', 'h2#h2one')
|
||||
end
|
||||
|
||||
it 'should support filter block' do
|
||||
expect { @session.assert_any_of_selectors(:css, 'h2#h2one', 'h2#h2two') { |_n| false } }.to raise_error(Capybara::ElementNotFound, /custom filter block/)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Capybara::SpecHelper.spec '#have_all_selectors' do
|
||||
Capybara::SpecHelper.spec '#have_all_of_selectors' do
|
||||
before do
|
||||
@session.visit('/with_html')
|
||||
end
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
Capybara::SpecHelper.spec '#have_any_of_selectors' do
|
||||
before do
|
||||
@session.visit('/with_html')
|
||||
end
|
||||
|
||||
it 'should be true if any of the given selectors are on the page' do
|
||||
expect(@session).to have_any_of_selectors(:css, 'p a#foo', 'h2#blah', 'h2#h2two')
|
||||
end
|
||||
|
||||
it 'should be false if none of the given selectors are not on the page' do
|
||||
expect do
|
||||
expect(@session).to have_any_of_selectors(:css, 'span a#foo', 'h2#h2nope', 'h2#h2one_no')
|
||||
end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
|
||||
end
|
||||
|
||||
it 'should use default selector' do
|
||||
Capybara.default_selector = :css
|
||||
expect(@session).to have_any_of_selectors('p a#foo', 'h2#h2two', 'a#not_on_page')
|
||||
expect do
|
||||
expect(@session).to have_any_of_selectors('p a#blah', 'h2#h2three')
|
||||
end.to raise_error ::RSpec::Expectations::ExpectationNotMetError
|
||||
end
|
||||
end
|
|
@ -105,6 +105,10 @@ class MinitestTest < Minitest::Test
|
|||
assert_none_of_selectors(:css, 'input#not_on_page', 'input#also_not_on_page')
|
||||
end
|
||||
|
||||
def test_assert_any_of_selectors
|
||||
assert_any_of_selectors(:css, 'input#not_on_page', 'select#form_other_title')
|
||||
end
|
||||
|
||||
def test_assert_matches_selector
|
||||
assert_matches_selector(find(:field, 'customer_email'), :field, 'customer_email')
|
||||
assert_not_matches_selector(find(:select, 'form_title'), :field, 'customer_email')
|
||||
|
@ -144,6 +148,6 @@ RSpec.describe 'capybara/minitest' do
|
|||
reporter.start
|
||||
MinitestTest.run reporter, {}
|
||||
reporter.report
|
||||
expect(output.string).to include('19 runs, 49 assertions, 0 failures, 0 errors, 1 skips')
|
||||
expect(output.string).to include('20 runs, 50 assertions, 0 failures, 0 errors, 1 skips')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -98,6 +98,10 @@ class MinitestSpecTest < Minitest::Spec
|
|||
page.must_have_none_of_selectors(:css, 'input#not_on_page', 'input#also_not_on_page')
|
||||
end
|
||||
|
||||
it 'supports any_of_selectors expectations' do
|
||||
page.must_have_any_of_selectors(:css, 'select#form_other_title', 'input#not_on_page')
|
||||
end
|
||||
|
||||
it 'supports match_selector expectations' do
|
||||
find(:field, 'customer_email').must_match_selector(:field, 'customer_email')
|
||||
find(:select, 'form_title').wont_match_selector(:field, 'customer_email')
|
||||
|
@ -140,7 +144,7 @@ RSpec.describe 'capybara/minitest/spec' do
|
|||
reporter.start
|
||||
MinitestSpecTest.run reporter, {}
|
||||
reporter.report
|
||||
expect(output.string).to include('19 runs, 41 assertions, 1 failures, 0 errors, 1 skips')
|
||||
expect(output.string).to include('20 runs, 42 assertions, 1 failures, 0 errors, 1 skips')
|
||||
# Make sure error messages are displayed
|
||||
expect(output.string).to include('expected to find select box "non_existing_form_title" but there were no matches')
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue