diff --git a/docs/src/traits/enum.md b/docs/src/traits/enum.md index 068a3b6c1..156dcbf15 100644 --- a/docs/src/traits/enum.md +++ b/docs/src/traits/enum.md @@ -59,6 +59,25 @@ FactoryBot.define do end ``` +If you want to override `FactoryBot.automatically_define_enum_traits` on a +per-model basis, you can use an additional attribute on your factory: + +```rb +FactoryBot.define do + factory :task, automatically_define_enum_traits: false do + status { :queued } + + trait :in_progress do + status { :started } + end + + trait :complete do + status {:finished } + end + end +end +``` + It is also possible to use this feature for other enumerable values, not specifically tied to Active Record enum attributes. diff --git a/lib/factory_bot/definition.rb b/lib/factory_bot/definition.rb index 0df62d6da..f08b42cd7 100644 --- a/lib/factory_bot/definition.rb +++ b/lib/factory_bot/definition.rb @@ -3,7 +3,7 @@ module FactoryBot class Definition attr_reader :defined_traits, :declarations, :name, :registered_enums - def initialize(name, base_traits = []) + def initialize(name, base_traits = [], automatically_define_enum_traits = nil) @name = name @declarations = DeclarationList.new(name) @callbacks = [] @@ -15,6 +15,7 @@ def initialize(name, base_traits = []) @constructor = nil @attributes = nil @compiled = false + @automatically_define_enum_traits = automatically_define_enum_traits @expanded_enum_traits = false end @@ -195,8 +196,13 @@ def automatically_register_defined_enums(klass) end def automatically_register_defined_enums?(klass) - FactoryBot.automatically_define_enum_traits && - klass.respond_to?(:defined_enums) + automatically_define_enum_traits = if @automatically_define_enum_traits.nil? + FactoryBot.automatically_define_enum_traits + else + @automatically_define_enum_traits + end + + automatically_define_enum_traits && klass.respond_to?(:defined_enums) end end end diff --git a/lib/factory_bot/factory.rb b/lib/factory_bot/factory.rb index 09116f768..ba594daef 100644 --- a/lib/factory_bot/factory.rb +++ b/lib/factory_bot/factory.rb @@ -12,7 +12,7 @@ def initialize(name, options = {}) @parent = options[:parent] @aliases = options[:aliases] || [] @class_name = options[:class] - @definition = Definition.new(@name, options[:traits] || []) + @definition = Definition.new(@name, options[:traits] || [], options[:automatically_define_enum_traits]) @compiled = false end @@ -140,7 +140,7 @@ def compiled_constructor private def assert_valid_options(options) - options.assert_valid_keys(:class, :parent, :aliases, :traits) + options.assert_valid_keys(:class, :parent, :aliases, :traits, :automatically_define_enum_traits) end def parent diff --git a/spec/acceptance/enum_traits_spec.rb b/spec/acceptance/enum_traits_spec.rb index 3f347251e..c08c557c5 100644 --- a/spec/acceptance/enum_traits_spec.rb +++ b/spec/acceptance/enum_traits_spec.rb @@ -1,5 +1,5 @@ describe "enum traits" do - context "when automatically_define_enum_traits is true" do + context "when FactoryBot.automatically_define_enum_traits is true" do it "builds traits automatically for model enum field" do define_model("Task", status: :integer) do enum status: {queued: 0, started: 1, finished: 2} @@ -113,9 +113,49 @@ def each(&block) expect(task.status).to eq(trait_name) end end + + context "when the factory specifies automatically_define_enum_traits as false" do + it "raises an error for undefined traits" do + define_model("Task", status: :integer) do + enum status: {queued: 0, started: 1, finished: 2} + end + + FactoryBot.define do + factory :task, automatically_define_enum_traits: false + end + + Task.statuses.each_key do |trait_name| + expect { FactoryBot.build(:task, trait_name) }.to raise_error( + KeyError, "Trait not registered: \"#{trait_name}\"" + ) + end + + Task.reset_column_information + end + + it "builds traits for each enumerated value when traits_for_enum are specified" do + define_model("Task", status: :integer) do + enum status: {queued: 0, started: 1, finished: 2} + end + + FactoryBot.define do + factory :task, automatically_define_enum_traits: false do + traits_for_enum(:status) + end + end + + Task.statuses.each_key do |trait_name| + task = FactoryBot.build(:task, trait_name) + + expect(task.status).to eq(trait_name) + end + + Task.reset_column_information + end + end end - context "when automatically_define_enum_traits is false" do + context "when FactoryBot.automatically_define_enum_traits is false" do it "raises an error for undefined traits" do with_temporary_assignment(FactoryBot, :automatically_define_enum_traits, false) do define_model("Task", status: :integer) do @@ -157,5 +197,27 @@ def each(&block) Task.reset_column_information end end + + context "when the factory specifies automatically_define_enum_traits as true" do + it "builds traits automatically for model enum field" do + with_temporary_assignment(FactoryBot, :automatically_define_enum_traits, false) do + define_model("Task", status: :integer) do + enum status: {queued: 0, started: 1, finished: 2} + end + + FactoryBot.define do + factory :task, automatically_define_enum_traits: true + end + + Task.statuses.each_key do |trait_name| + task = FactoryBot.build(:task, trait_name) + + expect(task.status).to eq(trait_name) + end + + Task.reset_column_information + end + end + end end end