Skip to content

Commit 01f47bd

Browse files
committed
Fix false negative for RSpec/RepeatedExampleGroupDescription cop when include skip/pending
Fixes: #2021
1 parent 7e6691d commit 01f47bd

File tree

3 files changed

+202
-28
lines changed

3 files changed

+202
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
- Add new cop `RSpec/LeakyLocalVariable`. ([@lovro-bikic])
66
- Bump RuboCop requirement to +1.81. ([@ydah])
77
- Fix a false positive for `RSpec/LetSetup` when `let!` used in outer scope. ([@ydah])
8+
- Fix false negative for `RSpec/RepeatedExampleGroupDescription` cop when include skip/pending. ([@ydah])
89

910
## 3.7.0 (2025-09-01)
1011

lib/rubocop/cop/rspec/repeated_example_group_description.rb

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ module RSpec
4545
class RepeatedExampleGroupDescription < Base
4646
include SkipOrPending
4747

48-
MSG = 'Repeated %<group>s block description on line(s) %<loc>s'
48+
MSG = 'Repeated %<group>s block description on line(s) %<loc>s.'
4949

5050
# @!method several_example_groups?(node)
5151
def_node_matcher :several_example_groups?, <<~PATTERN
@@ -64,7 +64,9 @@ def on_begin(node)
6464
return unless several_example_groups?(node)
6565

6666
repeated_group_descriptions(node).each do |group, repeats|
67-
add_offense(group, message: message(group, repeats))
67+
message = format(MSG, group: group.method_name,
68+
loc: repeats.join(', '))
69+
add_offense(group, message: message)
6870
end
6971
end
7072

@@ -74,7 +76,6 @@ def repeated_group_descriptions(node)
7476
node
7577
.children
7678
.select { |child| example_group?(child) }
77-
.reject { |child| skip_or_pending_inside_block?(child) }
7879
.reject { |child| empty_description?(child) }
7980
.group_by { |group| doc_string_and_metadata(group) }
8081
.values
@@ -86,10 +87,6 @@ def add_repeated_lines(groups)
8687
repeated_lines = groups.map(&:first_line)
8788
groups.map { |group| [group, repeated_lines - [group.first_line]] }
8889
end
89-
90-
def message(group, repeats)
91-
format(MSG, group: group.method_name, loc: repeats)
92-
end
9390
end
9491
end
9592
end

spec/rubocop/cop/rspec/repeated_example_group_description_spec.rb

Lines changed: 197 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
it 'registers an offense for repeated describe descriptions' do
55
expect_offense(<<~RUBY)
66
describe 'doing x' do
7-
^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) [5]
7+
^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) 5.
88
# example group
99
end
1010
1111
describe 'doing x' do
12-
^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) [1]
12+
^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) 1.
1313
# example group
1414
end
1515
RUBY
@@ -18,12 +18,12 @@
1818
it 'registers an offense for repeated context descriptions' do
1919
expect_offense(<<~RUBY)
2020
context 'when awesome case' do
21-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [5]
21+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
2222
# example group
2323
end
2424
2525
context 'when awesome case' do
26-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [1]
26+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 1.
2727
# example group
2828
end
2929
RUBY
@@ -37,17 +37,17 @@
3737
end
3838
3939
context 'when awesome case' do
40-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [10, 14]
40+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 10, 14.
4141
# example group
4242
end
4343
4444
context 'when awesome case' do
45-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [6, 14]
45+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6, 14.
4646
# example group
4747
end
4848
4949
context 'when awesome case' do
50-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [6, 10]
50+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6, 10.
5151
# example group
5252
end
5353
end
@@ -94,12 +94,12 @@
9494
'similar descriptions' do
9595
expect_offense(<<~RUBY)
9696
describe 'Animal' do
97-
^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) [5]
97+
^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) 5.
9898
# example group
9999
end
100100
101101
context 'Animal' do
102-
^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [1]
102+
^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 1.
103103
# example group
104104
end
105105
RUBY
@@ -112,12 +112,12 @@
112112
end
113113
114114
RSpec.describe 'doing x' do
115-
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) [9]
115+
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) 9.
116116
it { cool_predicate_method }
117117
end
118118
119119
context 'doing x' do
120-
^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [5]
120+
^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
121121
it { cool_predicate_method }
122122
end
123123
RUBY
@@ -126,12 +126,12 @@
126126
it 'registers offense only for RSPEC namespace example groups in any order' do
127127
expect_offense(<<~RUBY)
128128
RSpec.describe 'doing x' do
129-
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) [5]
129+
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) 5.
130130
it { cool_predicate_method }
131131
end
132132
133133
context 'doing x' do
134-
^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [1]
134+
^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 1.
135135
it { cool_predicate_method }
136136
end
137137
@@ -149,12 +149,12 @@
149149
before { create(:admin) }
150150
151151
describe '#load' do
152-
^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) [10]
152+
^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) 10.
153153
it { cool_predicate_method }
154154
end
155155
156156
describe '#load' do
157-
^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) [6]
157+
^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) 6.
158158
it { cool_predicate_method }
159159
end
160160
end
@@ -176,12 +176,12 @@
176176
it 'registers offense correctly for interpolated docstrings' do
177177
expect_offense(<<~RUBY)
178178
context "when class is \#{A::B}" do
179-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [5]
179+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
180180
# ...
181181
end
182182
183183
context "when class is \#{A::B}" do
184-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [1]
184+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 1.
185185
# ...
186186
end
187187
RUBY
@@ -202,12 +202,12 @@
202202
it 'registers offense if same method used in docstring' do
203203
expect_offense(<<~RUBY)
204204
context(description) do
205-
^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [5]
205+
^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
206206
# ...
207207
end
208208
209209
context(description) do
210-
^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) [1]
210+
^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 1.
211211
# ...
212212
end
213213
RUBY
@@ -216,14 +216,14 @@
216216
it 'registers offense correctly if example groups are separated' do
217217
expect_offense(<<~RUBY)
218218
describe 'repeated' do
219-
^^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) [7]
219+
^^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) 7.
220220
it { is_expected.to be_truthy }
221221
end
222222
223223
before { do_something }
224224
225225
describe 'repeated' do
226-
^^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) [1]
226+
^^^^^^^^^^^^^^^^^^^^^^ Repeated describe block description on line(s) 1.
227227
it { is_expected.to be_truthy }
228228
end
229229
RUBY
@@ -240,4 +240,180 @@
240240
end
241241
RUBY
242242
end
243+
244+
it 'does not register offense for example group with skip' do
245+
expect_no_offenses(<<~RUBY)
246+
describe 'Something' do
247+
context 'when foo is true' do
248+
skip
249+
end
250+
251+
context 'when foo is false' do
252+
skip
253+
end
254+
end
255+
RUBY
256+
end
257+
258+
it 'does not register offense for example group with pending' do
259+
expect_no_offenses(<<~RUBY)
260+
describe 'Something' do
261+
context 'when foo is true' do
262+
pending
263+
end
264+
265+
context 'when foo is false' do
266+
pending
267+
end
268+
end
269+
RUBY
270+
end
271+
272+
it 'registers offense for repeated descriptions with pending examples' do
273+
expect_offense(<<~RUBY)
274+
describe 'Screenshots::CreateInteractor' do
275+
context 'when the request is valid' do
276+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
277+
pending 'add something'
278+
end
279+
280+
context 'when the request is valid' do
281+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
282+
pending 'add something'
283+
end
284+
end
285+
RUBY
286+
end
287+
288+
it 'registers offense for repeated descriptions with skip examples' do
289+
expect_offense(<<~RUBY)
290+
describe 'Something' do
291+
context 'when foo' do
292+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
293+
skip 'not implemented'
294+
end
295+
296+
context 'when foo' do
297+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
298+
skip 'not implemented'
299+
end
300+
end
301+
RUBY
302+
end
303+
304+
it 'registers offense for repeated descriptions with pending metadata' do
305+
expect_offense(<<~RUBY)
306+
describe 'Something' do
307+
context 'when foo', :pending do
308+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
309+
end
310+
311+
context 'when foo', :pending do
312+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
313+
end
314+
end
315+
RUBY
316+
end
317+
318+
it 'registers offense for repeated descriptions with skip metadata' do
319+
expect_offense(<<~RUBY)
320+
describe 'Something' do
321+
context 'when foo', :skip do
322+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
323+
end
324+
325+
context 'when foo', :skip do
326+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
327+
end
328+
end
329+
RUBY
330+
end
331+
332+
it 'registers offense for repeated descriptions with skip metadata hash' do
333+
expect_offense(<<~RUBY)
334+
describe 'Something' do
335+
context 'when foo', skip: true do
336+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
337+
end
338+
339+
context 'when foo', skip: true do
340+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
341+
end
342+
end
343+
RUBY
344+
end
345+
346+
it 'registers offense for repeated descriptions with pending metadata hash' do
347+
expect_offense(<<~RUBY)
348+
describe 'Something' do
349+
context 'when foo', pending: 'not ready' do
350+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
351+
end
352+
353+
context 'when foo', pending: 'not ready' do
354+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
355+
end
356+
end
357+
RUBY
358+
end
359+
360+
it 'registers offense with mixed pending and skip' do
361+
expect_offense(<<~RUBY)
362+
describe 'Something' do
363+
context 'when foo' do
364+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
365+
pending 'add something'
366+
end
367+
368+
context 'when foo' do
369+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
370+
skip 'not ready'
371+
end
372+
end
373+
RUBY
374+
end
375+
376+
it 'registers offense for repeated descriptions with xcontext' do
377+
expect_offense(<<~RUBY)
378+
describe 'Something' do
379+
xcontext 'when foo' do
380+
^^^^^^^^^^^^^^^^^^^^^^ Repeated xcontext block description on line(s) 5.
381+
end
382+
383+
xcontext 'when foo' do
384+
^^^^^^^^^^^^^^^^^^^^^^ Repeated xcontext block description on line(s) 2.
385+
end
386+
end
387+
RUBY
388+
end
389+
390+
it 'registers offense for repeated descriptions with xdescribe' do
391+
expect_offense(<<~RUBY)
392+
xdescribe 'Something' do
393+
^^^^^^^^^^^^^^^^^^^^^^^^ Repeated xdescribe block description on line(s) 5.
394+
it { is_expected.to be_valid }
395+
end
396+
397+
xdescribe 'Something' do
398+
^^^^^^^^^^^^^^^^^^^^^^^^ Repeated xdescribe block description on line(s) 1.
399+
it { is_expected.to be_valid }
400+
end
401+
RUBY
402+
end
403+
404+
it 'registers offense when one group has pending and other does not' do
405+
expect_offense(<<~RUBY)
406+
describe 'Something' do
407+
context 'when foo' do
408+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
409+
pending 'add something'
410+
end
411+
412+
context 'when foo' do
413+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
414+
it { is_expected.to be_valid }
415+
end
416+
end
417+
RUBY
418+
end
243419
end

0 commit comments

Comments
 (0)