diff --git a/CHANGELOG.md b/CHANGELOG.md index 849a497..7b73230 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - Fix an offense message for `Capybara/SpecificFinders`. ([@ydah]) - Expand `Capybara/NegationMatcher` to support `have_content` ([@OskarsEzerins]) +- Fix an incorrect autocorrect for `Capybara/CurrentPathExpectation` when matcher's argument is a method with a argument and no parentheses. ([@ydah]) ## 2.17.1 (2023-02-13) diff --git a/lib/rubocop/cop/capybara/current_path_expectation.rb b/lib/rubocop/cop/capybara/current_path_expectation.rb index 5ab6b39..5ac7a91 100644 --- a/lib/rubocop/cop/capybara/current_path_expectation.rb +++ b/lib/rubocop/cop/capybara/current_path_expectation.rb @@ -30,6 +30,7 @@ module Capybara # class CurrentPathExpectation < ::RuboCop::Cop::Base extend AutoCorrector + include RangeHelp MSG = 'Do not set an RSpec expectation on `current_path` in ' \ 'Capybara feature specs - instead, use the ' \ @@ -85,8 +86,7 @@ def autocorrect(corrector, node) end def rewrite_expectation(corrector, node, to_symbol, matcher_node) - current_path_node = node.first_argument - corrector.replace(current_path_node, 'page') + corrector.replace(node.first_argument, 'page') corrector.replace(node.parent.loc.selector, 'to') matcher_method = if to_symbol == :to 'have_current_path' @@ -94,6 +94,7 @@ def rewrite_expectation(corrector, node, to_symbol, matcher_node) 'have_no_current_path' end corrector.replace(matcher_node.loc.selector, matcher_method) + add_argument_parentheses(corrector, matcher_node.first_argument) add_ignore_query_options(corrector, node) end @@ -111,6 +112,20 @@ def regexp_node_to_regexp_expr(regexp_node) end end + def add_argument_parentheses(corrector, arg_node) + return unless method_call_with_no_parentheses?(arg_node) + + first_argument_range = range_with_surrounding_space( + arg_node.first_argument.source_range, side: :left + ) + corrector.insert_before(first_argument_range, '(') + corrector.insert_after(arg_node.last_argument, ')') + end + + def method_call_with_no_parentheses?(arg_node) + arg_node.send_type? && arg_node.arguments? && !arg_node.parenthesized? + end + # `have_current_path` with no options will include the querystring # while `page.current_path` does not. # This ensures the option `ignore_query: true` is added diff --git a/spec/rubocop/cop/capybara/current_path_expectation_spec.rb b/spec/rubocop/cop/capybara/current_path_expectation_spec.rb index 3eb163a..c9aac93 100644 --- a/spec/rubocop/cop/capybara/current_path_expectation_spec.rb +++ b/spec/rubocop/cop/capybara/current_path_expectation_spec.rb @@ -55,6 +55,54 @@ RUBY end + it "registers an offense when matcher's argument is a method " \ + 'with a argument and no parentheses' do + expect_offense(<<~RUBY) + expect(current_path).to eq(foo bar) + ^^^^^^ Do not set an RSpec expectation on `current_path` in Capybara feature specs - instead, use the `have_current_path` matcher on `page` + RUBY + + expect_correction(<<~RUBY) + expect(page).to have_current_path(foo( bar), ignore_query: true) + RUBY + end + + it "registers an offense when matcher's argument is a method " \ + 'with arguments and no parentheses' do + expect_offense(<<~RUBY) + expect(current_path).to eq(foo bar, baz) + ^^^^^^ Do not set an RSpec expectation on `current_path` in Capybara feature specs - instead, use the `have_current_path` matcher on `page` + RUBY + + expect_correction(<<~RUBY) + expect(page).to have_current_path(foo( bar, baz), ignore_query: true) + RUBY + end + + it "registers an offense when matcher's argument is a method " \ + 'with a argument and parentheses' do + expect_offense(<<~RUBY) + expect(current_path).to eq(foo(bar)) + ^^^^^^ Do not set an RSpec expectation on `current_path` in Capybara feature specs - instead, use the `have_current_path` matcher on `page` + RUBY + + expect_correction(<<~RUBY) + expect(page).to have_current_path(foo(bar), ignore_query: true) + RUBY + end + + it "registers an offense when matcher's argument is a method " \ + 'with arguments and parentheses' do + expect_offense(<<~RUBY) + expect(current_path).to eq(foo bar(baz)) + ^^^^^^ Do not set an RSpec expectation on `current_path` in Capybara feature specs - instead, use the `have_current_path` matcher on `page` + RUBY + + expect_correction(<<~RUBY) + expect(page).to have_current_path(foo( bar(baz)), ignore_query: true) + RUBY + end + it 'preserves parentheses' do expect_offense(<<~RUBY) expect(current_path).to eq(expected_path)