class RuboCop::Cop::Airbnb::RspecDescribeOrContextUnderNamespace

This cop checks for Rspec describe or context method calls under a namespace. It can potentially cause autoloading to occur in a different order than it would have in development or production. This could cause flaky tests.

@example

# bad

# spec/foo/bar_spec.rb
module Foo
  describe Bar do
  end
end

# good

# spec/foo/bar_spec.rb do

describe Foo::Bar
end

Constants

DESCRIBE_OR_CONTEXT_UNDER_NAMESPACE_MSG
FIX_CODE_HELP_MSG
FIX_DESCRIBE_OR_CONTEXT_HELP_MSG

Public Instance Methods

get_described_class(node) click to toggle source
# File lib/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace.rb, line 96
def get_described_class(node)
  const_node = node.children[2]
  return unless const_node
  const_node.const_name
end
get_method_parent(node) click to toggle source
# File lib/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace.rb, line 102
def get_method_parent(node)
  const_node = node.children[0]
  return unless const_node
  const_node.const_name
end
get_module_name(node) click to toggle source
# File lib/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace.rb, line 90
def get_module_name(node)
  const_node = node.children[0]
  return unless const_node
  const_node.const_name
end
is_block?(node) click to toggle source
# File lib/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace.rb, line 108
def is_block?(node)
  node && [:block, :begin].include?(node.type)
end
is_spec_file?(path) click to toggle source
# File lib/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace.rb, line 86
def is_spec_file?(path)
  path.end_with?('_spec.rb')
end
on_module(node) click to toggle source
# File lib/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace.rb, line 38
def on_module(node)
  path = node.source_range.source_buffer.name
  return unless is_spec_file?(path)

  matched_node = search_children_for_describe_or_context(node.children)
  return unless matched_node

  method_name = matched_node.method_name
  module_name = get_module_name(node)
  message = [DESCRIBE_OR_CONTEXT_UNDER_NAMESPACE_MSG]

  described_class = get_described_class(matched_node)
  method_parent = get_method_parent(matched_node)
  parent_dot_method = method_parent ? "#{method_parent}.#{method_name}" : method_name
  if described_class
    message << FIX_DESCRIBE_OR_CONTEXT_HELP_MSG % {
      describe: parent_dot_method,
      klass: described_class,
      module_name: module_name,
    }
  end

  message << FIX_CODE_HELP_MSG % { module_name: module_name }
  add_offense(node, message: message.join(' '))
end
search_children_for_describe_or_context(nodes) click to toggle source
# File lib/rubocop/cop/airbnb/rspec_describe_or_context_under_namespace.rb, line 64
def search_children_for_describe_or_context(nodes)
  blocks = []
  # match nodes for send describe or context
  nodes.detect do |node|
    next unless node

    if is_block?(node)
      blocks << node
      next
    end
    return node if describe_or_context?(node)
  end

  # Process child nodes of block
  blocks.each do |node|
    matched_node = search_children_for_describe_or_context(node.children)
    return matched_node if matched_node
  end

  nil
end