Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to lazy load factory definitions #522

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
33 changes: 33 additions & 0 deletions features/load_definitions.feature
Original file line number Diff line number Diff line change
Expand Up @@ -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"
10 changes: 10 additions & 0 deletions lib/factory_bot_rails/lazy_registry_find.rb
Original file line number Diff line number Diff line change
@@ -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
9 changes: 8 additions & 1 deletion lib/factory_bot_rails/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be implemented in the factory_bot gem instead, so I'll open another PR for that if there's any interest here.

else
FactoryBot.find_definitions
end

Reloader.new(app).run
app.config.factory_bot.validator.run
end
Expand Down