Skip to content

Commit

Permalink
Merge pull request #932 from andrykonchin/add-top-level-group-callback
Browse files Browse the repository at this point in the history
RSpec/SubjectStub. Add top level group callback
  • Loading branch information
pirj committed Jun 14, 2020
2 parents e970b6a + 38fa7f3 commit 3030ba8
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 9 deletions.
1 change: 1 addition & 0 deletions lib/rubocop-rspec.rb
Expand Up @@ -13,6 +13,7 @@
require_relative 'rubocop/rspec/wording'
require_relative 'rubocop/rspec/language'
require_relative 'rubocop/rspec/language/node_pattern'
require_relative 'rubocop/rspec/top_level_group'
require_relative 'rubocop/rspec/concept'
require_relative 'rubocop/rspec/example_group'
require_relative 'rubocop/rspec/example'
Expand Down
12 changes: 3 additions & 9 deletions lib/rubocop/cop/rspec/subject_stub.rb
Expand Up @@ -22,6 +22,8 @@ module RSpec
# end
#
class SubjectStub < Cop
include RuboCop::RSpec::TopLevelGroup

MSG = 'Do not stub methods of the object under test.'

# @!method subject(node)
Expand Down Expand Up @@ -75,11 +77,7 @@ class SubjectStub < Cop
} ...)
PATTERN

def on_block(node)
return unless example_group?(node)
return if (processed_example_groups & node.ancestors).any?

processed_example_groups << node
def on_top_level_group(node)
@explicit_subjects = find_all_explicit_subjects(node)

find_subject_expectations(node) do |stub|
Expand All @@ -89,10 +87,6 @@ def on_block(node)

private

def processed_example_groups
@processed_example_groups ||= Set.new
end

def find_all_explicit_subjects(node)
node.each_descendant(:block).with_object({}) do |child, h|
name = subject(child)
Expand Down
44 changes: 44 additions & 0 deletions lib/rubocop/rspec/top_level_group.rb
@@ -0,0 +1,44 @@
# frozen_string_literal: true

module RuboCop
module RSpec
# Helper methods for top level example group cops
module TopLevelGroup
extend RuboCop::NodePattern::Macros
include RuboCop::RSpec::Language

def_node_matcher :example_or_shared_group?,
(ExampleGroups::ALL + SharedGroups::ALL).block_pattern

def on_block(node)
return unless respond_to?(:on_top_level_group)
return unless top_level_group?(node)

on_top_level_group(node)
end

private

def top_level_group?(node)
top_level_groups.include?(node)
end

def top_level_groups
@top_level_groups ||=
top_level_nodes.select { |n| example_or_shared_group?(n) }
end

def top_level_nodes
if root_node.begin_type?
root_node.children
else
[root_node]
end
end

def root_node
processed_source.ast
end
end
end
end
42 changes: 42 additions & 0 deletions spec/rubocop/cop/rspec/subject_stub_spec.rb
Expand Up @@ -321,4 +321,46 @@
end
RUBY
end

it 'flags when there are several top level example groups' do
expect_offense(<<-RUBY)
RSpec.describe Foo do
subject(:foo) { described_class.new }
specify do
expect(foo).to eq(foo)
end
end
RSpec.describe Bar do
subject(:bar) { described_class.new }
specify do
allow(bar).to receive(:bar)
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not stub methods of the object under test.
end
end
RUBY
end

describe 'top level example groups' do
%i[
describe xdescribe fdescribe
context xcontext fcontext
feature xfeature ffeature
example_group
shared_examples shared_examples_for shared_context
].each do |method|
it "flags in top level #{method}" do
expect_offense(<<-RUBY)
RSpec.#{method} '#{method}' do
it 'uses an implicit subject' do
expect(subject).to receive(:bar)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not stub methods of the object under test.
end
end
RUBY
end
end
end
end

0 comments on commit 3030ba8

Please sign in to comment.