diff --git a/lib/factory_bot/callback.rb b/lib/factory_bot/callback.rb index 1766cc80..c11f0716 100644 --- a/lib/factory_bot/callback.rb +++ b/lib/factory_bot/callback.rb @@ -7,6 +7,10 @@ def initialize(name, block) @block = block end + def run_before_build + syntax_runner.instance_exec(&block) + end + def run(instance, evaluator) case block.arity when 1, -1, -2 then syntax_runner.instance_exec(instance, &block) @@ -20,6 +24,10 @@ def ==(other) block == other.block end + def before_build? + name == :before_build + end + protected attr_reader :block diff --git a/lib/factory_bot/factory.rb b/lib/factory_bot/factory.rb index 7f445c88..fd94e5d0 100644 --- a/lib/factory_bot/factory.rb +++ b/lib/factory_bot/factory.rb @@ -32,6 +32,7 @@ def build_class def run(build_strategy, overrides, &block) block ||= ->(result) { result } compile + run_before_build_callbacks strategy = StrategyCalculator.new(build_strategy).strategy.new @@ -139,6 +140,12 @@ def compiled_constructor hierarchy_instance.constructor end + def run_before_build_callbacks + callbacks.each do |callback| + callback.run_before_build if callback.before_build? + end + end + private def assert_valid_options(options) diff --git a/spec/acceptance/callbacks_spec.rb b/spec/acceptance/callbacks_spec.rb index 57d2471a..bd3a9973 100644 --- a/spec/acceptance/callbacks_spec.rb +++ b/spec/acceptance/callbacks_spec.rb @@ -249,3 +249,33 @@ def name expect(build(:company).name).to eq "ACME SUPPLIERS" end end + +describe "before build callback" do + before do + define_class("TitleSetter") do + def self.title=(new_title) + class_variable_set(:@@title, new_title) + end + + def self.title + class_variable_get(:@@title) + end + end + + define_model("Article", title: :string) + + FactoryBot.define do + factory :article_with_before_callbacks, class: :article do + before(:build) { TitleSetter.title = "title from before build" } + after(:build) { TitleSetter.title = "title from after build" } + + title { TitleSetter.title } + end + end + end + + it "runs the before callback" do + article = FactoryBot.build(:article_with_before_callbacks) + expect(article.title).to eq("title from before build") + end +end diff --git a/spec/factory_bot/callback_spec.rb b/spec/factory_bot/callback_spec.rb index 238d7d8a..2ccbb934 100644 --- a/spec/factory_bot/callback_spec.rb +++ b/spec/factory_bot/callback_spec.rb @@ -24,4 +24,15 @@ FactoryBot::Callback.new(:after_create, ->(one, two) { ran_with = [one, two] }).run(:one, :two) expect(ran_with).to eq [:one, :two] end + + it "runs run_before_build callback without attributes" do + ran_with = nil + FactoryBot::Callback.new(:before_build, -> { ran_with = "before build" }).run_before_build + expect(ran_with).to eq "before build" + end + + it "#before_build?" do + expect(FactoryBot::Callback.new(:before_build, -> {}).before_build?).to be true + expect(FactoryBot::Callback.new(:after_create, -> {}).before_build?).to be false + end end