From f18edf427e1351d920225d54eb89bae2f28cd3bd Mon Sep 17 00:00:00 2001 From: Milo Winningham Date: Mon, 6 Jan 2025 17:57:44 -0800 Subject: [PATCH] Add option to lazy load factory definitions --- README.md | 11 +++++++ features/load_definitions.feature | 33 +++++++++++++++++++++ lib/factory_bot_rails/lazy_registry_find.rb | 10 +++++++ lib/factory_bot_rails/railtie.rb | 9 +++++- 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 lib/factory_bot_rails/lazy_registry_find.rb diff --git a/README.md b/README.md index 6aef3130..07e4da35 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,17 @@ class MyEngine < ::Rails::Engine end ``` +If your application has a large number of factories, you may want to enable +lazy loading to speed up boot time: + +```rb +config.factory_bot.lazy_load_definitions = true +``` + +With lazy loading of definitions enabled, `FactoryBot.factories` will appear +empty after booting the application. All factory definitions will be loaded +when any factory is first accessed by name. + You can also disable automatic factory definition loading entirely by using an empty array: diff --git a/features/load_definitions.feature b/features/load_definitions.feature index 4c01b9cb..90601c7b 100644 --- a/features/load_definitions.feature +++ b/features/load_definitions.feature @@ -197,3 +197,36 @@ Feature: automatically load factory definitions """ When I run `bundle exec rake test` with a clean environment Then the output should contain "2 assertions, 0 failures, 0 errors" + + Scenario: use lazy loading of factory definitions + When I configure the factories as: + """ + config.factory_bot.lazy_load_definitions = true + """ + When I write to "test/factories.rb" with: + """ + FactoryBot.define do + factory :user do + name { "Frank" } + end + end + """ + When I write to "test/unit/user_test.rb" with: + """ + require 'test_helper' + + class UserTest < ActiveSupport::TestCase + test "use lazy loaded factory" do + assert FactoryBot.factories.none? + refute FactoryBot.factories.registered?(:user) + + user = FactoryBot.create(:user) + assert_equal 'Frank', user.name + + assert FactoryBot.factories.any? + assert FactoryBot.factories.registered?(:user) + end + end + """ + When I run `bundle exec rake test` with a clean environment + Then the output should contain "5 assertions, 0 failures, 0 errors" diff --git a/lib/factory_bot_rails/lazy_registry_find.rb b/lib/factory_bot_rails/lazy_registry_find.rb new file mode 100644 index 00000000..783553d2 --- /dev/null +++ b/lib/factory_bot_rails/lazy_registry_find.rb @@ -0,0 +1,10 @@ +require "factory_bot/registry" + +module FactoryBotRails + module LazyRegistryFind + def find(*) + FactoryBot.find_definitions unless FactoryBot.factories.any? + super + end + end +end diff --git a/lib/factory_bot_rails/railtie.rb b/lib/factory_bot_rails/railtie.rb index 0e7dfdb8..7188e31c 100644 --- a/lib/factory_bot_rails/railtie.rb +++ b/lib/factory_bot_rails/railtie.rb @@ -10,6 +10,7 @@ module FactoryBotRails class Railtie < Rails::Railtie config.factory_bot = ActiveSupport::OrderedOptions.new config.factory_bot.definition_file_paths = FactoryBot.definition_file_paths + config.factory_bot.lazy_load_definitions = false config.factory_bot.validator = FactoryBotRails::FactoryValidator.new initializer "factory_bot.set_fixture_replacement" do @@ -21,7 +22,13 @@ class Railtie < Rails::Railtie end config.after_initialize do |app| - FactoryBot.find_definitions + if app.config.factory_bot.lazy_load_definitions && !app.config.eager_load + require "factory_bot_rails/lazy_registry_find" + FactoryBot::Registry.prepend FactoryBotRails::LazyRegistryFind + else + FactoryBot.find_definitions + end + Reloader.new(app).run app.config.factory_bot.validator.run end