Skip to content

Commit 78115ba

Browse files
committed
Fix false negative for RSpec/RepeatedExampleGroupDescription cop when include skip/pending
Fixes: #2021
1 parent ef3f1ee commit 78115ba

File tree

3 files changed

+176
-28
lines changed

3 files changed

+176
-28
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Add new cop `RSpec/LeakyLocalVariable`. ([@lovro-bikic])
66
- Bump RuboCop requirement to +1.81. ([@ydah])
7+
- Fix false negative for `RSpec/RepeatedExampleGroupDescription` cop when include skip/pending. ([@ydah])
78

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

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: 171 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,154 @@
240240
end
241241
RUBY
242242
end
243+
244+
# New tests for pending/skip detection
245+
246+
it 'registers offense for repeated descriptions with pending examples' do
247+
expect_offense(<<~RUBY)
248+
describe 'Screenshots::CreateInteractor' do
249+
context 'when the request is valid' do
250+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
251+
pending 'add something'
252+
end
253+
254+
context 'when the request is valid' do
255+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
256+
pending 'add something'
257+
end
258+
end
259+
RUBY
260+
end
261+
262+
it 'registers offense for repeated descriptions with skip examples' do
263+
expect_offense(<<~RUBY)
264+
describe 'Something' do
265+
context 'when foo' do
266+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
267+
skip 'not implemented'
268+
end
269+
270+
context 'when foo' do
271+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
272+
skip 'not implemented'
273+
end
274+
end
275+
RUBY
276+
end
277+
278+
it 'registers offense for repeated descriptions with pending metadata' do
279+
expect_offense(<<~RUBY)
280+
describe 'Something' do
281+
context 'when foo', :pending do
282+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
283+
end
284+
285+
context 'when foo', :pending do
286+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
287+
end
288+
end
289+
RUBY
290+
end
291+
292+
it 'registers offense for repeated descriptions with skip metadata' do
293+
expect_offense(<<~RUBY)
294+
describe 'Something' do
295+
context 'when foo', :skip do
296+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
297+
end
298+
299+
context 'when foo', :skip do
300+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
301+
end
302+
end
303+
RUBY
304+
end
305+
306+
it 'registers offense for repeated descriptions with skip metadata hash' do
307+
expect_offense(<<~RUBY)
308+
describe 'Something' do
309+
context 'when foo', skip: true do
310+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
311+
end
312+
313+
context 'when foo', skip: true do
314+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
315+
end
316+
end
317+
RUBY
318+
end
319+
320+
it 'registers offense for repeated descriptions with pending metadata hash' do
321+
expect_offense(<<~RUBY)
322+
describe 'Something' do
323+
context 'when foo', pending: 'not ready' do
324+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 5.
325+
end
326+
327+
context 'when foo', pending: 'not ready' do
328+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
329+
end
330+
end
331+
RUBY
332+
end
333+
334+
it 'registers offense with mixed pending and skip' do
335+
expect_offense(<<~RUBY)
336+
describe 'Something' do
337+
context 'when foo' do
338+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
339+
pending 'add something'
340+
end
341+
342+
context 'when foo' do
343+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
344+
skip 'not ready'
345+
end
346+
end
347+
RUBY
348+
end
349+
350+
it 'registers offense for repeated descriptions with xcontext' do
351+
expect_offense(<<~RUBY)
352+
describe 'Something' do
353+
xcontext 'when foo' do
354+
^^^^^^^^^^^^^^^^^^^^^^ Repeated xcontext block description on line(s) 5.
355+
end
356+
357+
xcontext 'when foo' do
358+
^^^^^^^^^^^^^^^^^^^^^^ Repeated xcontext block description on line(s) 2.
359+
end
360+
end
361+
RUBY
362+
end
363+
364+
it 'registers offense for repeated descriptions with xdescribe' do
365+
expect_offense(<<~RUBY)
366+
xdescribe 'Something' do
367+
^^^^^^^^^^^^^^^^^^^^^^^^ Repeated xdescribe block description on line(s) 5.
368+
it { is_expected.to be_valid }
369+
end
370+
371+
xdescribe 'Something' do
372+
^^^^^^^^^^^^^^^^^^^^^^^^ Repeated xdescribe block description on line(s) 1.
373+
it { is_expected.to be_valid }
374+
end
375+
RUBY
376+
end
377+
378+
it 'registers offense when one group has pending and other does not' do
379+
expect_offense(<<~RUBY)
380+
describe 'Something' do
381+
context 'when foo' do
382+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 6.
383+
pending 'add something'
384+
end
385+
386+
context 'when foo' do
387+
^^^^^^^^^^^^^^^^^^^^^ Repeated context block description on line(s) 2.
388+
it { is_expected.to be_valid }
389+
end
390+
end
391+
RUBY
392+
end
243393
end

0 commit comments

Comments
 (0)