From 79e7a11e22b4f661a4ea8b6ead71938ba25b51f3 Mon Sep 17 00:00:00 2001 From: ydah <13041216+ydah@users.noreply.github.com> Date: Mon, 10 Oct 2022 10:59:30 +0900 Subject: [PATCH] Add `AllowedPatterns` configuration option to `RSpec/NoExpectationExample` Fix: https://github.com/rubocop/rubocop-rspec/issues/1385 This cop can be customized allowed expectation methods pattern with `AllowedPatterns`. \Aexpect_ and \Aassert_ are allowed by default. ### @ example `AllowedPatterns: [\Aexpect_]` ```ruby # bad it do not_expect_something end # good it do expect_something end ``` --- CHANGELOG.md | 1 + config/default.yml | 4 ++ docs/modules/ROOT/pages/cops_rspec.adoc | 43 ++++++++++++++++++- .../cop/rspec/no_expectation_example.rb | 38 ++++++++++++++++ .../cop/rspec/no_expectation_example_spec.rb | 33 ++++++++++++++ 5 files changed, 118 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47e0ca0776..a901831800 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Add `require_implicit` style to `RSpec/ImplicitSubject`. ([@r7kamura][]) * Fix a false positive for `RSpec/Capybara/SpecificMatcher` when `have_css("a")` without attribute. ([@ydah][]) +* Add `AllowedPatterns` configuration option to `RSpec/NoExpectationExample`. ([@ydah][]) ## 2.13.2 (2022-09-23) diff --git a/config/default.yml b/config/default.yml index fa622f46d8..44ffc90409 100644 --- a/config/default.yml +++ b/config/default.yml @@ -641,7 +641,11 @@ RSpec/NoExpectationExample: Enabled: pending Safe: false VersionAdded: '2.13' + VersionChanged: '2.14' Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample + AllowedPatterns: + - "\\Aexpect_" + - "\\Aassert_" RSpec/NotToNot: Description: Checks for consistent method usage for negating expectations. diff --git a/docs/modules/ROOT/pages/cops_rspec.adoc b/docs/modules/ROOT/pages/cops_rspec.adoc index f7a1a004e2..72afd789ac 100644 --- a/docs/modules/ROOT/pages/cops_rspec.adoc +++ b/docs/modules/ROOT/pages/cops_rspec.adoc @@ -3503,7 +3503,7 @@ end | No | No | 2.13 -| - +| 2.14 |=== Checks if an example contains any expectation. @@ -3520,6 +3520,9 @@ add the following configuration: Expectations: - custom_expect +This cop can be customized allowed expectation methods pattern +with `AllowedPatterns`. \Aexpect_ and \Aassert_ are allowed by default. + === Examples [source,ruby] @@ -3535,6 +3538,44 @@ it do end ---- +==== `AllowedPatterns` configuration + +[source,ruby] +---- +# .rubocop.yml +# RSpec/NoExpectationExample: +# AllowedPatterns: +# - \Aexpect_ +# - \Aassert_ +---- + +[source,ruby] +---- +# bad +it do + not_expect_something +end + +# good +it do + expect_something +end + +it do + assert_something +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedPatterns +| `\Aexpect_`, `\Aassert_` +| Array +|=== + === References * https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample diff --git a/lib/rubocop/cop/rspec/no_expectation_example.rb b/lib/rubocop/cop/rspec/no_expectation_example.rb index 7e8d0a868f..5cd99253ff 100644 --- a/lib/rubocop/cop/rspec/no_expectation_example.rb +++ b/lib/rubocop/cop/rspec/no_expectation_example.rb @@ -28,7 +28,34 @@ module RSpec # expect(a?).to be(true) # end # + # This cop can be customized allowed expectation methods pattern + # with `AllowedPatterns`. \Aexpect_ and \Aassert_ are allowed by default. + # + # @example `AllowedPatterns` configuration + # + # # .rubocop.yml + # # RSpec/NoExpectationExample: + # # AllowedPatterns: + # # - \Aexpect_ + # # - \Aassert_ + # + # @example + # # bad + # it do + # not_expect_something + # end + # + # # good + # it do + # expect_something + # end + # + # it do + # assert_something + # end + # class NoExpectationExample < Base + include AllowedPattern MSG = 'No expectation found in this example.' # @!method regular_or_focused_example?(node) @@ -61,11 +88,22 @@ def on_block(node) return unless regular_or_focused_example?(node) return if including_any_expectation?(node) return if including_any_skip_example?(node) + return if including_any_allowed_pattern?(node) add_offense(node) end alias on_numblock on_block + + private + + def including_any_allowed_pattern?(node) + node.each_descendant(:send) do |send_node| + return true if matches_allowed_pattern?(send_node.method_name) + end + + false + end end end end diff --git a/spec/rubocop/cop/rspec/no_expectation_example_spec.rb b/spec/rubocop/cop/rspec/no_expectation_example_spec.rb index 265f46b1c4..aa6b6d5d4c 100644 --- a/spec/rubocop/cop/rspec/no_expectation_example_spec.rb +++ b/spec/rubocop/cop/rspec/no_expectation_example_spec.rb @@ -137,6 +137,39 @@ end end + context 'when `AllowedPatterns: [\Aexpect_]`' do + let(:cop_config) { { 'AllowedPatterns' => ['\Aexpect_'] } } + + context 'with only allowed pattern methods are used' do + it 'registers no offenses' do + expect_no_offenses(<<~RUBY) + it { expect_something } + RUBY + end + end + + context 'with allowed pattern methods and other method are used' do + it 'registers no offenses' do + expect_no_offenses(<<~RUBY) + it do + do_something + expect_something + do_something + end + RUBY + end + end + + context 'with only not allowed pattern methods are used' do + it 'does something' do + expect_offense(<<~RUBY) + it { not_expect_something } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ No expectation found in this example. + RUBY + end + end + end + context 'when Ruby 2.7', :ruby27 do context 'with no expectation example with it' do it 'registers an offense' do