Support filter block with current_path assertions and expectations

This commit is contained in:
Thomas Walpole 2020-10-05 22:59:25 -07:00
parent f43b6499ec
commit f98c699a4c
8 changed files with 46 additions and 22 deletions

View File

@ -50,10 +50,10 @@ module Capybara
%w[text no_text title no_title current_path no_current_path].each do |assertion_name|
class_eval <<-ASSERTION, __FILE__, __LINE__ + 1
def assert_#{assertion_name}(*args, **kwargs)
def assert_#{assertion_name}(*args, **kwargs, &optional_filter_block)
self.assertions +=1
subject, args = determine_subject(args)
subject.assert_#{assertion_name}(*args, **kwargs)
subject.assert_#{assertion_name}(*args, **kwargs, &optional_filter_block)
rescue Capybara::ExpectationNotMet => e
raise ::Minitest::Assertion, e.message
end

View File

@ -6,26 +6,30 @@ module Capybara
# @api private
module Queries
class CurrentPathQuery < BaseQuery
def initialize(expected_path, **options)
def initialize(expected_path, **options, &optional_filter_block)
super(options)
@expected_path = expected_path
@options = {
url: !@expected_path.is_a?(Regexp) && !::Addressable::URI.parse(@expected_path || '').hostname.nil?,
ignore_query: false
}.merge(options)
@filter_block = optional_filter_block
assert_valid_keys
end
def resolves_for?(session)
uri = ::Addressable::URI.parse(session.current_url)
uri&.query = nil if options[:ignore_query]
@actual_path = options[:url] ? uri&.to_s : uri&.request_uri
@actual_path = (options[:ignore_query] ? uri&.omit(:query) : uri).yield_self do |u|
options[:url] ? u&.to_s : u&.request_uri
end
if @expected_path.is_a? Regexp
res = if @expected_path.is_a? Regexp
@actual_path.to_s.match?(@expected_path)
else
::Addressable::URI.parse(@expected_path) == ::Addressable::URI.parse(@actual_path)
end
res && matches_filter_block?(uri)
end
def failure_message
@ -38,6 +42,12 @@ module Capybara
private
def matches_filter_block?(url)
return true unless @filter_block
@filter_block.call(url)
end
def failure_message_helper(negated = '')
verb = @expected_path.is_a?(Regexp) ? 'match' : 'equal'
"expected #{@actual_path.inspect}#{negated} to #{verb} #{@expected_path.inspect}"

View File

@ -6,7 +6,7 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
# That check should be based solely on the form element's 'enctype' attribute value,
# which should probably be provided to Rack::Test in its non-GET request methods.
class NilUploadedFile < Rack::Test::UploadedFile
def initialize # rubocop:disable Lint/MissingSuper
def initialize
@empty_file = Tempfile.new('nil_uploaded_file')
@empty_file.close
end

View File

@ -139,8 +139,8 @@ module Capybara
# RSpec matcher for the current path.
#
# @see Capybara::SessionMatchers#assert_current_path
def have_current_path(path, **options)
Matchers::HaveCurrentPath.new(path, **options)
def have_current_path(path, **options, &optional_filter_block)
Matchers::HaveCurrentPath.new(path, **options, &optional_filter_block)
end
# RSpec matcher for element style.

View File

@ -7,11 +7,11 @@ module Capybara
module Matchers
class HaveCurrentPath < WrappedElementMatcher
def element_matches?(el)
el.assert_current_path(current_path, **@kw_args)
el.assert_current_path(current_path, **@kw_args, &@filter_block)
end
def element_does_not_match?(el)
el.assert_no_current_path(current_path, **@kw_args)
el.assert_no_current_path(current_path, **@kw_args, &@filter_block)
end
def description

View File

@ -19,8 +19,8 @@ module Capybara
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
# @return [true]
#
def assert_current_path(path, **options)
_verify_current_path(path, **options) do |query|
def assert_current_path(path, **options, &optional_filter_block)
_verify_current_path(path, optional_filter_block, **options) do |query|
raise Capybara::ExpectationNotMet, query.failure_message unless query.resolves_for?(self)
end
end
@ -35,8 +35,8 @@ module Capybara
# @raise [Capybara::ExpectationNotMet] if the assertion hasn't succeeded during wait time
# @return [true]
#
def assert_no_current_path(path, **options)
_verify_current_path(path, **options) do |query|
def assert_no_current_path(path, **options, &optional_filter_block)
_verify_current_path(path, optional_filter_block, **options) do |query|
raise Capybara::ExpectationNotMet, query.negative_failure_message if query.resolves_for?(self)
end
end
@ -50,8 +50,8 @@ module Capybara
# @macro current_path_query_params
# @return [Boolean]
#
def has_current_path?(path, **options)
make_predicate(options) { assert_current_path(path, **options) }
def has_current_path?(path, **options, &optional_filter_block)
make_predicate(options) { assert_current_path(path, **options, &optional_filter_block) }
end
##
@ -63,14 +63,14 @@ module Capybara
# @macro current_path_query_params
# @return [Boolean]
#
def has_no_current_path?(path, **options)
make_predicate(options) { assert_no_current_path(path, **options) }
def has_no_current_path?(path, **options, &optional_filter_block)
make_predicate(options) { assert_no_current_path(path, **options, &optional_filter_block) }
end
private
def _verify_current_path(path, **options)
query = Capybara::Queries::CurrentPathQuery.new(path, **options)
def _verify_current_path(path, filter_block, **options)
query = Capybara::Queries::CurrentPathQuery.new(path, **options, &filter_block)
document.synchronize(query.wait) do
yield(query)
end

View File

@ -94,6 +94,13 @@ Capybara::SpecHelper.spec '#has_current_path?' do
expect(@session).to have_current_path(nil, ignore_query: true)
end.not_to raise_exception
end
it 'should accept a filter block that receives Addressable::URL' do
@session.visit('/with_js?a=3&b=defgh')
expect(@session).to have_current_path('/with_js', ignore_query: true) { |url|
url.query_values.keys == ['a','b']
}
end
end
Capybara::SpecHelper.spec '#has_no_current_path?' do
@ -135,4 +142,10 @@ Capybara::SpecHelper.spec '#has_no_current_path?' do
expect(@session).not_to have_current_path('/with_js', ignore_query: true)
end.not_to raise_exception
end
it 'should accept a filter block that receives Addressable::URL' do
expect(@session).to have_no_current_path('/with_js', ignore_query: true) { |url|
!url.query.nil?
}
end
end

View File

@ -30,6 +30,7 @@ class MinitestTest < Minitest::Test
def test_assert_current_path
assert_current_path('/form')
assert_current_path('/form') { |url| url.query.nil? }
assert_no_current_path('/not_form')
refute_current_path('/not_form')
end
@ -158,6 +159,6 @@ RSpec.describe 'capybara/minitest' do
reporter.start
MinitestTest.run reporter, {}
reporter.report
expect(output.string).to include('22 runs, 52 assertions, 0 failures, 0 errors, 1 skips')
expect(output.string).to include('22 runs, 53 assertions, 0 failures, 0 errors, 1 skips')
end
end