Class: RuboCop::Cop::Vicenzo::RSpec::DynamicExampleGeneration

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

Overview

Do not use iteration to dynamically generate example groups or examples.

Dynamic generation makes tests hard to find, hard to read, and creates pressure to add conditional logic (e.g. if variable == :x) when not all iterations share the same conditions. Write explicit, static contexts instead — one context per case.

Examples:

# bad

[:admin, :driver].each do |role|
  context "when role is #{role}" do
    it 'does something' do
      ...
    end
  end
end

# good

context 'when role is admin' do
  let(:role) { :admin }

  it 'does something' do
    ...
  end
end

context 'when role is driver' do
  let(:role) { :driver }

  it 'does something' do
    ...
  end
end

Constant Summary collapse

MSG =
'Do not use iteration to dynamically generate example groups or examples. ' \
'Write explicit, static contexts instead.'
ENUMERATION_METHODS =
%i[each each_with_index each_with_object map flat_map].freeze
EXAMPLE_GROUP_DSL =
%i[
  context describe feature experiment
  it specify example scenario focus
  let let! subject subject! before after around
  shared_examples shared_context shared_examples_for
].freeze

Instance Method Summary collapse

Instance Method Details

#enumeration_block?(node) ⇒ Object



56
57
58
59
60
# File 'lib/rubocop/cop/vicenzo/rspec/dynamic_example_generation.rb', line 56

def_node_matcher :enumeration_block?, <<~PATTERN
  (block
    (send _ {#{ENUMERATION_METHODS.map(&:inspect).join(' ')}} ...)
    ...)
PATTERN

#example_group_dsl_call?(node) ⇒ Object



63
64
65
# File 'lib/rubocop/cop/vicenzo/rspec/dynamic_example_generation.rb', line 63

def_node_matcher :example_group_dsl_call?, <<~PATTERN
  (block (send nil? {#{EXAMPLE_GROUP_DSL.map(&:inspect).join(' ')}} ...) ...)
PATTERN

#on_block(node) ⇒ Object Also known as: on_numblock



67
68
69
70
71
72
# File 'lib/rubocop/cop/vicenzo/rspec/dynamic_example_generation.rb', line 67

def on_block(node)
  return unless enumeration_block?(node)
  return unless contains_example_group_dsl?(node)

  add_offense(node.send_node)
end