diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ce64d2c1..eb2f01bd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index e5b0f7182..e955ea7e5 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -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 @@ -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 diff --git a/lib/rubocop/cop/rspec/example_without_description.rb b/lib/rubocop/cop/rspec/example_without_description.rb index 8d5209849..e53d574b1 100644 --- a/lib/rubocop/cop/rspec/example_without_description.rb +++ b/lib/rubocop/cop/rspec/example_without_description.rb @@ -7,6 +7,7 @@ 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 @@ -14,17 +15,24 @@ module RSpec # # 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 @@ -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 diff --git a/spec/rubocop/cop/rspec/example_without_description_spec.rb b/spec/rubocop/cop/rspec/example_without_description_spec.rb index fd382c83c..c3dad2ac1 100644 --- a/spec/rubocop/cop/rspec/example_without_description_spec.rb +++ b/spec/rubocop/cop/rspec/example_without_description_spec.rb @@ -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. @@ -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. @@ -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. @@ -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. @@ -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