2018-10-07 21:45:51 -04:00
|
|
|
require "set"
|
|
|
|
require "active_support/core_ext/module/delegation"
|
2019-01-02 21:16:23 -05:00
|
|
|
require "active_support/core_ext/module/attribute_accessors"
|
2018-10-07 21:45:51 -04:00
|
|
|
require "active_support/deprecation"
|
|
|
|
require "active_support/notifications"
|
2017-10-20 15:20:28 -04:00
|
|
|
|
2018-10-07 21:45:51 -04:00
|
|
|
require "factory_bot/definition_hierarchy"
|
|
|
|
require "factory_bot/configuration"
|
|
|
|
require "factory_bot/errors"
|
|
|
|
require "factory_bot/factory_runner"
|
|
|
|
require "factory_bot/strategy_syntax_method_registrar"
|
|
|
|
require "factory_bot/strategy_calculator"
|
|
|
|
require "factory_bot/strategy/build"
|
|
|
|
require "factory_bot/strategy/create"
|
|
|
|
require "factory_bot/strategy/attributes_for"
|
|
|
|
require "factory_bot/strategy/stub"
|
|
|
|
require "factory_bot/strategy/null"
|
|
|
|
require "factory_bot/registry"
|
|
|
|
require "factory_bot/null_factory"
|
|
|
|
require "factory_bot/null_object"
|
|
|
|
require "factory_bot/evaluation"
|
|
|
|
require "factory_bot/factory"
|
|
|
|
require "factory_bot/attribute_assigner"
|
|
|
|
require "factory_bot/evaluator"
|
|
|
|
require "factory_bot/evaluator_class_definer"
|
|
|
|
require "factory_bot/attribute"
|
|
|
|
require "factory_bot/callback"
|
|
|
|
require "factory_bot/callbacks_observer"
|
|
|
|
require "factory_bot/declaration_list"
|
|
|
|
require "factory_bot/declaration"
|
|
|
|
require "factory_bot/sequence"
|
|
|
|
require "factory_bot/attribute_list"
|
|
|
|
require "factory_bot/trait"
|
|
|
|
require "factory_bot/aliases"
|
|
|
|
require "factory_bot/definition"
|
|
|
|
require "factory_bot/definition_proxy"
|
|
|
|
require "factory_bot/syntax"
|
|
|
|
require "factory_bot/syntax_runner"
|
|
|
|
require "factory_bot/find_definitions"
|
|
|
|
require "factory_bot/reload"
|
|
|
|
require "factory_bot/decorator"
|
|
|
|
require "factory_bot/decorator/attribute_hash"
|
|
|
|
require "factory_bot/decorator/disallows_duplicates_registry"
|
|
|
|
require "factory_bot/decorator/invocation_tracker"
|
|
|
|
require "factory_bot/decorator/new_constructor"
|
|
|
|
require "factory_bot/linter"
|
|
|
|
require "factory_bot/version"
|
2017-10-20 15:20:28 -04:00
|
|
|
|
|
|
|
module FactoryBot
|
|
|
|
def self.configuration
|
|
|
|
@configuration ||= Configuration.new
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.reset_configuration
|
|
|
|
@configuration = nil
|
|
|
|
end
|
|
|
|
|
Default `use_parent_strategy` to true
Background
---
In issues #64 and #66 (from 2010) people expressed surprise
that using the `build` strategy would still `create` any associations.
I remember being similarly surprised by that behavior when I first
started using factory_bot.
The main reason for this behavior is to ensure the built instance will
be valid if there were any foreign key validations
(like `validates_presence_of :user_id`). If we don't save the
associations, there won't be any ids present.
PR #191 (from 2011) offers a workaround for people who don't want
records to be saved automatically. Passing `strategy: :build`
(originally `method: :build`, but later renamed) when declaring the
association will prevent it from being saved when using `build`.
But #191 isn't really a complete solution (as discussed on the PR
after it was merged). `strategy: :build` may do
the right thing when building objects with the `build` strategy, but it
can cause new problems when using the `create` strategy.
A better solution would be something like:
`strategy: <whatever strategy I was already using>`.
PRs #749 and #961 (merged in 2016) introduce something like that,
with the `use_parent_strategy` configuration option.
With this turned on `build` end up being generally [a little faster][]
than `build_stubbed`, since it no longer needs to hit the database for
each association.
[a little faster]: https://gist.github.com/composerinteralia/d4796df9140f431e36f88dfb6fe9733a
I have set `use_parent_strategy` on several projects now. I also added
it to suspenders in thoughtbot/suspenders#952.
On newer projects I have not run into any problems. On existing
projects I have seen the occasional test failure, which are easy enough
to fix by changing `build` to `create`.
Unfortunately I don't think `use_parent_strategy` is widely known,
since it wasn't documented until #1234 (about a month ago).
I also learned in #1234 that the `use_parent_strategy` setting gets
wiped out with `FactoryBot.reload`, which can be problematic when using
factory_bot_rails.
To summarize, we have been exploring having a `build` strategy that uses
`build` all the way down since 2010, but there still isn't a totally
reliable way to get that.
This PR
---
* Default to using the parent strategy for factory_bot 5, as suggested
in #749.
* In the original PR for this (#1240) I had removed
`use_parent_strategy`, but to make the transition smoother I ended up
fixing the reload problem in #1244
Once factory\_bot 5 is released and the dust has settled, it may make
sense to deprecate `use_parent_strategy`, and maybe also the strategy
option for associations.
2019-01-04 19:57:22 -05:00
|
|
|
mattr_accessor :use_parent_strategy, instance_accessor: false, default: true
|
2019-01-02 21:16:23 -05:00
|
|
|
|
2017-10-20 15:20:28 -04:00
|
|
|
# Look for errors in factories and (optionally) their traits.
|
|
|
|
# Parameters:
|
|
|
|
# factories - which factories to lint; omit for all factories
|
|
|
|
# options:
|
|
|
|
# traits: true - to lint traits as well as factories
|
|
|
|
# strategy: :create - to specify the strategy for linting
|
2018-11-21 15:28:28 -05:00
|
|
|
# verbose: true - to include full backtraces for each linting error
|
2017-10-20 15:20:28 -04:00
|
|
|
def self.lint(*args)
|
|
|
|
options = args.extract_options!
|
|
|
|
factories_to_lint = args[0] || FactoryBot.factories
|
2018-11-21 22:17:24 -05:00
|
|
|
Linter.new(factories_to_lint, options).lint!
|
2017-10-20 15:20:28 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
class << self
|
|
|
|
delegate :factories,
|
|
|
|
:sequences,
|
|
|
|
:traits,
|
|
|
|
:callbacks,
|
|
|
|
:strategies,
|
|
|
|
:callback_names,
|
|
|
|
:to_create,
|
|
|
|
:skip_create,
|
|
|
|
:initialize_with,
|
|
|
|
:constructor,
|
|
|
|
to: :configuration
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.register_factory(factory)
|
|
|
|
factory.names.each do |name|
|
|
|
|
factories.register(name, factory)
|
|
|
|
end
|
|
|
|
factory
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.factory_by_name(name)
|
|
|
|
factories.find(name)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.register_sequence(sequence)
|
|
|
|
sequence.names.each do |name|
|
|
|
|
sequences.register(name, sequence)
|
|
|
|
end
|
|
|
|
sequence
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.sequence_by_name(name)
|
|
|
|
sequences.find(name)
|
|
|
|
end
|
|
|
|
|
2017-09-30 23:06:14 -04:00
|
|
|
def self.rewind_sequences
|
|
|
|
sequences.each(&:rewind)
|
|
|
|
end
|
|
|
|
|
2017-10-20 15:20:28 -04:00
|
|
|
def self.register_trait(trait)
|
|
|
|
trait.names.each do |name|
|
|
|
|
traits.register(name, trait)
|
|
|
|
end
|
|
|
|
trait
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.trait_by_name(name)
|
|
|
|
traits.find(name)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.register_strategy(strategy_name, strategy_class)
|
|
|
|
strategies.register(strategy_name, strategy_class)
|
|
|
|
StrategySyntaxMethodRegistrar.new(strategy_name).define_strategy_methods
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.strategy_by_name(name)
|
|
|
|
strategies.find(name)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.register_default_strategies
|
|
|
|
register_strategy(:build, FactoryBot::Strategy::Build)
|
|
|
|
register_strategy(:create, FactoryBot::Strategy::Create)
|
|
|
|
register_strategy(:attributes_for, FactoryBot::Strategy::AttributesFor)
|
|
|
|
register_strategy(:build_stubbed, FactoryBot::Strategy::Stub)
|
|
|
|
register_strategy(:null, FactoryBot::Strategy::Null)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.register_default_callbacks
|
|
|
|
register_callback(:after_build)
|
|
|
|
register_callback(:after_create)
|
|
|
|
register_callback(:after_stub)
|
|
|
|
register_callback(:before_create)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.register_callback(name)
|
|
|
|
name = name.to_sym
|
|
|
|
callback_names << name
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
FactoryBot.register_default_strategies
|
|
|
|
FactoryBot.register_default_callbacks
|