Skip to content

Commit

Permalink
Fix a false positive for RSpec/ExampleWithoutDescription when `spec…
Browse files Browse the repository at this point in the history
…ify` with multi-line block and missing description

This PR fixes a false positive for `RSpec/ExampleWithoutDescription` when `specify` with multi-line block and missing description.
This is because `specify` is recommended when there is no description.

refs: https://rspec.rubystyle.guide/#it-and-specify

```ruby
specify do
  # ...
end
```
  • Loading branch information
ydah committed Feb 17, 2024
1 parent f9abbde commit 20311f5
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- Add new `RSpec/RepeatedSubjectCall` cop. ([@drcapulet])
- Add configuration option `ResponseMethods` to `RSpec/Rails/HaveHttpStatus`. ([@ydah])
- Fix a false negative for `RSpec/DescribedClass` when class with constant. ([@ydah])
- Fix a false positive for `RSpec/ExampleWithoutDescription` when `specify` with multi-line block and missing description. ([@ydah])

## 2.26.1 (2024-01-05)

Expand Down
14 changes: 12 additions & 2 deletions docs/modules/ROOT/pages/cops_rspec.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1628,6 +1628,7 @@ Checks for examples without a description.
RSpec allows for auto-generated example descriptions when there is no
description provided or the description is an empty one.
It is acceptable to use `specify` without a description
This cop removes empty descriptions.
It also defines whether auto-generated description is allowed, based
Expand All @@ -1637,20 +1638,29 @@ This cop can be configured using the `EnforcedStyle` option
=== Examples
[source,ruby]
----
# always good
specify do
result = service.call
expect(result).to be(true)
end
----
==== `EnforcedStyle: always_allow` (default)
[source,ruby]
----
# bad
it('') { is_expected.to be_good }
it '' do
specify '' do
result = service.call
expect(result).to be(true)
end
# good
it { is_expected.to be_good }
it do
specify do
result = service.call
expect(result).to be(true)
end
Expand Down
13 changes: 11 additions & 2 deletions lib/rubocop/cop/rspec/example_without_description.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,32 @@ module RSpec
#
# RSpec allows for auto-generated example descriptions when there is no
# description provided or the description is an empty one.
# It is acceptable to use `specify` without a description
#
# This cop removes empty descriptions.
# It also defines whether auto-generated description is allowed, based
# on the configured style.
#
# This cop can be configured using the `EnforcedStyle` option
#
# @example
# # always good
# specify do
# result = service.call
# expect(result).to be(true)
# end
#
# @example `EnforcedStyle: always_allow` (default)
# # bad
# it('') { is_expected.to be_good }
# it '' do
# specify '' do
# result = service.call
# expect(result).to be(true)
# end
#
# # good
# it { is_expected.to be_good }
# it do
# specify do
# result = service.call
# expect(result).to be(true)
# end
Expand Down Expand Up @@ -75,6 +83,7 @@ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
def check_example_without_description(node)
return if node.arguments?
return unless disallow_empty_description?(node)
return if node.method?(:specify) && node.parent.multiline?

add_offense(node, message: MSG_ADD_DESCRIPTION)
end
Expand Down
81 changes: 75 additions & 6 deletions spec/rubocop/cop/rspec/example_without_description_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
context 'with EnforcedStyle `always_allow`' do
let(:enforced_style) { 'always_allow' }

it 'flags empty strings for description' do
it 'flags `it` with a empty strings for description' do
expect_offense(<<~RUBY)
it '' do
^^ Omit the argument when you want to have auto-generated description.
Expand All @@ -32,12 +32,37 @@
end
RUBY
end

it 'flags `specify` with a empty strings for description' do
expect_offense(<<~RUBY)
specify '' do
^^ Omit the argument when you want to have auto-generated description.
expect(subject).to be_good
end
RUBY
end

it 'ignores `specify` without an argument' do
expect_no_offenses(<<~RUBY)
specify do
expect(subject).to be_good
end
RUBY
end

it 'ignores `specify` with a description' do
expect_no_offenses(<<~RUBY)
specify 'is good' do
expect(subject).to be_good
end
RUBY
end
end

context 'with EnforcedStyle `single_line_only`' do
let(:enforced_style) { 'single_line_only' }

it 'flags missing description in multi-line examples' do
it 'flags `it` missing description in multi-line examples' do
expect_offense(<<~RUBY)
it do
^^ Add a description.
Expand All @@ -46,24 +71,45 @@
RUBY
end

it 'ignores missing description in single-line examples' do
it 'ignores `it` missing description in single-line examples' do
expect_no_offenses(<<~RUBY)
it { expect(subject).to be_good }
RUBY
end

it 'flags example with an empty string for description' do
it 'flags `it` with an empty string for description' do
expect_offense(<<~RUBY)
it('') { expect(subject).to be_good }
^^ Omit the argument when you want to have auto-generated description.
RUBY
end

it 'ignores `specify` missing decripton in multi-line examples' do
expect_no_offenses(<<~RUBY)
specify do
expect(subject).to be_good
end
RUBY
end

it 'ignores `specify` missing description in single-line examples' do
expect_no_offenses(<<~RUBY)
specify { expect(subject).to be_good }
RUBY
end

it 'flags `specify` with an empty string for description' do
expect_offense(<<~RUBY)
specify('') { expect(subject).to be_good }
^^ Omit the argument when you want to have auto-generated description.
RUBY
end
end

context 'with EnforcedStyle `disallow`' do
let(:enforced_style) { 'disallow' }

it 'flags missing description in multi-line examples' do
it 'flags `it` missing description in multi-line examples' do
expect_offense(<<~RUBY)
it do
^^ Add a description.
Expand All @@ -72,7 +118,7 @@
RUBY
end

it 'flags missing description in single-line examples' do
it 'flags `it` missing description in single-line examples' do
expect_offense(<<~RUBY)
it { expect(subject).to be_good }
^^ Add a description.
Expand All @@ -86,5 +132,28 @@
end
RUBY
end

it 'ignores `specify` missing description in multi-line examples' do
expect_no_offenses(<<~RUBY)
specify do
expect(subject).to be_good
end
RUBY
end

it 'flags `specify` missing description in single-line examples' do
expect_offense(<<~RUBY)
specify { expect(subject).to be_good }
^^^^^^^ Add a description.
RUBY
end

it 'ignores `specify` with a description' do
expect_no_offenses(<<~RUBY)
specify 'is good' do
expect(subject).to be_good
end
RUBY
end
end
end

0 comments on commit 20311f5

Please sign in to comment.