Skip to content

Commit

Permalink
Add AllowedPatterns configuration option to `RSpec/NoExpectationExa…
Browse files Browse the repository at this point in the history
…mple`

Fix: #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
```
  • Loading branch information
ydah committed Oct 16, 2022
1 parent e95228d commit 9a96177
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 10 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Fix a false positive for `RSpec/Capybara/SpecificMatcher` when `have_css("a")` without attribute. ([@ydah][])
* Update `RSpec/ExampleWording` cop to raise error for insufficient descriptions. ([@akrox58][])
* Add new `RSpec/Capybara/NegationMatcher` cop. ([@ydah][])
* Add `AllowedPatterns` configuration option to `RSpec/NoExpectationExample`. ([@ydah][])

## 2.13.2 (2022-09-23)

Expand Down
4 changes: 4 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,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:
- "^expect_"
- "^assert_"

RSpec/NotToNot:
Description: Checks for consistent method usage for negating expectations.
Expand Down
44 changes: 43 additions & 1 deletion docs/modules/ROOT/pages/cops_rspec.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3525,7 +3525,7 @@ end
| No
| No
| 2.13
| -
| 2.14
|===

Checks if an example contains any expectation.
Expand All @@ -3542,6 +3542,10 @@ add the following configuration:
Expectations:
- custom_expect

This cop can be customized with an allowed expectation methods pattern
with an `AllowedPatterns` option. ^expect_ and ^assert_ are allowed
by default.

=== Examples

[source,ruby]
Expand All @@ -3557,6 +3561,44 @@ it do
end
----

==== `AllowedPatterns` configuration

[source,ruby]
----
# .rubocop.yml
# RSpec/NoExpectationExample:
# AllowedPatterns:
# - ^expect_
# - ^assert_
----

[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
| `^expect_`, `^assert_`
| Array
|===

=== References

* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/NoExpectationExample
Expand Down
48 changes: 39 additions & 9 deletions lib/rubocop/cop/rspec/no_expectation_example.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,35 @@ module RSpec
# expect(a?).to be(true)
# end
#
# This cop can be customized with an allowed expectation methods pattern
# with an `AllowedPatterns` option. ^expect_ and ^assert_ are allowed
# by default.
#
# @example `AllowedPatterns` configuration
#
# # .rubocop.yml
# # RSpec/NoExpectationExample:
# # AllowedPatterns:
# # - ^expect_
# # - ^assert_
#
# @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)
Expand All @@ -41,26 +69,28 @@ class NoExpectationExample < Base
}
PATTERN

# @!method including_any_expectation?(node)
# @!method includes_expectation?(node)
# @param [RuboCop::AST::Node] node
# @return [Boolean]
def_node_search(
:including_any_expectation?,
send_pattern('#Expectations.all')
)
def_node_search :includes_expectation?, <<~PATTERN
{
#{send_pattern('#Expectations.all')}
(send nil? `#matches_allowed_pattern?)
}
PATTERN

# @!method including_any_skip_example?(node)
# @!method includes_skip_example?(node)
# @param [RuboCop::AST::Node] node
# @return [Boolean]
def_node_search :including_any_skip_example?, <<~PATTERN
def_node_search :includes_skip_example?, <<~PATTERN
(send nil? {:pending :skip} ...)
PATTERN

# @param [RuboCop::AST::BlockNode] node
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 includes_expectation?(node)
return if includes_skip_example?(node)

add_offense(node)
end
Expand Down
47 changes: 47 additions & 0 deletions spec/rubocop/cop/rspec/no_expectation_example_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,53 @@
end
end

context 'when `AllowedPatterns: [^expect_]`' do
let(:cop_config) { { 'AllowedPatterns' => ['^expect_'] } }

context 'when only allowed pattern methods are used' do
it 'registers no offenses' do
expect_no_offenses(<<~RUBY)
it { expect_something }
RUBY
end
end

context 'when 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 'when nested allowed pattern methods and other method are used' do
it 'registers no offenses' do
expect_no_offenses(<<~RUBY)
it do
do_something
some_patterns.each do
expect_something
end
do_something
end
RUBY
end
end

context 'when 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
Expand Down

0 comments on commit 9a96177

Please sign in to comment.