summaryrefslogtreecommitdiff
path: root/rubocop/cop/rspec/factory_bot/local_static_assignment.rb
diff options
context:
space:
mode:
Diffstat (limited to 'rubocop/cop/rspec/factory_bot/local_static_assignment.rb')
-rw-r--r--rubocop/cop/rspec/factory_bot/local_static_assignment.rb67
1 files changed, 67 insertions, 0 deletions
diff --git a/rubocop/cop/rspec/factory_bot/local_static_assignment.rb b/rubocop/cop/rspec/factory_bot/local_static_assignment.rb
new file mode 100644
index 00000000000..1a26bc31c78
--- /dev/null
+++ b/rubocop/cop/rspec/factory_bot/local_static_assignment.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require 'rubocop-rspec'
+
+module RuboCop
+ module Cop
+ module RSpec
+ module FactoryBot
+ # Flags local assignments during factory "load time". This leads to
+ # static data definitions.
+ #
+ # Move these definitions into attribute block or
+ # `transient` block to ensure that the data is evaluated during
+ # "runtime" and remains dynamic.
+ #
+ # @example
+ # # bad
+ # factory :foo do
+ # random = rand(23)
+ # baz { "baz-#{random}" }
+ #
+ # trait :a_trait do
+ # random = rand(23)
+ # baz { "baz-#{random}" }
+ # end
+ #
+ # transient do
+ # random = rand(23)
+ # baz { "baz-#{random}" }
+ # end
+ # end
+ #
+ # # good
+ # factory :foo do
+ # baz { "baz-#{random}" }
+ #
+ # trait :a_trait do
+ # baz { "baz-#{random}" }
+ # end
+ #
+ # transient do
+ # random { rand(23) }
+ # end
+ # end
+ class LocalStaticAssignment < RuboCop::Cop::Base
+ MSG = 'Avoid local static assignemnts in factories which lead to static data definitions.'
+
+ RESTRICT_ON_SEND = %i[factory transient trait].freeze
+
+ def_node_search :local_assignment, <<~PATTERN
+ (begin $(lvasgn ...))
+ PATTERN
+
+ def on_send(node)
+ return unless node.parent&.block_type?
+
+ node.parent.each_child_node(:begin) do |begin_node|
+ begin_node.each_child_node(:lvasgn) do |lvasgn_node|
+ add_offense(lvasgn_node)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end