Skip to content

Commit

Permalink
Assign klass to global traits when find by name
Browse files Browse the repository at this point in the history
To pass their class to ActiveSuport::Notifications.
Re-Fix thoughtbot/factory_bot_rails#431
  • Loading branch information
makicamel committed Nov 21, 2023
1 parent b3dcdb5 commit bc7fe7d
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 13 deletions.
3 changes: 2 additions & 1 deletion lib/factory_bot/definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def compile(klass = nil)

declarations.attributes

self.klass ||= klass
defined_traits.each do |defined_trait|
defined_trait.klass ||= klass
base_traits.each { |bt| bt.define_trait defined_trait }
Expand Down Expand Up @@ -152,7 +153,7 @@ def additional_traits
end

def trait_by_name(name)
trait_for(name) || Internal.trait_by_name(name)
trait_for(name) || Internal.trait_by_name(name, klass)
end

def trait_for(name)
Expand Down
4 changes: 2 additions & 2 deletions lib/factory_bot/internal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def register_trait(trait)
trait
end

def trait_by_name(name)
traits.find(name)
def trait_by_name(name, klass)
traits.find(name).tap { |t| t.klass = klass }
end

def register_sequence(sequence)
Expand Down
88 changes: 79 additions & 9 deletions spec/acceptance/activesupport_instrumentation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,14 +114,84 @@ def subscribed(callback, *args)
FactoryBot.build(:user, :special)
end

user_payload = tracked_payloads.detect { |payload| payload[:name] == :user }
expect(user_payload[:class]).to eq(User)
expect(user_payload[:attributes].map(&:name)).to eq([:email, :name])
expect(user_payload[:traits].map(&:name)).to eq(["special"])

special_payload = tracked_payloads.detect { |payload| payload[:name] == "special" }
expect(special_payload[:class]).to eq(User)
expect(special_payload[:attributes].map(&:name)).to eq([:name])
expect(special_payload[:traits].map(&:name)).to eq(["special"])
factory_payload = tracked_payloads.detect { |payload| payload[:name] == :user }
expect(factory_payload[:class]).to eq(User)
expect(factory_payload[:attributes].map(&:name)).to eq([:email, :name])
expect(factory_payload[:traits].map(&:name)).to eq(["special"])

trait_payload = tracked_payloads.detect { |payload| payload[:name] == "special" }
expect(trait_payload[:class]).to eq(User)
expect(trait_payload[:attributes].map(&:name)).to eq([:name])
expect(trait_payload[:traits].map(&:name)).to eq(["special"])
end

context "when factory with base traits" do
before do
define_model("Company", name: :string, email: :string)

FactoryBot.define do
trait :email do
email { "#{name}@example.com" }
end

factory :company, traits: [:email] do
name { "Charlie" }
end
end
end

it "builds the correct payload" do
tracked_payloads = []
callback = ->(_name, _start, _finish, _id, payload) { tracked_payloads << payload }

ActiveSupport::Notifications.subscribed(callback, "factory_bot.compile_factory") do
FactoryBot.build(:company)
end

factory_payload = tracked_payloads.detect { |payload| payload[:name] == :company }
expect(factory_payload[:class]).to eq(Company)
expect(factory_payload[:attributes].map(&:name)).to eq([:name])
expect(factory_payload[:traits].map(&:name)).to eq([])

trait_payload = tracked_payloads.detect { |payload| payload[:name] == "email" }
expect(trait_payload[:class]).to eq(Company)
expect(trait_payload[:attributes].map(&:name)).to eq([:email])
expect(trait_payload[:traits].map(&:name)).to eq([])
end
end

context "when factory with additional traits" do
before do
define_model("Company", name: :string, email: :string)

FactoryBot.define do
trait :email do
email { "#{name}@example.com" }
end

factory :company do
name { "Charlie" }
end
end
end

it "builds the correct payload" do
tracked_payloads = []
callback = ->(_name, _start, _finish, _id, payload) { tracked_payloads << payload }

ActiveSupport::Notifications.subscribed(callback, "factory_bot.compile_factory") do
FactoryBot.build(:company, :email)
end

factory_payload = tracked_payloads.detect { |payload| payload[:name] == :company }
expect(factory_payload[:class]).to eq(Company)
expect(factory_payload[:attributes].map(&:name)).to eq([:name])
expect(factory_payload[:traits].map(&:name)).to eq([])

trait_payload = tracked_payloads.detect { |payload| payload[:name] == "email" }
expect(trait_payload[:class]).to eq(Company)
expect(trait_payload[:attributes].map(&:name)).to eq([:email])
expect(trait_payload[:traits].map(&:name)).to eq([])
end
end
end
5 changes: 4 additions & 1 deletion spec/factory_bot/internal_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
describe ".trait_by_name" do
it "finds a previously registered trait" do
trait = FactoryBot::Trait.new(:admin)
klass = instance_double("klass")
FactoryBot::Internal.register_trait(trait)

expect(FactoryBot::Internal.trait_by_name(trait.name)).to eq trait
expect(trait.klass).to be_nil
expect(FactoryBot::Internal.trait_by_name(trait.name, klass)).to eq trait
expect(trait.klass).to eq klass
end
end

Expand Down

0 comments on commit bc7fe7d

Please sign in to comment.