describe "callbacks" do before do define_model("User", first_name: :string, last_name: :string) FactoryBot.define do factory :user_with_callbacks, class: :user do after(:stub) { |user| user.first_name = "Stubby" } after(:build) { |user| user.first_name = "Buildy" } after(:create) { |user| user.last_name = "Createy" } end factory :user_with_inherited_callbacks, parent: :user_with_callbacks do after(:stub) { |user| user.last_name = "Double-Stubby" } after(:build) { |user| user.first_name = "Child-Buildy" } end end end it "runs the after(:stub) callback when stubbing" do user = FactoryBot.build_stubbed(:user_with_callbacks) expect(user.first_name).to eq "Stubby" end it "runs the after(:build) callback when building" do user = FactoryBot.build(:user_with_callbacks) expect(user.first_name).to eq "Buildy" end it "runs both the after(:build) and after(:create) callbacks when creating" do user = FactoryBot.create(:user_with_callbacks) expect(user.first_name).to eq "Buildy" expect(user.last_name).to eq "Createy" end it "runs both the after(:stub) callback on the factory and the inherited after(:stub) callback" do user = FactoryBot.build_stubbed(:user_with_inherited_callbacks) expect(user.first_name).to eq "Stubby" expect(user.last_name).to eq "Double-Stubby" end it "runs child callback after parent callback" do user = FactoryBot.build(:user_with_inherited_callbacks) expect(user.first_name).to eq "Child-Buildy" end end describe "callbacks using Symbol#to_proc" do before do define_model("User") do def confirmed? !!@confirmed end def confirm! @confirmed = true end end FactoryBot.define do factory :user do after :build, &:confirm! end end end it "runs the callback correctly" do user = FactoryBot.build(:user) expect(user).to be_confirmed end end describe "callbacks using syntax methods without referencing FactoryBot explicitly" do before do define_model("User", first_number: :integer, last_number: :integer) FactoryBot.define do sequence(:sequence_1) sequence(:sequence_2) sequence(:sequence_3) factory :user do after(:stub) { generate(:sequence_3) } after(:build) { |user| user.first_number = generate(:sequence_1) } after(:create) { |user, _evaluator| user.last_number = generate(:sequence_2) } end end end it "works when the callback has no variables" do FactoryBot.build_stubbed(:user) expect(FactoryBot.generate(:sequence_3)).to eq 2 end it "works when the callback has one variable" do expect(FactoryBot.build(:user).first_number).to eq 1 end it "works when the callback has two variables" do expect(FactoryBot.create(:user).last_number).to eq 1 end end describe "custom callbacks" do let(:custom_before) do Class.new do def result(evaluation) evaluation.object.tap do |instance| evaluation.notify(:before_custom, instance) end end end end let(:custom_after) do Class.new do def result(evaluation) evaluation.object.tap do |instance| evaluation.notify(:after_custom, instance) end end end end let(:totally_custom) do Class.new do def result(evaluation) evaluation.object.tap do |instance| evaluation.notify(:totally_custom, instance) end end end end before do define_model("User", first_name: :string, last_name: :string) do def name [first_name, last_name].join(" ") end end FactoryBot.register_strategy(:custom_before, custom_before) FactoryBot.register_strategy(:custom_after, custom_after) FactoryBot.register_strategy(:totally_custom, totally_custom) FactoryBot.define do factory :user do first_name { "John" } last_name { "Doe" } before(:custom) { |instance| instance.first_name = "Overridden First" } after(:custom) { |instance| instance.last_name = "Overridden Last" } callback(:totally_custom) do |instance| instance.first_name = "Totally" instance.last_name = "Custom" end end end end it "runs a custom before callback when the proper strategy executes" do expect(FactoryBot.build(:user).name).to eq "John Doe" expect(FactoryBot.custom_before(:user).name).to eq "Overridden First Doe" end it "runs a custom after callback when the proper strategy executes" do expect(FactoryBot.build(:user).name).to eq "John Doe" expect(FactoryBot.custom_after(:user).name).to eq "John Overridden Last" end it "runs a custom callback without prepending before or after when the proper strategy executes" do expect(FactoryBot.build(:user).name).to eq "John Doe" expect(FactoryBot.totally_custom(:user).name).to eq "Totally Custom" end end describe "binding a callback to multiple callbacks" do before do define_model("User", name: :string) FactoryBot.define do factory :user do callback(:before_create, :after_stub) do |instance| instance.name = instance.name.upcase end end end end it "binds the callback to creation" do expect(FactoryBot.create(:user, name: "John Doe").name).to eq "JOHN DOE" end it "does not bind the callback to building" do expect(FactoryBot.build(:user, name: "John Doe").name).to eq "John Doe" end it "binds the callback to stubbing" do expect(FactoryBot.build_stubbed(:user, name: "John Doe").name).to eq "JOHN DOE" end end describe "global callbacks" do include FactoryBot::Syntax::Methods before do define_model("User", name: :string) define_model("Company", name: :string) FactoryBot.define do after :build do |object| object.name = case object.class.to_s when "User" then "John Doe" when "Company" then "Acme Suppliers" end end after :create do |object| object.name = "#{object.name}!!!" end trait :awesome do after :build do |object| object.name = "___#{object.name}___" end after :create do |object| object.name = "A#{object.name}Z" end end factory :user do after :build do |user| user.name = user.name.downcase end end factory :company do after :build do |company| company.name = company.name.upcase end end end end it "triggers after build callbacks for all factories" do expect(build(:user).name).to eq "john doe" expect(create(:user).name).to eq "john doe!!!" expect(create(:user, :awesome).name).to eq "A___john doe___!!!Z" expect(build(:company).name).to eq "ACME SUPPLIERS" end end