Class: RuboCop::Cop::RSpec::EmptyExampleGroup

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Includes:
RangeHelp
Defined in:
lib/rubocop/cop/rspec/empty_example_group.rb

Overview

Checks if an example group does not include any tests.

Examples:

usage

# 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

Constant Summary collapse

MSG =
'Empty example group detected.'

Instance Method Summary collapse

Methods inherited from Base

inherited, #on_new_investigation

Methods included from RSpec::Language::NodePattern

#block_or_numblock_pattern, #block_pattern, #numblock_pattern, #send_pattern

Methods included from RSpec::Language

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

Instance Method Details

#example_group_body(node) {|RuboCop::AST::Node| ... } ⇒ Object

Match example group blocks and yield their body

Examples:

source that matches

describe 'example group' do
  it { is_expected.to be }
end

Parameters:

  • node (RuboCop::AST::Node)

Yields:

  • (RuboCop::AST::Node)

    example group body



55
56
57
# File 'lib/rubocop/cop/rspec/empty_example_group.rb', line 55

def_node_matcher :example_group_body, <<~PATTERN
  (block (send #rspec? #ExampleGroups.all ...) args $_)
PATTERN

#example_or_group_or_include?(node) ⇒ Array<RuboCop::AST::Node>

Match examples, example groups and includes

Examples:

source that matches

it { is_expected.to fly }
describe('non-empty example groups too') { }
it_behaves_like 'an animal'
it_behaves_like('a cat') { let(:food) { 'milk' } }
it_has_root_access
skip
it 'will be implemented later'

Parameters:

  • node (RuboCop::AST::Node)

Returns:

  • (Array<RuboCop::AST::Node>)

    matching nodes



73
74
75
76
77
78
79
80
# File 'lib/rubocop/cop/rspec/empty_example_group.rb', line 73

def_node_matcher :example_or_group_or_include?, <<~PATTERN
  {
    (block
      (send #rspec? {#Examples.all #ExampleGroups.all #Includes.all} ...)
    ...)
    (send nil? {#Examples.all #Includes.all} ...)
  }
PATTERN

#examples?(node) ⇒ Array<RuboCop::AST::Node>

Matches examples defined in scopes where they could run

Examples:

source that matches

it { expect(myself).to be_run }
describe { it { i_run_as_well } }

source that does not match

before { it { whatever here won't run anyway } }

Parameters:

  • node (RuboCop::AST::Node)

Returns:

  • (Array<RuboCop::AST::Node>)

    matching nodes



130
131
132
133
134
135
136
# File 'lib/rubocop/cop/rspec/empty_example_group.rb', line 130

def_node_matcher :examples?, <<~PATTERN
  {
    #examples_directly_or_in_block?
    (begin <#examples_directly_or_in_block? ...>)
    (begin <#examples_in_branches? ...>)
  }
PATTERN

#examples_directly_or_in_block?(node) ⇒ Array<RuboCop::AST::Node>

Match examples or examples inside blocks

Examples:

source that matches

it { expect(drink).to be_cold }
context('when winter') { it { expect(drink).to be_hot } }
(1..5).each { |divisor| it { is_expected.to divide_by(divisor) } }

Parameters:

  • node (RuboCop::AST::Node)

Returns:

  • (Array<RuboCop::AST::Node>)

    matching nodes



111
112
113
114
115
116
# File 'lib/rubocop/cop/rspec/empty_example_group.rb', line 111

def_node_matcher :examples_directly_or_in_block?, <<~PATTERN
  {
    #example_or_group_or_include?
    #examples_inside_block?
  }
PATTERN

#examples_inside_block?(node) ⇒ Array<RuboCop::AST::Node>

Match examples defined inside a block which is not a hook

Examples:

source that matches

%w(r g b).each do |color|
  it { is_expected.to have_color(color) }
end

source that does not match

before do
  it { is_expected.to fall_into_oblivion }
end

Parameters:

  • node (RuboCop::AST::Node)

Returns:

  • (Array<RuboCop::AST::Node>)

    matching nodes



97
98
99
# File 'lib/rubocop/cop/rspec/empty_example_group.rb', line 97

def_node_matcher :examples_inside_block?, <<~PATTERN
  (block !(send nil? #Hooks.all ...) _ #examples?)
PATTERN

#on_block(node) ⇒ Object

rubocop:disable InternalAffairs/NumblockHandler



138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/rubocop/cop/rspec/empty_example_group.rb', line 138

def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
  return if node.each_ancestor(:def, :defs).any?
  return if node.each_ancestor(:block).any? { |block| example?(block) }

  example_group_body(node) do |body|
    next unless offensive?(body)

    add_offense(node.send_node) do |corrector|
      corrector.remove(removed_range(node))
    end
  end
end