Skip to content

Commit

Permalink
Add new RSpec/ExpectInHook cop
Browse files Browse the repository at this point in the history
  • Loading branch information
pocke committed Aug 18, 2017
1 parent e370647 commit 6647b14
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -11,6 +11,7 @@
* Add `RSpec/VoidExpect` cop. ([@pocke][])
* Change HookArgument cop to detect when hook has a receiver. ([@pocke][])
* Add `RSpec/PredicateMatcher` cop. ([@pocke][])
* Add `RSpec/ExpectInHook` cop. ([@pocke][])

## 1.15.1 (2017-04-30)

Expand Down
5 changes: 5 additions & 0 deletions config/default.yml
Expand Up @@ -113,6 +113,11 @@ RSpec/ExpectActual:
- spec/routing/**/*
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectActual

RSpec/ExpectInHook:
Enabled: true
Description: Do not use `expect` in hooks such as `before`.
StyleGuide: http://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ExpectInHook

RSpec/ExpectOutput:
Description: Checks for opportunities to use `expect { ... }.to output`.
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop-rspec.rb
Expand Up @@ -38,6 +38,7 @@
require 'rubocop/cop/rspec/example_length'
require 'rubocop/cop/rspec/example_wording'
require 'rubocop/cop/rspec/expect_actual'
require 'rubocop/cop/rspec/expect_in_hook'
require 'rubocop/cop/rspec/expect_output'
require 'rubocop/cop/rspec/factory_girl/dynamic_attribute_defined_statically'
require 'rubocop/cop/rspec/file_path'
Expand Down
57 changes: 57 additions & 0 deletions lib/rubocop/cop/rspec/expect_in_hook.rb
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module RuboCop
module Cop
module RSpec
# Do not use `expect` in hooks such as `before`.
#
# @example
# # 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
#
# # good
# it do
# expect_any_instance_of(Something).to receive(:foo)
# end
class ExpectInHook < Cop
MSG = 'Do not use `%<expect>s` in `%<hook>s` hook'.freeze
HOOKS = Hooks::ALL.node_pattern_union.freeze

def on_block(node)
hook(node) do |hook_name, body|
expect(body) do |expect|
add_offense(expect, :selector,
message(expect.method_name, hook_name))
end
end
end

private

def message(expect, hook)
format(MSG, expect: expect, hook: hook)
end

def_node_matcher :hook, <<-PATTERN
(block (send _ $#{HOOKS} ...) _ $!nil)
PATTERN

def_node_search :expect, <<-PATTERN
(send nil {:expect :expect_any_instance_of} ...)
PATTERN
end
end
end
end
63 changes: 63 additions & 0 deletions spec/rubocop/cop/rspec/expect_in_hook_spec.rb
@@ -0,0 +1,63 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::RSpec::ExpectInHook do
subject(:cop) { described_class.new }

it 'adds an offense for `expect` in `before` hook' do
expect_offense(<<-RUBY)
before do
expect(something).to eq('foo')
^^^^^^ Do not use `expect` in `before` hook
expect_any_instance_of(Something).to receive(:foo)
^^^^^^^^^^^^^^^^^^^^^^ Do not use `expect_any_instance_of` in `before` hook
end
RUBY
end

it 'adds an offense for `expect` in `after` hook' do
expect_offense(<<-RUBY)
after do
expect(something).to eq('foo')
^^^^^^ Do not use `expect` in `after` hook
expect_any_instance_of(Something).to receive(:foo)
^^^^^^^^^^^^^^^^^^^^^^ Do not use `expect_any_instance_of` in `after` hook
end
RUBY
end

it 'adds an offense for `expect` in `around` hook' do
expect_offense(<<-RUBY)
around do
expect(something).to eq('foo')
^^^^^^ Do not use `expect` in `around` hook
expect_any_instance_of(Something).to receive(:foo)
^^^^^^^^^^^^^^^^^^^^^^ Do not use `expect_any_instance_of` in `around` hook
end
RUBY
end

it 'accepts an empty `before` hook' do
expect_no_offenses(<<-RUBY)
before do
end
RUBY
end

it 'accepts `allow` in `before` hook' do
expect_no_offenses(<<-RUBY)
before do
allow(something).to receive(:foo)
allow_any_instance_of(something).to receive(:foo)
end
RUBY
end

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

0 comments on commit 6647b14

Please sign in to comment.