diff --git a/CHANGELOG.md b/CHANGELOG.md index 4bdfe4c..661b986 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Master (Unreleased) - Handle unknown HTTP status codes for `RSpecRails/HttpStatus` cop. ([@viralpraxis]) +- Fix a false negative for `RSpecRails/TravelAround` cop when passed as a proc to a travel method. ([@ydah]) ## 2.30.0 (2024-06-12) diff --git a/docs/modules/ROOT/pages/cops_rspecrails.adoc b/docs/modules/ROOT/pages/cops_rspecrails.adoc index 8559133..07650f9 100644 --- a/docs/modules/ROOT/pages/cops_rspecrails.adoc +++ b/docs/modules/ROOT/pages/cops_rspecrails.adoc @@ -456,6 +456,11 @@ around do |example| end end +# bad +around do |example| + freeze_time(&example) +end + # good before { freeze_time } ---- diff --git a/lib/rubocop/cop/rspec_rails/travel_around.rb b/lib/rubocop/cop/rspec_rails/travel_around.rb index 0fbc6e2..ffdd1f4 100644 --- a/lib/rubocop/cop/rspec_rails/travel_around.rb +++ b/lib/rubocop/cop/rspec_rails/travel_around.rb @@ -21,8 +21,14 @@ module RSpecRails # end # end # + # # bad + # around do |example| + # freeze_time(&example) + # end + # # # good # before { freeze_time } + # class TravelAround < ::RuboCop::Cop::Base extend AutoCorrector @@ -43,6 +49,13 @@ class TravelAround < ::RuboCop::Cop::Base ) PATTERN + # @!method extract_travel_with_block_pass(node) + def_node_search :extract_travel_with_block_pass, <<~PATTERN + $(send _ TRAVEL_METHOD_NAMES + (block_pass $lvar) + ) + PATTERN + # @!method match_around_each?(node) def_node_matcher :match_around_each?, <<~PATTERN (block @@ -52,29 +65,39 @@ class TravelAround < ::RuboCop::Cop::Base PATTERN def on_block(node) - run_node = extract_run_in_travel(node) - return unless run_node + extract_run_in_travel(node) do |run_node| + run_in_travel(node, run_node) + end + extract_travel_with_block_pass(node) do |travel_node, lvar| + travel_with_block_pass(travel_node, lvar) + end + end + alias on_numblock on_block + + private + def run_in_travel(node, run_node) around_node = extract_surrounding_around_block(run_node) return unless around_node add_offense(node) do |corrector| - autocorrect(corrector, node, run_node, around_node) + corrector.replace(node, node.body.source) + corrector.insert_before(around_node, + "before { #{run_node.source} }\n\n") end end - alias on_numblock on_block - private + def travel_with_block_pass(node, lvar) + around_node = extract_surrounding_around_block(node) + return unless around_node - def autocorrect(corrector, node, run_node, around_node) - corrector.replace( - node, - node.body.source - ) - corrector.insert_before( - around_node, - "before { #{run_node.source} }\n\n" - ) + add_offense(node) do |corrector| + corrector.replace(node, "#{lvar.name}.run") + corrector.insert_before( + around_node, + "before { #{node.method_name} }\n\n" + ) + end end # @param node [RuboCop::AST::BlockNode] diff --git a/spec/rubocop/cop/rspec_rails/travel_around_spec.rb b/spec/rubocop/cop/rspec_rails/travel_around_spec.rb index 52401f3..9a1a41c 100644 --- a/spec/rubocop/cop/rspec_rails/travel_around_spec.rb +++ b/spec/rubocop/cop/rspec_rails/travel_around_spec.rb @@ -67,6 +67,35 @@ end end + context 'with `freeze_time` with `&example` in `around`' do + it 'registers offense' do + expect_offense(<<~RUBY) + around do |example| + freeze_time(&example) + ^^^^^^^^^^^^^^^^^^^^^ Prefer to travel in `before` rather than `around`. + end + RUBY + + expect_correction(<<~RUBY) + before { freeze_time } + + around do |example| + example.run + end + RUBY + end + end + + context 'with `freeze_time` with `&example` not in `around`' do + it 'registers no offense' do + expect_no_offenses(<<~RUBY) + examples.each do |example| + freeze_time(&example) + end + RUBY + end + end + context 'with `freeze_time` in `around(:each)`' do it 'registers offense' do expect_offense(<<~RUBY) @@ -113,6 +142,29 @@ end end + context 'with `freeze_time` with `&example` and another node in `around`' do + it 'registers offense' do + expect_offense(<<~RUBY) + around do |example| + foo + + freeze_time(&example) + ^^^^^^^^^^^^^^^^^^^^^ Prefer to travel in `before` rather than `around`. + end + RUBY + + expect_correction(<<~RUBY) + before { freeze_time } + + around do |example| + foo + + example.run + end + RUBY + end + end + context 'with `travel` in `around`' do it 'registers offense' do expect_offense(<<~RUBY)