diff --git a/lib/factory_bot/definition.rb b/lib/factory_bot/definition.rb index 936babb1..a9d5fe5c 100644 --- a/lib/factory_bot/definition.rb +++ b/lib/factory_bot/definition.rb @@ -95,6 +95,10 @@ def define_trait(trait) @defined_traits.add(trait) end + def defined_traits_names + @defined_traits.map(&:name) + end + def register_enum(enum) @registered_enums << enum end diff --git a/lib/factory_bot/factory.rb b/lib/factory_bot/factory.rb index 7f445c88..17aafa84 100644 --- a/lib/factory_bot/factory.rb +++ b/lib/factory_bot/factory.rb @@ -17,7 +17,8 @@ def initialize(name, options = {}) end delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor, - :defined_traits, :inherit_traits, :append_traits, to: :@definition + :defined_traits, :defined_traits_names, :inherit_traits, :append_traits, + to: :@definition def build_class @build_class ||= if class_name.is_a? Class @@ -85,7 +86,7 @@ def names def compile unless @compiled parent.compile - parent.defined_traits.each { |trait| define_trait(trait) } + inherit_parent_traits @definition.compile(build_class) build_hierarchy @compiled = true @@ -153,6 +154,13 @@ def parent end end + def inherit_parent_traits + parent.defined_traits.each do |trait| + next if defined_traits_names.include?(trait.name) + define_trait(trait.clone) + end + end + def initialize_copy(source) super @definition = @definition.clone diff --git a/lib/factory_bot/trait.rb b/lib/factory_bot/trait.rb index d45a99c8..384a4e7d 100644 --- a/lib/factory_bot/trait.rb +++ b/lib/factory_bot/trait.rb @@ -14,6 +14,10 @@ def initialize(name, &block) end end + def clone + Trait.new(name, &block) + end + delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor, :callbacks, :attributes, :klass, :klass=, to: :@definition diff --git a/spec/acceptance/traits_spec.rb b/spec/acceptance/traits_spec.rb index 24289cf7..710ccc64 100644 --- a/spec/acceptance/traits_spec.rb +++ b/spec/acceptance/traits_spec.rb @@ -38,6 +38,10 @@ gender { "Female" } end + trait :make_it_great do + great + end + factory :great_user do great end @@ -50,6 +54,12 @@ end end + factory :greatest_user do + trait :great do + great { "GREATEST EVER!!!" } + end + end + factory :admin, traits: [:admin] factory :male_user do @@ -177,6 +187,22 @@ end end + context "factory with implicit traits called by child" do + it "calls the correct trait when parent built first" do + user = FactoryBot.create(:user, :make_it_great) + + expect(user.great).to eq "GREAT!!!" + end + + it "calls the correct trait when child built first" do + greatest = FactoryBot.create(:greatest_user, :make_it_great) + user = FactoryBot.create(:user, :make_it_great) + + expect(user.great).to eq "GREAT!!!" + expect(greatest.great).to eq "GREATEST EVER!!!" + end + end + context "child factory created where trait attributes are inherited" do subject { FactoryBot.create(:child_male_user) } its(:gender) { should eq "Male" }