Skip to content

Commit b0bf26c

Browse files
committed
Fix false negative for RSpec/RepeatedExampleGroupDescription cop when include skip/pending
Fixes: #2021
1 parent 961389a commit b0bf26c

File tree

3 files changed

+203
-28
lines changed

3 files changed

+203
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- Fix a false positive for `RSpec/ReceiveNever` cop when `allow(...).to receive(...).never`. ([@ydah])
99
- Fix detection of nameless doubles with methods in `RSpec/VerifiedDoubles`. ([@ushi-as])
1010
- Improve an offense message for `RSpec/RepeatedExample` cop. ([@ydah])
11+
- Fix false negative for `RSpec/RepeatedExampleGroupDescription` cop when include skip/pending. ([@ydah])
1112

1213
## 3.7.0 (2025-09-01)
1314

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: 198 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,181 @@
240240
end
241241
RUBY
242242
end
243+
244+
it 'does not register offense for non-repeating group examples 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 non-repeating group examples ' \
259+
'with pending' do
260+
expect_no_offenses(<<~RUBY)
261+
describe 'Something' do
262+
context 'when foo is true' do
263+
pending
264+
end
265+
266+
context 'when foo is false' do
267+
pending
268+
end
269+
end
270+
RUBY
271+
end
272+
273+
it 'registers offense for repeated descriptions with pending examples' do
274+
expect_offense(<<~RUBY)
275+
describe 'Screenshots::CreateInteractor' do
276+
context 'when the request is valid' do
277+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
278+
pending 'add something'
279+
end
280+
281+
context 'when the request is valid' do
282+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
283+
pending 'add something'
284+
end
285+
end
286+
RUBY
287+
end
288+
289+
it 'registers offense for repeated descriptions with skip examples' do
290+
expect_offense(<<~RUBY)
291+
describe 'Something' do
292+
context 'when foo' do
293+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
294+
skip 'not implemented'
295+
end
296+
297+
context 'when foo' do
298+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
299+
skip 'not implemented'
300+
end
301+
end
302+
RUBY
303+
end
304+
305+
it 'registers offense for repeated descriptions with pending metadata' do
306+
expect_offense(<<~RUBY)
307+
describe 'Something' do
308+
context 'when foo', :pending do
309+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
310+
end
311+
312+
context 'when foo', :pending do
313+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
314+
end
315+
end
316+
RUBY
317+
end
318+
319+
it 'registers offense for repeated descriptions with skip metadata' do
320+
expect_offense(<<~RUBY)
321+
describe 'Something' do
322+
context 'when foo', :skip do
323+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
324+
end
325+
326+
context 'when foo', :skip do
327+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
328+
end
329+
end
330+
RUBY
331+
end
332+
333+
it 'registers offense for repeated descriptions with skip metadata hash' do
334+
expect_offense(<<~RUBY)
335+
describe 'Something' do
336+
context 'when foo', skip: true do
337+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
338+
end
339+
340+
context 'when foo', skip: true do
341+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
342+
end
343+
end
344+
RUBY
345+
end
346+
347+
it 'registers offense for repeated descriptions with pending metadata hash' do
348+
expect_offense(<<~RUBY)
349+
describe 'Something' do
350+
context 'when foo', pending: 'not ready' do
351+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
352+
end
353+
354+
context 'when foo', pending: 'not ready' do
355+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
356+
end
357+
end
358+
RUBY
359+
end
360+
361+
it 'registers offense with mixed pending and skip' do
362+
expect_offense(<<~RUBY)
363+
describe 'Something' do
364+
context 'when foo' do
365+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
366+
pending 'add something'
367+
end
368+
369+
context 'when foo' do
370+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
371+
skip 'not ready'
372+
end
373+
end
374+
RUBY
375+
end
376+
377+
it 'registers offense for repeated descriptions with xcontext' do
378+
expect_offense(<<~RUBY)
379+
describe 'Something' do
380+
xcontext 'when foo' do
381+
^^^^^^^^^^^^^^^^^^^^^^ Repeated xcontext block description on line(s) 5.
382+
end
383+
384+
xcontext 'when foo' do
385+
^^^^^^^^^^^^^^^^^^^^^^ Repeated xcontext block description on line(s) 2.
386+
end
387+
end
388+
RUBY
389+
end
390+
391+
it 'registers offense for repeated descriptions with xdescribe' do
392+
expect_offense(<<~RUBY)
393+
xdescribe 'Something' do
394+
^^^^^^^^^^^^^^^^^^^^^^^^ Repeated xdescribe block description on line(s) 5.
395+
it { is_expected.to be_valid }
396+
end
397+
398+
xdescribe 'Something' do
399+
^^^^^^^^^^^^^^^^^^^^^^^^ Repeated xdescribe block description on line(s) 1.
400+
it { is_expected.to be_valid }
401+
end
402+
RUBY
403+
end
404+
405+
it 'registers offense when one group has pending and other does not' do
406+
expect_offense(<<~RUBY)
407+
describe 'Something' do
408+
context 'when foo' do
409+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
410+
pending 'add something'
411+
end
412+
413+
context 'when foo' do
414+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
415+
it { is_expected.to be_valid }
416+
end
417+
end
418+
RUBY
419+
end
243420
end

0 commit comments

Comments
 (0)