Checks that left braces for adjacent single line lets are aligned.
# bad let(:foobar) < blahblah >let(:baz) < bar >let(:a) < b ># good let(:foobar) < blahblah >let(:baz) < bar >let(:a)
Checks that right braces for adjacent single line lets are aligned.
# bad let(:foobar) < blahblah >let(:baz) < bar >let(:a) < b ># good let(:foobar) < blahblah >let(:baz) < bar >let(:a)
Check that instances are not being stubbed globally.
Prefer instance doubles over stubbing any instance of a class
# bad describe MyClass do before < allow_any_instance_of(MyClass).to receive(:foo) >end # good describe MyClass do let(:my_instance) < instance_double(MyClass) >before do allow(MyClass).to receive(:new).and_return(my_instance) allow(my_instance).to receive(:foo) end end
Checks that around blocks actually run the test.
# bad around do some_method end around do |test| some_method end # good around do |test| some_method test.call end around do |test| some_method test.run end
Check for expectations where be is used without argument.
The be matcher is too generic, as it pass on everything that is not nil or false. If that is the exact intend, use be_truthy . In all other cases it’s better to specify what exactly is the expected value.
# bad expect(foo).to be # good expect(foo).to be_truthy expect(foo).to be 1.0 expect(foo).to be(true)
Prefer using be_empty when checking for an empty array.
# bad expect(array).to contain_exactly expect(array).to match_array([]) # good expect(array).to be_empty
Check for expectations where be(…) can replace eq(…) .
The be matcher compares by identity while the eq matcher compares using == . Booleans and nil can be compared by identity and therefore the be matcher is preferable as it is a more strict test.
This cop is unsafe because it changes how values are compared.
# bad expect(foo).to eq(true) expect(foo).to eq(false) expect(foo).to eq(nil) # good expect(foo).to be(true) expect(foo).to be(false) expect(foo).to be(nil)
Check for expectations where be(…) can replace eql(…) .
The be matcher compares by identity while the eql matcher compares using eql? . Integers, floats, booleans, symbols, and nil can be compared by identity and therefore the be matcher is preferable as it is a more strict test.
This cop only looks for instances of expect(…).to eql(…) . We do not check to_not or not_to since !eql? is more strict than !equal? . We also do not try to flag eq because if a == b , and b is comparable by identity, a is still not necessarily the same type as b since the #== operator can coerce objects for comparison.
This cop is unsafe because it changes how values are compared.
# bad expect(foo).to eql(1) expect(foo).to eql(1.0) expect(foo).to eql(true) expect(foo).to eql(false) expect(foo).to eql(:bar) expect(foo).to eql(nil) # good expect(foo).to be(1) expect(foo).to be(1.0) expect(foo).to be(true) expect(foo).to be(false) expect(foo).to be(:bar) expect(foo).to be(nil)
Ensures a consistent style is used when matching nil .
You can either use the more specific be_nil matcher, or the more generic be matcher with a nil argument.
This cop can be configured using the EnforcedStyle option
# bad expect(foo).to be(nil) # good expect(foo).to be_nil
# bad expect(foo).to be_nil # good expect(foo).to be(nil)
Check that before/after(:all/:context) isn’t being used.
# bad - Faster but risk of state leaking between examples describe MyClass do before(:all) < Widget.create >after(:context) < Widget.delete_all >end # good - Slower but examples are properly isolated describe MyClass do before(:each) < Widget.create >after(:each) < Widget.delete_all >end
**/spec/spec_helper.rb , **/spec/rails_helper.rb , **/spec/support/**/*.rb
Prefer negated matchers over to change.by(0) .
In the case of composite expectations, cop suggest using the negation matchers of RSpec::Matchers#change .
By default the cop does not support autocorrect of compound expectations, but if you set the negated matcher for change , e.g. not_change with the NegatedMatcher option, the cop will perform the autocorrection.
# bad expect < run >.to change(Foo, :bar).by(0) expect < run >.to change < Foo.bar >.by(0) # bad - compound expectations (does not support autocorrection) expect < run >.to change(Foo, :bar).by(0) .and change(Foo, :baz).by(0) expect < run >.to change < Foo.bar >.by(0) .and change < Foo.baz >.by(0) # good expect < run >.not_to change(Foo, :bar) expect < run >.not_to change < Foo.bar ># good - compound expectations define_negated_matcher :not_change, :change expect < run >.to not_change(Foo, :bar) .and not_change(Foo, :baz) expect < run >.to not_change < Foo.bar >.and not_change
# bad (support autocorrection to good case) expect < run >.to change(Foo, :bar).by(0) .and change(Foo, :baz).by(0) expect < run >.to change < Foo.bar >.by(0) .and change < Foo.baz >.by(0) # good define_negated_matcher :not_change, :change expect < run >.to not_change(Foo, :bar) .and not_change(Foo, :baz) expect < run >.to not_change < Foo.bar >.and not_change
Enforces consistent use of be_a or be_kind_of .
# bad expect(object).to be_kind_of(String) expect(object).to be_a_kind_of(String) # good expect(object).to be_a(String) expect(object).to be_an(String)
# bad expect(object).to be_a(String) expect(object).to be_an(String) # good expect(object).to be_kind_of(String) expect(object).to be_a_kind_of(String)
Checks where contain_exactly is used.
This cop checks for the following: - Prefer match_array when matching array values. - Prefer be_empty when using contain_exactly with no arguments.
# bad it < is_expected.to contain_exactly(*array1, *array2) ># good it < is_expected.to match_array(array1 + array2) ># good it
context should not be used for specifying methods.
# bad context '#foo_bar' do # . end context '.foo_bar' do # . end # good describe '#foo_bar' do # . end describe '.foo_bar' do # . end
Checks that context docstring starts with an allowed prefix.
The default list of prefixes is minimal. Users are encouraged to tailor the configuration to meet project needs. Other acceptable prefixes may include if , unless , for , before , after , or during . They may consist of multiple words if desired.
This cop can be customized allowed context description pattern with AllowedPatterns . By default, there are no checking by pattern.
# .rubocop.yml # RSpec/ContextWording: # Prefixes: # - when # - with # - without # - if # - unless # - for
# bad context 'the display name not present' do # . end # good context 'when the display name is not present' do # . end
# .rubocop.yml # RSpec/ContextWording: # AllowedPatterns: # - とき$
# bad context '条件を満たす' do # . end # good context '条件を満たすとき' do # . end
when , with , without
Check that the first argument to the top-level describe is a constant.
It can be configured to ignore strings when certain metadata is passed.
Ignores Rails and Aruba type metadata by default.
# .rubocop.yml # RSpec/DescribeClass: # IgnoredMetadata: # type: # - request # - controller
# bad describe 'Do something' do end # good describe TestedClass do subject < described_class >end describe 'TestedClass::VERSION' do subject < Object.const_get(self.class.description) >end describe "A feature example", type: :feature do end
**/spec/features/**/* , **/spec/requests/**/* , **/spec/routing/**/* , **/spec/system/**/* , **/spec/views/**/*
Checks that the second argument to describe specifies a method.
# bad describe MyClass, 'do something' do end # good describe MyClass, '#my_instance_method' do end describe MyClass, '.my_class_method' do end
Avoid describing symbols.
# bad describe :my_method do # . end # good describe '#my_method' do # . end
Checks that tests use described_class .
If the first argument of describe is a class, the class is exposed to each example via described_class.
This cop can be configured using the EnforcedStyle , SkipBlocks and OnlyStaticConstants options. OnlyStaticConstants is only relevant when EnforcedStyle is described_class .
There’s a known caveat with rspec-rails’s controller helper that runs its block in a different context, and described_class is not available to it. SkipBlocks option excludes detection in all non-RSpec related blocks.
To narrow down this setting to only a specific directory, it is possible to use an overriding configuration file local to that directory.
# bad describe MyClass do subject < MyClass.do_something >end # good describe MyClass do subject < described_class.do_something >end
# good describe MyClass do subject < MyClass::CONSTANT >end
# bad describe MyClass do subject < MyClass::CONSTANT >end
# bad describe MyClass do subject < described_class.do_something >end # good describe MyClass do subject < MyClass.do_something >end
# spec/controllers/.rubocop.yml # RSpec/DescribedClass: # SkipBlocks: true # acceptable describe MyConcern do controller(ApplicationController) do include MyConcern end end
Avoid opening modules and defining specs within them.
# bad module MyModule RSpec.describe MyClass do # . end end # good RSpec.describe MyModule::MyClass do # . end
Enforces custom RSpec dialects.
A dialect can be based on the following RSpec methods:
By default all of the RSpec methods and aliases are allowed. By setting a config like:
RSpec/Dialect: PreferredMethods: context: describe
If you were previously using the RSpec/Capybara/FeatureMethods cop and want to keep disabling all Capybara-specific methods that have the same native RSpec method (e.g. are just aliases), use the following config:
RSpec/Dialect: PreferredMethods: background: :before scenario: :it xscenario: :xit given: :let given!: :let! feature: :describe
You can expect the following behavior:
# bad context 'display name presence' do # . end # good describe 'display name presence' do # . end
Avoid duplicated metadata.
# bad describe 'Something', :a, :a # good describe 'Something', :a
Command-line only (Unsafe)
Checks if an example group does not include any tests.
# bad describe Bacon do let(:bacon) < Bacon.new(chunkiness) >let(:chunkiness) < false >context 'extra chunky' do # flagged by rubocop let(:chunkiness) < true >end it 'is chunky' do expect(bacon.chunky?).to be_truthy end end # good describe Bacon do let(:bacon) < Bacon.new(chunkiness) >let(:chunkiness) < false >it 'is chunky' do expect(bacon.chunky?).to be_truthy end end # good describe Bacon do pending 'will add tests later' end
Checks for empty before and after hooks.
# bad before <> after do; end before(:all) do end after(:all) < ># good before < create_users >after do cleanup_users end before(:all) do create_feed end after(:all)
Checks if there is an empty line after example blocks.
# bad RSpec.describe Foo do it 'does this' do end it 'does that' do end end # good RSpec.describe Foo do it 'does this' do end it 'does that' do end end # fair - it's ok to have non-separated one-liners RSpec.describe Foo do it < one >it < two >end
# rubocop.yml # RSpec/EmptyLineAfterExample: # AllowConsecutiveOneLiners: false # bad RSpec.describe Foo do it < one >it < two >end
Checks if there is an empty line after example group blocks.
# bad RSpec.describe Foo do describe '#bar' do end describe '#baz' do end end # good RSpec.describe Foo do describe '#bar' do end describe '#baz' do end end
Checks if there is an empty line after the last let block.
# bad let(:foo) < bar >let(:something) < other >it < does_something ># good let(:foo) < bar >let(:something) < other >it
Checks if there is an empty line after hook blocks.
AllowConsecutiveOneLiners configures whether adjacent one-line definitions are considered an offense.
# bad before < do_something >it < does_something ># bad after < do_something >it < does_something ># bad around < |test| test.run >it < does_something ># good after < do_something >it < does_something ># fair - it's ok to have non-separated one-liners hooks around < |test| test.run >after < do_something >it
# rubocop.yml # RSpec/EmptyLineAfterHook: # AllowConsecutiveOneLiners: false # bad around < |test| test.run >after < do_something >it < does_something ># good around < |test| test.run >after < do_something >it
Checks if there is an empty line after subject block.
# bad subject(:obj) < described_class >let(:foo) < bar ># good subject(:obj) < described_class >let(:foo)
Avoid empty metadata hash.
# bad describe 'Something', <> # good describe 'Something'
Check that the output matcher is not called with an empty string.
# bad expect < foo >.to output('').to_stdout expect < bar >.not_to output('').to_stderr # good expect < foo >.not_to output.to_stdout expect < bar >.to output.to_stderr
Use eq instead of be == to compare objects.
# bad expect(foo).to be == 42 # good expect(foo).to eq 42
Checks for long examples.
A long example is usually more difficult to understand. Consider extracting out some behavior, e.g. with a let block, or a helper method.
You can set constructs you want to fold with CountAsOne . Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct will be counted as one line regardless of its actual size.
# bad it do service = described_class.new more_setup more_setup result = service.call expect(result).to be(true) end # good it do service = described_class.new result = service.call expect(result).to be(true) end
it do array = [ # +1 1, 2 ] hash = < # +3 key: 'value' >msg =
Checks for examples without a description.
RSpec allows for auto-generated example descriptions when there is no description provided or the description is an empty one. It is acceptable to use specify without a description
This cop removes empty descriptions. It also defines whether auto-generated description is allowed, based on the configured style.
This cop can be configured using the EnforcedStyle option
# always good specify do result = service.call expect(result).to be(true) end
# bad it('') < is_expected.to be_good >specify '' do result = service.call expect(result).to be(true) end # good it < is_expected.to be_good >specify do result = service.call expect(result).to be(true) end
# bad it('') < is_expected.to be_good >it do result = service.call expect(result).to be(true) end # good it
# bad it < is_expected.to be_good >it do result = service.call expect(result).to be(true) end
always_allow , single_line_only , disallow
Checks for common mistakes in example descriptions.
This cop will correct docstrings that begin with 'should' and 'it'. This cop will also look for insufficient examples and call them out.
The autocorrect is experimental - use with care! It can be configured with CustomTransform (e.g. have ⇒ has) and IgnoredWords (e.g. only).
Use the DisallowedExamples setting to prevent unclear or insufficient descriptions. Please note that this config will not be treated as case sensitive.
# bad it 'should find nothing' do end it 'will find nothing' do end # good it 'finds nothing' do end
# bad it 'it does things' do end # good it 'does things' do end
# bad it 'works' do end # good it 'marks the task as done' do end
Checks for excessive whitespace in example descriptions.
# bad it ' has excessive spacing ' do end # good it 'has excessive spacing' do end
# bad context ' when a condition is met ' do end # good context 'when a condition is met' do end
Checks for expect(…) calls containing literal values.
Autocorrection is performed when the expected is not a literal.
# bad expect(5).to eq(price) expect(/foo/).to eq(pattern) expect("John").to eq(name) # good expect(price).to eq(5) expect(pattern).to eq(/foo/) expect(name).to eq("John") # bad (not supported autocorrection) expect(false).to eq(true)
Checks for consistent style of change matcher.
Enforces either passing object and attribute as arguments to the matcher or passing a block that reads the attribute value.
This cop can be configured using the EnforcedStyle option.
# bad expect < run >.to change < Foo.bar >expect < run >.to change < foo.baz ># good expect < run >.to change(Foo, :bar) expect < run >.to change(foo, :baz) # also good when there are arguments or chained method calls expect < run >.to change < Foo.bar(:count) >expect < run >.to change
# bad expect < run >.to change(Foo, :bar) # good expect < run >.to change
Do not use expect in hooks such as before .
# bad before do expect(something).to eq 'foo' end # bad after do expect_any_instance_of(Something).to receive(:foo) end # good it do expect(something).to eq 'foo' end
Do not use expect in let.
# bad let(:foo) do expect(something).to eq 'foo' end # good it do expect(something).to eq 'foo' end
Checks for opportunities to use expect < … >.to output .
# bad $stdout = StringIO.new my_app.print_report $stdout = STDOUT expect($stdout.string).to eq('Hello World') # good expect < my_app.print_report >.to output('Hello World').to_stdout
Checks if examples are focused.
This cop does not support autocorrection in some cases.
# bad describe MyClass, focus: true do end describe MyClass, :focus do end fdescribe MyClass do end # good describe MyClass do end # bad fdescribe 'test' do; end # good describe 'test' do; end # bad fdescribe 'test' do; end # good describe 'test' do; end # bad shared_examples 'test', focus: true do; end # good shared_examples 'test' do; end # bad shared_context 'test', focus: true do; end # good shared_context 'test' do; end # bad (does not support autocorrection) focus 'test' do; end
Checks the arguments passed to before , around , and after .
This cop checks for consistent style when specifying RSpec hooks which run for each example. There are three supported styles: "implicit", "each", and "example." All styles have the same behavior.
# bad before(:each) do # . end # bad before(:example) do # . end # good before do # . end
# bad before(:example) do # . end # bad before do # . end # good before(:each) do # . end
# bad before(:each) do # . end # bad before do # . end # good before(:example) do # . end
implicit , each , example
Checks for before/around/after hooks that come after an example.
# bad it 'checks what foo does' do expect(foo).to be end before < prepare >after < clean_up ># good before < prepare >after < clean_up >it 'checks what foo does' do expect(foo).to be end
Checks for equality assertions with identical expressions on both sides.
# bad expect(foo.bar).to eq(foo.bar) expect(foo.bar).to eql(foo.bar) # good expect(foo.bar).to eq(2) expect(foo.bar).to eql(2)
Check that implicit block expectation syntax is not used.
Prefer using explicit block expectations.
# bad subject < -> < do_something >> it < is_expected.to change(something).to(new_value) ># good it 'changes something to a new value' do expect < do_something >.to change(something).to(new_value) end
Check that a consistent implicit expectation style is used.
This cop can be configured using the EnforcedStyle option and supports the --auto-gen-config flag.
# bad it < should be_truthy ># good it
# bad it < is_expected.to be_truthy ># good it
Checks for usage of implicit subject ( is_expected / should ).
This cop can be configured using the EnforcedStyle option
# bad it do is_expected.to be_truthy end # good it < is_expected.to be_truthy >it do expect(subject).to be_truthy end
# bad it do foo = 1 is_expected.to be_truthy end # good it do foo = 1 expect(subject).to be_truthy end it do is_expected.to be_truthy end
# bad it < is_expected.to be_truthy ># good it
# bad it < expect(subject).to be_truthy ># good it < is_expected.to be_truthy ># bad it do expect(subject).to be_truthy end # good it do is_expected.to be_truthy end # good it
single_line_only , single_statement_only , disallow , require_implicit
Do not set up test data using indexes (e.g., item_1 , item_2 ).
It makes reading the test harder because it’s not clear what exactly is tested by this particular example.
The configurable options AllowedIdentifiers and AllowedPatterns will also read those set in Naming/VariableNumber .
# bad let(:item_1) < create(:item) >let(:item_2) < create(:item) >let(:item1) < create(:item) >let(:item2) < create(:item) ># good let(:visible_item) < create(:item, visible: true) >let(:invisible_item)
# bad let(:item_1) < create(:item) >let(:item_2) < create(:item) >let(:item_3) < create(:item) ># good let(:item_1) < create(:item) >let(:item_2)
# good let(:item_1) < create(:item) >let(:item_2)
# good let(:item_1) < create(:item) >let(:item_2)
Checks for instance_double used with have_received .
# bad it do foo = instance_double(Foo).as_null_object expect(foo).to have_received(:bar) end # good it do foo = instance_spy(Foo) expect(foo).to have_received(:bar) end
Checks for instance variable usage in specs.
This cop can be configured with the option AssignmentOnly which will configure the cop to only register offenses on instance variable usage if the instance variable is also assigned within the spec
# bad describe MyClass do before < @foo = [] >it < expect(@foo).to be_empty >end # good describe MyClass do let(:foo) < [] >it < expect(foo).to be_empty >end
# rubocop.yml # RSpec/InstanceVariable: # AssignmentOnly: true # bad describe MyClass do before < @foo = [] >it < expect(@foo).to be_empty >end # allowed describe MyClass do it < expect(@foo).to be_empty >end # good describe MyClass do let(:foo) < [] >it < expect(foo).to be_empty >end
Check for specify with is_expected and one-liner expectations.
# bad specify < is_expected.to be_truthy ># good it < is_expected.to be_truthy ># good specify do # . end specify
Checks that only one it_behaves_like style is used.
# bad it_should_behave_like 'a foo' # good it_behaves_like 'a foo'
# bad it_behaves_like 'a foo' # good it_should_behave_like 'a foo'
Check that all matcher is used instead of iterating over an array.
# bad it 'validates users' do [user1, user2, user3].each < |user| expect(user).to be_valid >end # good it 'validates users' do expect([user1, user2, user3]).to all(be_valid) end
Enforce that subject is the first definition in the test.
# bad let(:params) < blah >subject < described_class.new(params) >before < do_something >subject < described_class.new(params) >it < expect_something >subject < described_class.new(params) >it < expect_something_else ># good subject < described_class.new(params) >let(:params) < blah ># good subject < described_class.new(params) >before < do_something ># good subject < described_class.new(params) >it < expect_something >it
Checks that no class, module, or constant is declared.
Constants, including classes and modules, when declared in a block scope, are defined in global namespace, and leak between examples.
If several examples may define a DummyClass , instead of being a blank slate class as it will be in the first example, subsequent examples will be reopening it and modifying its behavior in unpredictable ways. Even worse when a class that exists in the codebase is reopened.
Anonymous classes are fine, since they don’t result in global namespace name clashes.
# bad describe SomeClass do OtherClass = Struct.new CONSTANT_HERE = 'I leak into global namespace' end # good describe SomeClass do before do stub_const('OtherClass', Struct.new) stub_const('CONSTANT_HERE', 'I only exist during this example') end end
# bad describe SomeClass do class FooClass < described_class def double_that some_base_method * 2 end end it < expect(FooClass.new.double_that).to eq(4) >end # good - anonymous class, no constant needs to be defined describe SomeClass do let(:foo_class) do Class.new(described_class) do def double_that some_base_method * 2 end end end it < expect(foo_class.new.double_that).to eq(4) >end # good - constant is stubbed describe SomeClass do before do foo_class = Class.new(described_class) do def do_something end end stub_const('FooClass', foo_class) end it < expect(FooClass.new.double_that).to eq(4) >end
# bad describe SomeClass do module SomeModule class SomeClass def do_something end end end end # good describe SomeClass do before do foo_class = Class.new(described_class) do def do_something end end stub_const('SomeModule::SomeClass', foo_class) end end