Class: RuboCop::Cop::Momocop::FactoryBotMissingAssociations

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Includes:
Momocop::Helpers::FactoryBotHelper, Momocop::Helpers::RailsHelper, ActiveRecordHelper
Defined in:
lib/rubocop/cop/momocop/factory_bot_missing_associations.rb

Overview

Ensures that all properties of a Rails model class are defined in a FactoryBot factory, auto-corrects by adding missing properties with sensible defaults based on their types.

Examples:

# Assuming User model has one Account

# bad
FactoryBot.define do
  factory :user, class: 'User' do
  end
end

# good
FactoryBot.define do
  factory :user, class: 'User' do
    association(:account)
  end
end

Constant Summary collapse

MSG =
'Ensure all associations of the model class are defined in the factory.'
RESTRICT_ON_SEND =
%i[factory].freeze

Constants included from Momocop::Helpers::RailsHelper

Momocop::Helpers::RailsHelper::RESTRICTED_COLUMNS

Constants included from Momocop::Helpers::FactoryBotHelper

Momocop::Helpers::FactoryBotHelper::RUBOCOP_HELPER_METHODS

Instance Method Summary collapse

Instance Method Details

#on_send(node) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rubocop/cop/momocop/factory_bot_missing_associations.rb', line 40

def on_send(node)
  return unless inside_factory_bot_define?(node)

  class_name = get_class_name(node)
  return unless class_name

  block_node = node.block_node

  # Add block if it's missing
  unless block_node
    add_offense(node, message: MSG) do |corrector|
      indentation = ' ' * node.loc.column
      corrector.replace(node.source_range, "#{node.source} do\n#{indentation}end")
    end
  end

  # Check missing associations
  defined_associations = get_defined_association_names(block_node)
  model_associations = get_model_association_names(class_name)
  missing_associations = (model_associations - defined_associations).sort

  # Add offense for missing associations
  return unless missing_associations.any?

  add_offense(node, message: MSG) do |corrector|
    # Add newline before closing block if it's a one-liner
    if one_line_block?(block_node)
      indentation = ' ' * node.loc.column
      corrector.insert_before(block_node.loc.end, "\n#{indentation}")
    end

    missing_associations.each do |property|
      definition = generate_association_definition(property)
      break unless definition

      # TODO: calculate indentation size
      indentation = ' ' * (node.loc.column + 2)

      # use send node if blockless
      corrector.insert_after(block_node.loc.begin, "\n#{indentation}#{definition}")
    end
  end
end