Skip to content

Commit

Permalink
Merge pull request #1894 from rubocop/backport-pr-1885
Browse files Browse the repository at this point in the history
Backport `RSpec/ExpectInLet` cop to v2 branch
  • Loading branch information
pirj authored Jun 2, 2024
2 parents cd279a8 + 72846b0 commit 3d97a57
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ RSpec/Eq:
Enabled: true
RSpec/ExcessiveDocstringSpacing:
Enabled: true
RSpec/ExpectInLet:
Enabled: true
RSpec/IdenticalEqualityAssertion:
Enabled: true
RSpec/IndexedLet:
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Master (Unreleased)

- Add new `RSpec/ExpectInLet` cop. ([@yasu551])

## 2.29.2 (2024-05-02)

- Fix beginless and endless range bug for RepeatedIncludeExample cop. ([@hasghari])
Expand Down Expand Up @@ -976,6 +978,7 @@ Compatibility release so users can upgrade RuboCop to 0.51.0. No new features.
[@twalpole]: https://github.com/twalpole
[@vzvu3k6k]: https://github.com/vzvu3k6k
[@walf443]: https://github.com/walf443
[@yasu551]: https://github.com/yasu551
[@ybiquitous]: https://github.com/ybiquitous
[@ydah]: https://github.com/ydah
[@yevhene]: https://github.com/yevhene
Expand Down
6 changes: 6 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,12 @@ RSpec/ExpectInHook:
VersionAdded: '1.16'
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInHook

RSpec/ExpectInLet:
Description: Do not use `expect` in let.
Enabled: pending
VersionAdded: "<<next>>"
Reference: https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInLet

RSpec/ExpectOutput:
Description: Checks for opportunities to use `expect { ... }.to output`.
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
* xref:cops_rspec.adoc#rspecexpectactual[RSpec/ExpectActual]
* xref:cops_rspec.adoc#rspecexpectchange[RSpec/ExpectChange]
* xref:cops_rspec.adoc#rspecexpectinhook[RSpec/ExpectInHook]
* xref:cops_rspec.adoc#rspecexpectinlet[RSpec/ExpectInLet]
* xref:cops_rspec.adoc#rspecexpectoutput[RSpec/ExpectOutput]
* xref:cops_rspec.adoc#rspecfilepath[RSpec/FilePath]
* xref:cops_rspec.adoc#rspecfocus[RSpec/Focus]
Expand Down
33 changes: 33 additions & 0 deletions docs/modules/ROOT/pages/cops_rspec.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2042,6 +2042,39 @@ end
* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInHook
== RSpec/ExpectInLet
|===
| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed
| Pending
| Yes
| No
| <<next>>
| -
|===
Do not use `expect` in let.
=== Examples
[source,ruby]
----
# bad
let(:foo) do
expect(something).to eq 'foo'
end
# good
it do
expect(something).to eq 'foo'
end
----
=== References
* https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInLet
== RSpec/ExpectOutput
|===
Expand Down
44 changes: 44 additions & 0 deletions lib/rubocop/cop/rspec/expect_in_let.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true

module RuboCop
module Cop
module RSpec
# Do not use `expect` in let.
#
# @example
# # bad
# let(:foo) do
# expect(something).to eq 'foo'
# end
#
# # good
# it do
# expect(something).to eq 'foo'
# end
#
class ExpectInLet < Base
MSG = 'Do not use `%<expect>s` in let'

# @!method expectation(node)
def_node_search :expectation, '(send nil? #Expectations.all ...)'

def on_block(node)
return unless let?(node)
return if node.body.nil?

expectation(node.body) do |expect|
add_offense(expect.loc.selector, message: message(expect))
end
end

alias on_numblock on_block

private

def message(expect)
format(MSG, expect: expect.method_name)
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/rspec_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
require_relative 'rspec/expect_actual'
require_relative 'rspec/expect_change'
require_relative 'rspec/expect_in_hook'
require_relative 'rspec/expect_in_let'
require_relative 'rspec/expect_output'
require_relative 'rspec/file_path'
require_relative 'rspec/focus'
Expand Down
57 changes: 57 additions & 0 deletions spec/rubocop/cop/rspec/expect_in_let_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::RSpec::ExpectInLet do
it 'adds an offense for `expect` in let' do
expect_offense(<<~RUBY)
let(:foo) do
expect(something).to eq 'foo'
^^^^^^ Do not use `expect` in let
end
RUBY
end

it 'adds an offense for `is_expected` in let' do
expect_offense(<<~RUBY)
let(:foo) do
is_expected.to eq 'foo'
^^^^^^^^^^^ Do not use `is_expected` in let
end
RUBY
end

it 'adds an offense for `expect_any_instance_of` in let' do
expect_offense(<<~RUBY)
let(:foo) do
expect_any_instance_of(Something).to receive :foo
^^^^^^^^^^^^^^^^^^^^^^ Do not use `expect_any_instance_of` in let
end
RUBY
end

it 'adds offenses for multiple expectations in let' do
expect_offense(<<~RUBY)
let(:foo) do
expect(something).to eq 'foo'
^^^^^^ Do not use `expect` in let
is_expected.to eq 'foo'
^^^^^^^^^^^ Do not use `is_expected` in let
end
RUBY
end

it 'accepts an empty let' do
expect_no_offenses(<<~RUBY)
let(:foo) {}
RUBY
end

it 'accepts `expect` in `it`' do
expect_no_offenses(<<~RUBY)
it do
expect(something).to eq 'foo'
is_expected.to eq 'foo'
expect_any_instance_of(Something).to receive :foo
end
RUBY
end
end

0 comments on commit 3d97a57

Please sign in to comment.