rubocop-rspec 1.40.0 → 1.43.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/CODE_OF_CONDUCT.md +17 -0
  4. data/config/default.yml +12 -2
  5. data/lib/rubocop-rspec.rb +3 -1
  6. data/lib/rubocop/cop/rspec/align_left_let_brace.rb +12 -19
  7. data/lib/rubocop/cop/rspec/align_right_let_brace.rb +12 -19
  8. data/lib/rubocop/cop/rspec/any_instance.rb +1 -1
  9. data/lib/rubocop/cop/rspec/around_block.rb +1 -1
  10. data/lib/rubocop/cop/rspec/base.rb +74 -0
  11. data/lib/rubocop/cop/rspec/be.rb +2 -2
  12. data/lib/rubocop/cop/rspec/be_eql.rb +6 -6
  13. data/lib/rubocop/cop/rspec/before_after_all.rb +1 -1
  14. data/lib/rubocop/cop/rspec/capybara/current_path_expectation.rb +19 -17
  15. data/lib/rubocop/cop/rspec/capybara/feature_methods.rb +14 -12
  16. data/lib/rubocop/cop/rspec/capybara/visibility_matcher.rb +1 -1
  17. data/lib/rubocop/cop/rspec/context_method.rb +7 -9
  18. data/lib/rubocop/cop/rspec/context_wording.rb +3 -3
  19. data/lib/rubocop/cop/rspec/cop.rb +2 -66
  20. data/lib/rubocop/cop/rspec/describe_class.rb +20 -27
  21. data/lib/rubocop/cop/rspec/describe_method.rb +14 -6
  22. data/lib/rubocop/cop/rspec/describe_symbol.rb +2 -2
  23. data/lib/rubocop/cop/rspec/described_class.rb +12 -9
  24. data/lib/rubocop/cop/rspec/described_class_module_wrapping.rb +1 -1
  25. data/lib/rubocop/cop/rspec/dialect.rb +5 -12
  26. data/lib/rubocop/cop/rspec/empty_example_group.rb +91 -7
  27. data/lib/rubocop/cop/rspec/empty_hook.rb +6 -10
  28. data/lib/rubocop/cop/rspec/empty_line_after_example.rb +5 -7
  29. data/lib/rubocop/cop/rspec/empty_line_after_example_group.rb +5 -9
  30. data/lib/rubocop/cop/rspec/empty_line_after_final_let.rb +8 -8
  31. data/lib/rubocop/cop/rspec/empty_line_after_hook.rb +5 -9
  32. data/lib/rubocop/cop/rspec/empty_line_after_subject.rb +6 -6
  33. data/lib/rubocop/cop/rspec/example_length.rb +1 -1
  34. data/lib/rubocop/cop/rspec/example_without_description.rb +1 -1
  35. data/lib/rubocop/cop/rspec/example_wording.rb +10 -11
  36. data/lib/rubocop/cop/rspec/expect_actual.rb +8 -11
  37. data/lib/rubocop/cop/rspec/expect_change.rb +10 -35
  38. data/lib/rubocop/cop/rspec/expect_in_hook.rb +3 -3
  39. data/lib/rubocop/cop/rspec/expect_output.rb +2 -2
  40. data/lib/rubocop/cop/rspec/factory_bot/attribute_defined_statically.rb +24 -21
  41. data/lib/rubocop/cop/rspec/factory_bot/create_list.rb +20 -22
  42. data/lib/rubocop/cop/rspec/factory_bot/factory_class_name.rb +7 -8
  43. data/lib/rubocop/cop/rspec/file_path.rb +25 -17
  44. data/lib/rubocop/cop/rspec/focus.rb +7 -11
  45. data/lib/rubocop/cop/rspec/hook_argument.rb +16 -23
  46. data/lib/rubocop/cop/rspec/hooks_before_examples.rb +13 -14
  47. data/lib/rubocop/cop/rspec/implicit_block_expectation.rb +1 -1
  48. data/lib/rubocop/cop/rspec/implicit_expect.rb +7 -15
  49. data/lib/rubocop/cop/rspec/implicit_subject.rb +16 -11
  50. data/lib/rubocop/cop/rspec/instance_spy.rb +18 -12
  51. data/lib/rubocop/cop/rspec/instance_variable.rb +4 -8
  52. data/lib/rubocop/cop/rspec/invalid_predicate_matcher.rb +3 -6
  53. data/lib/rubocop/cop/rspec/it_behaves_like.rb +5 -6
  54. data/lib/rubocop/cop/rspec/iterated_expectation.rb +1 -1
  55. data/lib/rubocop/cop/rspec/leading_subject.rb +27 -20
  56. data/lib/rubocop/cop/rspec/leaky_constant_declaration.rb +2 -5
  57. data/lib/rubocop/cop/rspec/let_before_examples.rb +13 -11
  58. data/lib/rubocop/cop/rspec/let_setup.rb +21 -6
  59. data/lib/rubocop/cop/rspec/message_chain.rb +7 -6
  60. data/lib/rubocop/cop/rspec/message_expectation.rb +2 -2
  61. data/lib/rubocop/cop/rspec/message_spies.rb +2 -3
  62. data/lib/rubocop/cop/rspec/missing_example_group_argument.rb +1 -1
  63. data/lib/rubocop/cop/rspec/multiple_describes.rb +11 -8
  64. data/lib/rubocop/cop/rspec/multiple_expectations.rb +7 -11
  65. data/lib/rubocop/cop/rspec/multiple_memoized_helpers.rb +148 -0
  66. data/lib/rubocop/cop/rspec/multiple_subjects.rb +18 -19
  67. data/lib/rubocop/cop/rspec/named_subject.rb +2 -2
  68. data/lib/rubocop/cop/rspec/nested_groups.rb +12 -13
  69. data/lib/rubocop/cop/rspec/not_to_not.rb +5 -6
  70. data/lib/rubocop/cop/rspec/overwriting_setup.rb +1 -1
  71. data/lib/rubocop/cop/rspec/pending.rb +1 -1
  72. data/lib/rubocop/cop/rspec/predicate_matcher.rb +32 -69
  73. data/lib/rubocop/cop/rspec/rails/http_status.rb +5 -9
  74. data/lib/rubocop/cop/rspec/receive_counts.rb +15 -17
  75. data/lib/rubocop/cop/rspec/receive_never.rb +12 -12
  76. data/lib/rubocop/cop/rspec/repeated_description.rb +1 -1
  77. data/lib/rubocop/cop/rspec/repeated_example.rb +2 -2
  78. data/lib/rubocop/cop/rspec/repeated_example_group_body.rb +1 -1
  79. data/lib/rubocop/cop/rspec/repeated_example_group_description.rb +1 -1
  80. data/lib/rubocop/cop/rspec/return_from_stub.rb +12 -22
  81. data/lib/rubocop/cop/rspec/scattered_let.rb +8 -11
  82. data/lib/rubocop/cop/rspec/scattered_setup.rb +1 -1
  83. data/lib/rubocop/cop/rspec/shared_context.rb +8 -21
  84. data/lib/rubocop/cop/rspec/shared_examples.rb +6 -9
  85. data/lib/rubocop/cop/rspec/single_argument_message_chain.rb +15 -18
  86. data/lib/rubocop/cop/rspec/subject_stub.rb +5 -11
  87. data/lib/rubocop/cop/rspec/unspecified_exception.rb +1 -1
  88. data/lib/rubocop/cop/rspec/variable_definition.rb +6 -6
  89. data/lib/rubocop/cop/rspec/variable_name.rb +28 -9
  90. data/lib/rubocop/cop/rspec/verified_doubles.rb +1 -1
  91. data/lib/rubocop/cop/rspec/void_expect.rb +1 -1
  92. data/lib/rubocop/cop/rspec/yield.rb +14 -11
  93. data/lib/rubocop/cop/rspec_cops.rb +1 -0
  94. data/lib/rubocop/rspec/corrector/move_node.rb +7 -5
  95. data/lib/rubocop/rspec/description_extractor.rb +1 -1
  96. data/lib/rubocop/rspec/{blank_line_separation.rb → empty_line_separation.rb} +13 -10
  97. data/lib/rubocop/rspec/example_group.rb +21 -49
  98. data/lib/rubocop/rspec/factory_bot.rb +7 -1
  99. data/lib/rubocop/rspec/language.rb +6 -4
  100. data/lib/rubocop/rspec/language/node_pattern.rb +10 -1
  101. data/lib/rubocop/rspec/top_level_describe.rb +2 -2
  102. data/lib/rubocop/rspec/top_level_group.rb +57 -0
  103. data/lib/rubocop/rspec/variable.rb +1 -1
  104. data/lib/rubocop/rspec/version.rb +1 -1
  105. metadata +29 -11
@@ -18,7 +18,9 @@ module RuboCop
18
18
  # expect(foo).to have_received(:bar)
19
19
  # end
20
20
  #
21
- class InstanceSpy < Cop
21
+ class InstanceSpy < Base
22
+ extend AutoCorrector
23
+
22
24
  MSG = 'Use `instance_spy` when you check your double '\
23
25
  'with `have_received`.'
24
26
 
@@ -43,22 +45,26 @@ module RuboCop
43
45
 
44
46
  null_double(node) do |var, receiver|
45
47
  have_received_usage(node) do |expected|
46
- add_offense(receiver) if expected == var
48
+ next if expected != var
49
+
50
+ add_offense(receiver) do |corrector|
51
+ autocorrect(corrector, receiver)
52
+ end
47
53
  end
48
54
  end
49
55
  end
50
56
 
51
- def autocorrect(node)
52
- lambda do |corrector|
53
- replacement = 'instance_spy'
54
- corrector.replace(node.loc.selector, replacement)
57
+ private
55
58
 
56
- double_source_map = node.parent.loc
57
- as_null_object_range = double_source_map
58
- .dot
59
- .join(double_source_map.selector)
60
- corrector.remove(as_null_object_range)
61
- end
59
+ def autocorrect(corrector, node)
60
+ replacement = 'instance_spy'
61
+ corrector.replace(node.loc.selector, replacement)
62
+
63
+ double_source_map = node.parent.loc
64
+ as_null_object_range = double_source_map
65
+ .dot
66
+ .join(double_source_map.selector)
67
+ corrector.remove(as_null_object_range)
62
68
  end
63
69
  end
64
70
  end
@@ -46,14 +46,12 @@ module RuboCop
46
46
  # it { expect(foo).to be_empty }
47
47
  # end
48
48
  #
49
- class InstanceVariable < Cop
49
+ class InstanceVariable < Base
50
+ include RuboCop::RSpec::TopLevelGroup
51
+
50
52
  MSG = 'Avoid instance variables – use let, ' \
51
53
  'a method call, or a local variable (if possible).'
52
54
 
53
- EXAMPLE_GROUP_METHODS = ExampleGroups::ALL + SharedGroups::ALL
54
-
55
- def_node_matcher :spec_group?, EXAMPLE_GROUP_METHODS.block_pattern
56
-
57
55
  def_node_matcher :dynamic_class?, <<-PATTERN
58
56
  (block (send (const nil? :Class) :new ...) ...)
59
57
  PATTERN
@@ -69,9 +67,7 @@ module RuboCop
69
67
 
70
68
  def_node_search :ivar_assigned?, '(ivasgn % ...)'
71
69
 
72
- def on_block(node)
73
- return unless spec_group?(node)
74
-
70
+ def on_top_level_group(node)
75
71
  ivar_usage(node) do |ivar, name|
76
72
  next if valid_usage?(ivar)
77
73
  next if assignment_only? && !ivar_assigned?(node, name)
@@ -15,7 +15,7 @@ module RuboCop
15
15
  #
16
16
  # # good
17
17
  # expect(foo).to be_something
18
- class InvalidPredicateMatcher < Cop
18
+ class InvalidPredicateMatcher < Base
19
19
  MSG = 'Omit `?` from `%<matcher>s`.'
20
20
 
21
21
  def_node_matcher :invalid_predicate_matcher?, <<-PATTERN
@@ -24,7 +24,8 @@ module RuboCop
24
24
 
25
25
  def on_send(node)
26
26
  invalid_predicate_matcher?(node) do |predicate|
27
- add_offense(predicate)
27
+ add_offense(predicate,
28
+ message: format(MSG, matcher: predicate.method_name))
28
29
  end
29
30
  end
30
31
 
@@ -34,10 +35,6 @@ module RuboCop
34
35
  name = name.to_s
35
36
  name.start_with?('be_', 'have_') && name.end_with?('?')
36
37
  end
37
-
38
- def message(predicate)
39
- format(MSG, matcher: predicate.method_name)
40
- end
41
38
  end
42
39
  end
43
40
  end
@@ -18,7 +18,8 @@ module RuboCop
18
18
  #
19
19
  # # good
20
20
  # it_should_behave_like 'a foo'
21
- class ItBehavesLike < Cop
21
+ class ItBehavesLike < Base
22
+ extend AutoCorrector
22
23
  include ConfigurableEnforcedStyle
23
24
 
24
25
  MSG = 'Prefer `%<replacement>s` over `%<original>s` when including '\
@@ -28,14 +29,12 @@ module RuboCop
28
29
 
29
30
  def on_send(node)
30
31
  example_inclusion_offense(node, alternative_style) do
31
- add_offense(node)
32
+ add_offense(node) do |corrector|
33
+ corrector.replace(node.loc.selector, style.to_s)
34
+ end
32
35
  end
33
36
  end
34
37
 
35
- def autocorrect(node)
36
- ->(corrector) { corrector.replace(node.loc.selector, style.to_s) }
37
- end
38
-
39
38
  private
40
39
 
41
40
  def message(_node)
@@ -15,7 +15,7 @@ module RuboCop
15
15
  # it 'validates users' do
16
16
  # expect([user1, user2, user3]).to all(be_valid)
17
17
  # end
18
- class IteratedExpectation < Cop
18
+ class IteratedExpectation < Base
19
19
  MSG = 'Prefer using the `all` matcher instead ' \
20
20
  'of iterating over an array.'
21
21
 
@@ -31,7 +31,9 @@ module RuboCop
31
31
  # it { expect_something }
32
32
  # it { expect_something_else }
33
33
  #
34
- class LeadingSubject < Cop
34
+ class LeadingSubject < Base
35
+ extend AutoCorrector
36
+
35
37
  MSG = 'Declare `subject` above any other `%<offending>s` declarations.'
36
38
 
37
39
  def on_block(node)
@@ -41,35 +43,40 @@ module RuboCop
41
43
  end
42
44
 
43
45
  def check_previous_nodes(node)
44
- node.parent.each_child_node do |sibling|
45
- if offending?(sibling)
46
- add_offense(
47
- node,
48
- message: format(MSG, offending: sibling.method_name)
49
- )
46
+ offending_node(node) do |offender|
47
+ msg = format(MSG, offending: offender.method_name)
48
+ add_offense(node, message: msg) do |corrector|
49
+ autocorrect(corrector, node, offender)
50
50
  end
51
-
52
- break if offending?(sibling) || sibling.equal?(node)
53
51
  end
54
52
  end
55
53
 
56
- def autocorrect(node)
57
- lambda do |corrector|
58
- first_node = find_first_offending_node(node)
59
- RuboCop::RSpec::Corrector::MoveNode.new(
60
- node, corrector, processed_source
61
- ).move_before(first_node)
54
+ private
55
+
56
+ def offending_node(node)
57
+ parent(node).each_child_node.find do |sibling|
58
+ break if sibling.equal?(node)
59
+
60
+ yield sibling if offending?(sibling)
62
61
  end
63
62
  end
64
63
 
65
- private
64
+ def parent(node)
65
+ node.each_ancestor(:block).first.body
66
+ end
66
67
 
67
- def offending?(node)
68
- let?(node) || hook?(node) || example?(node)
68
+ def autocorrect(corrector, node, sibling)
69
+ RuboCop::RSpec::Corrector::MoveNode.new(
70
+ node, corrector, processed_source
71
+ ).move_before(sibling)
69
72
  end
70
73
 
71
- def find_first_offending_node(node)
72
- node.parent.children.find { |sibling| offending?(sibling) }
74
+ def offending?(node)
75
+ let?(node) ||
76
+ hook?(node) ||
77
+ example?(node) ||
78
+ spec_group?(node) ||
79
+ include?(node)
73
80
  end
74
81
 
75
82
  def in_spec_block?(node)
@@ -93,7 +93,7 @@ module RuboCop
93
93
  # stub_const('SomeModule::SomeClass', foo_class)
94
94
  # end
95
95
  # end
96
- class LeakyConstantDeclaration < Cop
96
+ class LeakyConstantDeclaration < Base
97
97
  MSG_CONST = 'Stub constant instead of declaring explicitly.'
98
98
  MSG_CLASS = 'Stub class constant instead of declaring explicitly.'
99
99
  MSG_MODULE = 'Stub module constant instead of declaring explicitly.'
@@ -119,11 +119,8 @@ module RuboCop
119
119
  private
120
120
 
121
121
  def inside_describe_block?(node)
122
- node.each_ancestor(:block).any?(&method(:in_example_or_shared_group?))
122
+ node.each_ancestor(:block).any?(&method(:spec_group?))
123
123
  end
124
-
125
- def_node_matcher :in_example_or_shared_group?,
126
- (ExampleGroups::ALL + SharedGroups::ALL).block_pattern
127
124
  end
128
125
  end
129
126
  end
@@ -30,7 +30,9 @@ module RuboCop
30
30
  # it 'checks what some does' do
31
31
  # expect(some).to be
32
32
  # end
33
- class LetBeforeExamples < Cop
33
+ class LetBeforeExamples < Base
34
+ extend AutoCorrector
35
+
34
36
  MSG = 'Move `let` before the examples in the group.'
35
37
 
36
38
  def_node_matcher :example_or_group?, <<-PATTERN
@@ -46,15 +48,6 @@ module RuboCop
46
48
  check_let_declarations(node.body) if multiline_block?(node.body)
47
49
  end
48
50
 
49
- def autocorrect(node)
50
- lambda do |corrector|
51
- first_example = find_first_example(node.parent)
52
- RuboCop::RSpec::Corrector::MoveNode.new(
53
- node, corrector, processed_source
54
- ).move_before(first_example)
55
- end
56
- end
57
-
58
51
  private
59
52
 
60
53
  def multiline_block?(block)
@@ -67,14 +60,23 @@ module RuboCop
67
60
 
68
61
  node.each_child_node do |child|
69
62
  next if child.sibling_index < first_example.sibling_index
63
+ next unless let?(child)
70
64
 
71
- add_offense(child) if let?(child)
65
+ add_offense(child) do |corrector|
66
+ autocorrect(corrector, child, first_example)
67
+ end
72
68
  end
73
69
  end
74
70
 
75
71
  def find_first_example(node)
76
72
  node.children.find { |sibling| example_or_group?(sibling) }
77
73
  end
74
+
75
+ def autocorrect(corrector, node, first_example)
76
+ RuboCop::RSpec::Corrector::MoveNode.new(
77
+ node, corrector, processed_source
78
+ ).move_before(first_example)
79
+ end
78
80
  end
79
81
  end
80
82
  end
@@ -25,17 +25,26 @@ module RuboCop
25
25
  # it 'counts widgets' do
26
26
  # expect(Widget.count).to eq(1)
27
27
  # end
28
- class LetSetup < Cop
28
+ class LetSetup < Base
29
29
  MSG = 'Do not use `let!` to setup objects not referenced in tests.'
30
30
 
31
- def_node_search :let_bang, <<-PATTERN
32
- (block $(send nil? :let! (sym $_)) args ...)
31
+ def_node_matcher :example_or_shared_group_or_including?,
32
+ (
33
+ ExampleGroups::ALL + SharedGroups::ALL +
34
+ Includes::ALL
35
+ ).block_pattern
36
+
37
+ def_node_matcher :let_bang, <<-PATTERN
38
+ {
39
+ (block $(send nil? :let! {(sym $_) (str $_)}) ...)
40
+ $(send nil? :let! {(sym $_) (str $_)} block_pass)
41
+ }
33
42
  PATTERN
34
43
 
35
44
  def_node_search :method_called?, '(send nil? %)'
36
45
 
37
46
  def on_block(node)
38
- return unless example_group?(node)
47
+ return unless example_or_shared_group_or_including?(node)
39
48
 
40
49
  unused_let_bang(node) do |let|
41
50
  add_offense(let)
@@ -45,8 +54,14 @@ module RuboCop
45
54
  private
46
55
 
47
56
  def unused_let_bang(node)
48
- let_bang(node) do |method_send, method_name|
49
- yield(method_send) unless method_called?(node, method_name)
57
+ child_let_bang(node) do |method_send, method_name|
58
+ yield(method_send) unless method_called?(node, method_name.to_sym)
59
+ end
60
+ end
61
+
62
+ def child_let_bang(node, &block)
63
+ RuboCop::RSpec::ExampleGroup.new(node).lets.each do |let|
64
+ let_bang(let, &block)
50
65
  end
51
66
  end
52
67
  end
@@ -13,7 +13,7 @@ module RuboCop
13
13
  # thing = Thing.new(baz: 42)
14
14
  # allow(foo).to receive(:bar).and_return(thing)
15
15
  #
16
- class MessageChain < Cop
16
+ class MessageChain < Base
17
17
  MSG = 'Avoid stubbing using `%<method>s`.'
18
18
 
19
19
  def_node_matcher :message_chain, <<-PATTERN
@@ -21,11 +21,12 @@ module RuboCop
21
21
  PATTERN
22
22
 
23
23
  def on_send(node)
24
- message_chain(node) { add_offense(node, location: :selector) }
25
- end
26
-
27
- def message(node)
28
- format(MSG, method: node.method_name)
24
+ message_chain(node) do
25
+ add_offense(
26
+ node.loc.selector,
27
+ message: format(MSG, method: node.method_name)
28
+ )
29
+ end
29
30
  end
30
31
  end
31
32
  end
@@ -24,7 +24,7 @@ module RuboCop
24
24
  # # good
25
25
  # expect(foo).to receive(:bar)
26
26
  #
27
- class MessageExpectation < Cop
27
+ class MessageExpectation < Base
28
28
  include ConfigurableEnforcedStyle
29
29
 
30
30
  MSG = 'Prefer `%<style>s` for setting message expectations.'
@@ -42,7 +42,7 @@ module RuboCop
42
42
  return correct_style_detected if preferred_style?(match)
43
43
 
44
44
  message = format(MSG, style: style)
45
- add_offense(match, location: :selector, message: message) do
45
+ add_offense(match.loc.selector, message: message) do
46
46
  opposite_style_detected
47
47
  end
48
48
  end
@@ -24,7 +24,7 @@ module RuboCop
24
24
  # # good
25
25
  # expect(foo).to receive(:bar)
26
26
  #
27
- class MessageSpies < Cop
27
+ class MessageSpies < Base
28
28
  include ConfigurableEnforcedStyle
29
29
 
30
30
  MSG_RECEIVE = 'Prefer `receive` for setting message expectations.'
@@ -48,8 +48,7 @@ module RuboCop
48
48
  return correct_style_detected if preferred_style?(message_matcher)
49
49
 
50
50
  add_offense(
51
- message_matcher,
52
- location: :selector,
51
+ message_matcher.loc.selector,
53
52
  message: error_message(receiver)
54
53
  ) { opposite_style_detected }
55
54
  end
@@ -19,7 +19,7 @@ module RuboCop
19
19
  #
20
20
  # describe "A feature example" do
21
21
  # end
22
- class MissingExampleGroupArgument < Cop
22
+ class MissingExampleGroupArgument < Base
23
23
  MSG = 'The first argument to `%<method>s` should not be empty.'
24
24
 
25
25
  def on_block(node)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module RSpec
6
- # Checks for multiple top level describes.
6
+ # Checks for multiple top-level example groups.
7
7
  #
8
8
  # Multiple descriptions for the same class or module should either
9
9
  # be nested or separated into different test files.
@@ -22,17 +22,20 @@ module RuboCop
22
22
  # describe '.do_something_else' do
23
23
  # end
24
24
  # end
25
- class MultipleDescribes < Cop
26
- include RuboCop::RSpec::TopLevelDescribe
25
+ class MultipleDescribes < Base
26
+ include RuboCop::RSpec::TopLevelGroup
27
27
 
28
- MSG = 'Do not use multiple top level describes - '\
28
+ MSG = 'Do not use multiple top-level example groups - '\
29
29
  'try to nest them.'
30
30
 
31
- def on_top_level_describe(node, _args)
32
- return if single_top_level_describe?
33
- return unless top_level_nodes.first.equal?(node)
31
+ def on_top_level_group(node)
32
+ top_level_example_groups =
33
+ top_level_groups.select(&method(:example_group?))
34
34
 
35
- add_offense(node)
35
+ return if top_level_example_groups.one?
36
+ return unless top_level_example_groups.first.equal?(node)
37
+
38
+ add_offense(node.send_node)
36
39
  end
37
40
  end
38
41
  end