Class: RuboCop::Cop::RSpec::LeakyLocalVariable

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/rspec/leaky_local_variable.rb

Overview

Checks for local variables from outer scopes used inside examples.

Local variables assigned outside an example but used within it act as shared state, which can make tests non-deterministic.

Examples:

# bad - outside variable used in a hook
user = create(:user)

before { user.update(admin: true) }

# good
let(:user) { create(:user) }

before { user.update(admin: true) }

# bad - outside variable used in an example
user = create(:user)

it 'is persisted' do
  expect(user).to be_persisted
end

# good
let(:user) { create(:user) }

it 'is persisted' do
  expect(user).to be_persisted
end

# also good - assigning the variable within the example
it 'is persisted' do
  user = create(:user)

  expect(user).to be_persisted
end

# bad - outside variable passed to included examples
attrs = ['foo', 'bar']

it_behaves_like 'some examples', attrs

# good
it_behaves_like 'some examples' do
  let(:attrs) { ['foo', 'bar'] }
end

# good - when variable is used only as example description
attribute = 'foo'

it "#{attribute} is persisted" do
  expectations
end

# good - when variable is used only in example metadata
skip_message = 'not yet implemented'

it 'does something', skip: skip_message do
  expectations
end

# good - when variable is used only to include other examples
examples = foo ? 'some examples' : 'other examples'

it_behaves_like examples, another_argument

Constant Summary collapse

MSG =
'Do not use local variables defined outside of ' \
'examples inside of them.'

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

inherited, #on_new_investigation

Methods included from RSpec::Language

#example?, #example_group?, #example_group_with_body?, #explicit_rspec?, #hook?, #include?, #let?, #rspec?, #shared_group?, #spec_group?, #subject?

Class Method Details

.joining_forcesObject



86
87
88
# File 'lib/rubocop/cop/rspec/leaky_local_variable.rb', line 86

def self.joining_forces
  VariableForce
end

Instance Method Details

#after_leaving_scope(scope, _variable_table) ⇒ Object



90
91
92
# File 'lib/rubocop/cop/rspec/leaky_local_variable.rb', line 90

def after_leaving_scope(scope, _variable_table)
  scope.variables.each_value { |variable| check_references(variable) }
end

#example_method?(node) ⇒ Object



77
78
79
# File 'lib/rubocop/cop/rspec/leaky_local_variable.rb', line 77

def_node_matcher :example_method?, "(send nil? #Examples.all _)\n"

#includes_method?(node) ⇒ Object



82
83
84
# File 'lib/rubocop/cop/rspec/leaky_local_variable.rb', line 82

def_node_matcher :includes_method?, "(send nil? #Includes.all ...)\n"