From f98c699a4c73340a2ee122f813c9074949785f3f Mon Sep 17 00:00:00 2001 From: Thomas Walpole Date: Mon, 5 Oct 2020 22:59:25 -0700 Subject: [PATCH] Support filter block with current_path assertions and expectations --- lib/capybara/minitest.rb | 4 ++-- lib/capybara/queries/current_path_query.rb | 18 +++++++++++++---- lib/capybara/rack_test/form.rb | 2 +- lib/capybara/rspec/matchers.rb | 4 ++-- .../rspec/matchers/have_current_path.rb | 4 ++-- lib/capybara/session/matchers.rb | 20 +++++++++---------- .../spec/session/has_current_path_spec.rb | 13 ++++++++++++ spec/minitest_spec.rb | 3 ++- 8 files changed, 46 insertions(+), 22 deletions(-) diff --git a/lib/capybara/minitest.rb b/lib/capybara/minitest.rb index 319ca887..2d768739 100644 --- a/lib/capybara/minitest.rb +++ b/lib/capybara/minitest.rb @@ -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 diff --git a/lib/capybara/queries/current_path_query.rb b/lib/capybara/queries/current_path_query.rb index 774ef16a..46097241 100644 --- a/lib/capybara/queries/current_path_query.rb +++ b/lib/capybara/queries/current_path_query.rb @@ -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}" diff --git a/lib/capybara/rack_test/form.rb b/lib/capybara/rack_test/form.rb index 5fabd7d9..763a8528 100644 --- a/lib/capybara/rack_test/form.rb +++ b/lib/capybara/rack_test/form.rb @@ -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 diff --git a/lib/capybara/rspec/matchers.rb b/lib/capybara/rspec/matchers.rb index 8be5f764..589d85d6 100644 --- a/lib/capybara/rspec/matchers.rb +++ b/lib/capybara/rspec/matchers.rb @@ -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. diff --git a/lib/capybara/rspec/matchers/have_current_path.rb b/lib/capybara/rspec/matchers/have_current_path.rb index e329fe3c..00884f77 100644 --- a/lib/capybara/rspec/matchers/have_current_path.rb +++ b/lib/capybara/rspec/matchers/have_current_path.rb @@ -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 diff --git a/lib/capybara/session/matchers.rb b/lib/capybara/session/matchers.rb index 292120cd..e367ce83 100644 --- a/lib/capybara/session/matchers.rb +++ b/lib/capybara/session/matchers.rb @@ -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 diff --git a/lib/capybara/spec/session/has_current_path_spec.rb b/lib/capybara/spec/session/has_current_path_spec.rb index 5d00d08b..f8fa28eb 100644 --- a/lib/capybara/spec/session/has_current_path_spec.rb +++ b/lib/capybara/spec/session/has_current_path_spec.rb @@ -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 diff --git a/spec/minitest_spec.rb b/spec/minitest_spec.rb index 9a361a65..eb35c539 100644 --- a/spec/minitest_spec.rb +++ b/spec/minitest_spec.rb @@ -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