Skip to content

Commit

Permalink
Merge pull request #1822 from rubocop/fix1821
Browse files Browse the repository at this point in the history
Fix a false positive for `RSpec/RepeatedSubjectCall`
  • Loading branch information
ydah authored Mar 1, 2024
2 parents 2e1488a + e1b1076 commit 6b37836
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Master (Unreleased)

- Fix a false positive for `RSpec/RepeatedSubjectCall` when `subject.method_call`. ([@ydah])

## 2.27.0 (2024-03-01)

- Add new `RSpec/IsExpectedSpecify` cop. ([@ydah])
Expand Down
6 changes: 6 additions & 0 deletions docs/modules/ROOT/pages/cops_rspec.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4921,6 +4921,12 @@ it do
expect { my_method }.to change { A.count }
expect { my_method }.to not_change { A.count }
end
# also good
it do
expect { subject.a }.to change { A.count }
expect { subject.b }.to not_change { A.count }
end
----
=== References
Expand Down
24 changes: 14 additions & 10 deletions lib/rubocop/cop/rspec/repeated_subject_call.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ module RSpec
# expect { my_method }.to not_change { A.count }
# end
#
# # also good
# it do
# expect { subject.a }.to change { A.count }
# expect { subject.b }.to not_change { A.count }
# end
#
class RepeatedSubjectCall < Base
include TopLevelGroup

Expand Down Expand Up @@ -64,17 +70,15 @@ def on_top_level_group(node)

private

def detect_offense(example_node, subject_node)
walker = subject_node
def detect_offense(subject_node)
return if subject_node.chained?
return unless (block_node = expect_block(subject_node))

while walker.parent? && walker.parent != example_node.body
walker = walker.parent
add_offense(block_node)
end

if walker.block_type? && walker.method?(:expect)
add_offense(walker)
return
end
end
def expect_block(node)
node.each_ancestor(:block).find { |block| block.method?(:expect) }
end

def detect_offenses_in_block(node, subject_names = [])
Expand All @@ -96,7 +100,7 @@ def detect_offenses_in_example(node, subject_names)

subject_calls(node.body, Set[*subject_names, :subject]).each do |call|
if subjects_used[call.method_name]
detect_offense(node, call)
detect_offense(call)
else
subjects_used[call.method_name] = true
end
Expand Down
11 changes: 11 additions & 0 deletions spec/rubocop/cop/rspec/repeated_subject_call_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,15 @@
end
RUBY
end

it 'registers no offenses for `subject.method_call`' do
expect_no_offenses(<<~RUBY)
RSpec.describe Foo do
it do
expect { subject.a }.to change { A.count }
expect { subject.b }.to not_change { A.count }
end
end
RUBY
end
end

0 comments on commit 6b37836

Please sign in to comment.