Class: RuboCop::Cop::Vicenzo::RSpec::SubjectDefinedAsLet

Inherits:
RSpec::Base
  • Object
show all
Includes:
DescribedMethod, ExpectationTarget, PremiseTracking
Defined in:
lib/rubocop/cop/vicenzo/rspec/subject_defined_as_let.rb

Overview

A let the expectations assert on, in an example group that declares no subject, is the subject wearing another name. Declare it as one.

The subject of a specification is what the sentences are about. When every expectation in a group reads expect(service), service is that - and calling it a let costs the group the one declaration that says so out loud, leaves is_expected unavailable, and hides the redefinitions from the cops that watch subjects for a living.

This says nothing about what the subject should hold - that is Vicenzo/RSpec/SubjectIsMethodResult's question, and it already knows the conventions the project declared. The two compose without arguing: declare the subject, and if the value it holds is not fit to be the subject either, the sibling cop says so next.

AllowedMethods exempts a let whose value comes from calling one of the listed methods, for the projects where such a definition is deliberately a let. It ships empty.

Examples:

# bad - every expectation is about `service`, yet the group declares no subject
describe '.call' do
  context 'when the order is unknown' do
    let(:service) { described_class.(order_id: 42) }

    it { expect(service).to be_failure }
  end
end

# good - the subject is declared, and `is_expected` reads the sentence back
describe '.call' do
  context 'when the order is unknown' do
    subject(:service) { described_class.(order_id: 42) }

    it { is_expected.to be_failure }
  end
end

a let the expectations only read through is a premise

# good - the expectation is about the book, not about the author
describe '#author' do
  subject(:book) { create(:book, author:) }

  let(:author) { create(:author) }

  it { expect(book.author).to eq(author) }
end

Constant Summary collapse

MSG =
'Let `:%<name>s` is what the expectations assert on, so it is the subject. ' \
'Declare it with `subject(:%<name>s)`.'

Constants included from PremiseTracking

PremiseTracking::SETUP_HOOKS

Constants included from ExpectationTarget

ExpectationTarget::EXPECTATION_RUNNERS, ExpectationTarget::MESSAGE_MATCHERS

Constants included from DescribedMethod

DescribedMethod::BARE_METHOD_DESCRIPTION, DescribedMethod::PREFIXED_METHOD_DESCRIPTION

Instance Method Summary collapse

Methods included from PremiseTracking

#premise_name, #root_receiver_name

Instance Method Details

#on_block(node) ⇒ Object Also known as: on_numblock, on_itblock



63
64
65
66
67
68
69
# File 'lib/rubocop/cop/vicenzo/rspec/subject_defined_as_let.rb', line 63

def on_block(node)
  name = subject_in_disguise(node)

  return if name.nil?

  add_offense(node.send_node, message: format(MSG, name:))
end