factory_bot 4.11.1 → 5.0.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/GETTING_STARTED.md +105 -29
- data/NEWS +17 -0
- data/README.md +3 -14
- data/lib/factory_bot.rb +56 -56
- data/lib/factory_bot/aliases.rb +1 -1
- data/lib/factory_bot/attribute.rb +4 -39
- data/lib/factory_bot/attribute_assigner.rb +20 -5
- data/lib/factory_bot/attribute_list.rb +2 -1
- data/lib/factory_bot/callback.rb +1 -0
- data/lib/factory_bot/configuration.rb +6 -18
- data/lib/factory_bot/declaration.rb +4 -4
- data/lib/factory_bot/declaration/association.rb +3 -1
- data/lib/factory_bot/declaration/dynamic.rb +3 -1
- data/lib/factory_bot/declaration/implicit.rb +3 -1
- data/lib/factory_bot/declaration_list.rb +1 -1
- data/lib/factory_bot/decorator.rb +5 -1
- data/lib/factory_bot/decorator/attribute_hash.rb +1 -1
- data/lib/factory_bot/decorator/invocation_tracker.rb +1 -1
- data/lib/factory_bot/definition.rb +4 -3
- data/lib/factory_bot/definition_proxy.rb +53 -62
- data/lib/factory_bot/errors.rb +4 -4
- data/lib/factory_bot/evaluation.rb +1 -1
- data/lib/factory_bot/evaluator.rb +4 -4
- data/lib/factory_bot/factory.rb +7 -7
- data/lib/factory_bot/factory_runner.rb +3 -3
- data/lib/factory_bot/find_definitions.rb +1 -1
- data/lib/factory_bot/linter.rb +35 -18
- data/lib/factory_bot/null_factory.rb +3 -0
- data/lib/factory_bot/null_object.rb +2 -2
- data/lib/factory_bot/registry.rb +15 -6
- data/lib/factory_bot/sequence.rb +0 -1
- data/lib/factory_bot/strategy/null.rb +2 -4
- data/lib/factory_bot/strategy/stub.rb +23 -29
- data/lib/factory_bot/strategy_syntax_method_registrar.rb +2 -2
- data/lib/factory_bot/syntax.rb +2 -2
- data/lib/factory_bot/syntax/default.rb +1 -1
- data/lib/factory_bot/trait.rb +2 -1
- data/lib/factory_bot/version.rb +1 -1
- metadata +68 -29
- data/lib/factory_bot/attribute/static.rb +0 -16
- data/lib/factory_bot/declaration/static.rb +0 -26
- data/lib/factory_bot/decorator/class_key_hash.rb +0 -28
data/lib/factory_bot/errors.rb
CHANGED
@@ -11,12 +11,12 @@ module FactoryBot
|
|
11
11
|
# Raised when attempting to register a sequence from a dynamic attribute block
|
12
12
|
class SequenceAbuseError < RuntimeError; end
|
13
13
|
|
14
|
-
# Raised when defining an
|
15
|
-
# * Defining an attribute which has a name ending in "="
|
16
|
-
# * Defining an attribute with both a static and lazy value
|
17
|
-
# * Defining an attribute twice in the same factory
|
14
|
+
# Raised when defining an attribute twice in the same factory
|
18
15
|
class AttributeDefinitionError < RuntimeError; end
|
19
16
|
|
17
|
+
# Raised when attempting to pass a block to an association definition
|
18
|
+
class AssociationDefinitionError < RuntimeError; end
|
19
|
+
|
20
20
|
# Raised when a method is defined in a factory or trait with arguments
|
21
21
|
class MethodDefinitionError < RuntimeError; end
|
22
22
|
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "active_support/core_ext/hash/except"
|
2
|
+
require "active_support/core_ext/class/attribute"
|
3
3
|
|
4
4
|
module FactoryBot
|
5
5
|
# @api private
|
@@ -37,7 +37,7 @@ module FactoryBot
|
|
37
37
|
@instance = object_instance
|
38
38
|
end
|
39
39
|
|
40
|
-
def method_missing(method_name, *args, &block)
|
40
|
+
def method_missing(method_name, *args, &block) # rubocop:disable Style/MethodMissing
|
41
41
|
if @instance.respond_to?(method_name)
|
42
42
|
@instance.send(method_name, *args, &block)
|
43
43
|
else
|
@@ -45,7 +45,7 @@ module FactoryBot
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
def respond_to_missing?(method_name,
|
48
|
+
def respond_to_missing?(method_name, _include_private = false)
|
49
49
|
@instance.respond_to?(method_name) || SyntaxRunner.new.respond_to?(method_name)
|
50
50
|
end
|
51
51
|
|
data/lib/factory_bot/factory.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "active_support/core_ext/hash/keys"
|
2
|
+
require "active_support/inflector"
|
3
3
|
|
4
4
|
module FactoryBot
|
5
5
|
# @api private
|
@@ -21,10 +21,10 @@ module FactoryBot
|
|
21
21
|
|
22
22
|
def build_class
|
23
23
|
@build_class ||= if class_name.is_a? Class
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
class_name
|
25
|
+
else
|
26
|
+
class_name.to_s.camelize.constantize
|
27
|
+
end
|
28
28
|
end
|
29
29
|
|
30
30
|
def run(build_strategy, overrides, &block)
|
@@ -91,7 +91,7 @@ module FactoryBot
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def with_traits(traits)
|
94
|
-
|
94
|
+
clone.tap do |factory_with_traits|
|
95
95
|
factory_with_traits.append_traits traits
|
96
96
|
end
|
97
97
|
end
|
@@ -5,7 +5,7 @@ module FactoryBot
|
|
5
5
|
@strategy = strategy
|
6
6
|
|
7
7
|
@overrides = traits_and_overrides.extract_options!
|
8
|
-
@traits = traits_and_overrides
|
8
|
+
@traits = traits_and_overrides.map(&:to_sym)
|
9
9
|
end
|
10
10
|
|
11
11
|
def run(runner_strategy = @strategy, &block)
|
@@ -22,10 +22,10 @@ module FactoryBot
|
|
22
22
|
strategy: runner_strategy,
|
23
23
|
traits: @traits,
|
24
24
|
overrides: @overrides,
|
25
|
-
factory: factory
|
25
|
+
factory: factory,
|
26
26
|
}
|
27
27
|
|
28
|
-
ActiveSupport::Notifications.instrument(
|
28
|
+
ActiveSupport::Notifications.instrument("factory_bot.run_factory", instrumentation_payload) do
|
29
29
|
factory.run(runner_strategy, @overrides, &block)
|
30
30
|
end
|
31
31
|
end
|
data/lib/factory_bot/linter.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module FactoryBot
|
2
2
|
class Linter
|
3
|
-
|
4
|
-
def initialize(factories, linting_strategy, factory_strategy = :create)
|
3
|
+
def initialize(factories, strategy: :create, traits: false, verbose: false)
|
5
4
|
@factories_to_lint = factories
|
6
|
-
@
|
7
|
-
@
|
5
|
+
@factory_strategy = strategy
|
6
|
+
@traits = traits
|
7
|
+
@verbose = verbose
|
8
8
|
@invalid_factories = calculate_invalid_factories
|
9
9
|
end
|
10
10
|
|
@@ -20,7 +20,7 @@ module FactoryBot
|
|
20
20
|
|
21
21
|
def calculate_invalid_factories
|
22
22
|
factories_to_lint.reduce(Hash.new([])) do |result, factory|
|
23
|
-
errors =
|
23
|
+
errors = lint(factory)
|
24
24
|
result[factory] |= errors unless errors.empty?
|
25
25
|
result
|
26
26
|
end
|
@@ -37,6 +37,13 @@ module FactoryBot
|
|
37
37
|
"* #{location} - #{message} (#{@wrapped_error.class.name})"
|
38
38
|
end
|
39
39
|
|
40
|
+
def verbose_message
|
41
|
+
<<~MESSAGE
|
42
|
+
#{message}
|
43
|
+
#{@wrapped_error.backtrace.join("\n ")}
|
44
|
+
MESSAGE
|
45
|
+
end
|
46
|
+
|
40
47
|
def location
|
41
48
|
@factory.name
|
42
49
|
end
|
@@ -53,11 +60,19 @@ module FactoryBot
|
|
53
60
|
end
|
54
61
|
end
|
55
62
|
|
63
|
+
def lint(factory)
|
64
|
+
if @traits
|
65
|
+
lint_factory(factory) + lint_traits(factory)
|
66
|
+
else
|
67
|
+
lint_factory(factory)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
56
71
|
def lint_factory(factory)
|
57
72
|
result = []
|
58
73
|
begin
|
59
74
|
FactoryBot.public_send(factory_strategy, factory.name)
|
60
|
-
rescue => error
|
75
|
+
rescue StandardError => error
|
61
76
|
result |= [FactoryError.new(error, factory)]
|
62
77
|
end
|
63
78
|
result
|
@@ -68,30 +83,32 @@ module FactoryBot
|
|
68
83
|
factory.definition.defined_traits.map(&:name).each do |trait_name|
|
69
84
|
begin
|
70
85
|
FactoryBot.public_send(factory_strategy, factory.name, trait_name)
|
71
|
-
rescue => error
|
86
|
+
rescue StandardError => error
|
72
87
|
result |=
|
73
|
-
|
88
|
+
[FactoryTraitError.new(error, factory, trait_name)]
|
74
89
|
end
|
75
90
|
end
|
76
91
|
result
|
77
92
|
end
|
78
93
|
|
79
|
-
def lint_factory_and_traits(factory)
|
80
|
-
errors = lint_factory(factory)
|
81
|
-
errors |= lint_traits(factory)
|
82
|
-
errors
|
83
|
-
end
|
84
|
-
|
85
94
|
def error_message
|
86
95
|
lines = invalid_factories.map do |_factory, exceptions|
|
87
|
-
exceptions.map(
|
96
|
+
exceptions.map(&error_message_type)
|
88
97
|
end.flatten
|
89
98
|
|
90
|
-
|
91
|
-
The following factories are invalid:
|
99
|
+
<<~ERROR_MESSAGE.strip
|
100
|
+
The following factories are invalid:
|
92
101
|
|
93
|
-
#{lines.join("\n")}
|
102
|
+
#{lines.join("\n")}
|
94
103
|
ERROR_MESSAGE
|
95
104
|
end
|
105
|
+
|
106
|
+
def error_message_type
|
107
|
+
if @verbose
|
108
|
+
:verbose_message
|
109
|
+
else
|
110
|
+
:message
|
111
|
+
end
|
112
|
+
end
|
96
113
|
end
|
97
114
|
end
|
@@ -13,11 +13,11 @@ module FactoryBot
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
def respond_to?(method,
|
16
|
+
def respond_to?(method, _include_private = false)
|
17
17
|
@methods_to_respond_to.include? method.to_s
|
18
18
|
end
|
19
19
|
|
20
|
-
def respond_to_missing?(*
|
20
|
+
def respond_to_missing?(*)
|
21
21
|
false
|
22
22
|
end
|
23
23
|
end
|
data/lib/factory_bot/registry.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "active_support/core_ext/hash/indifferent_access"
|
2
|
+
|
1
3
|
module FactoryBot
|
2
4
|
class Registry
|
3
5
|
include Enumerable
|
@@ -6,7 +8,7 @@ module FactoryBot
|
|
6
8
|
|
7
9
|
def initialize(name)
|
8
10
|
@name = name
|
9
|
-
@items =
|
11
|
+
@items = ActiveSupport::HashWithIndifferentAccess.new
|
10
12
|
end
|
11
13
|
|
12
14
|
def clear
|
@@ -18,11 +20,9 @@ module FactoryBot
|
|
18
20
|
end
|
19
21
|
|
20
22
|
def find(name)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
raise ArgumentError, "#{@name} not registered: #{name}"
|
25
|
-
end
|
23
|
+
@items.fetch(name)
|
24
|
+
rescue KeyError => key_error
|
25
|
+
raise key_error_with_custom_message(key_error)
|
26
26
|
end
|
27
27
|
|
28
28
|
alias :[] :find
|
@@ -34,5 +34,14 @@ module FactoryBot
|
|
34
34
|
def registered?(name)
|
35
35
|
@items.key?(name)
|
36
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def key_error_with_custom_message(key_error)
|
41
|
+
message = key_error.message.sub("key not found", "#{@name} not registered")
|
42
|
+
error = KeyError.new(message)
|
43
|
+
error.set_backtrace(key_error.backtrace)
|
44
|
+
error
|
45
|
+
end
|
37
46
|
end
|
38
47
|
end
|
data/lib/factory_bot/sequence.rb
CHANGED
@@ -31,7 +31,8 @@ module FactoryBot
|
|
31
31
|
def result(evaluation)
|
32
32
|
evaluation.object.tap do |instance|
|
33
33
|
stub_database_interaction_on_result(instance)
|
34
|
-
|
34
|
+
set_timestamps(instance)
|
35
|
+
clear_changes_information(instance)
|
35
36
|
evaluation.notify(:after_stub, instance)
|
36
37
|
end
|
37
38
|
end
|
@@ -60,46 +61,39 @@ module FactoryBot
|
|
60
61
|
|
61
62
|
DISABLED_PERSISTENCE_METHODS.each do |write_method|
|
62
63
|
define_singleton_method(write_method) do |*args|
|
63
|
-
raise "stubbed models are not allowed to access the database -
|
64
|
+
raise "stubbed models are not allowed to access the database - "\
|
65
|
+
"#{self.class}##{write_method}(#{args.join(',')})"
|
64
66
|
end
|
65
67
|
end
|
66
68
|
end
|
69
|
+
end
|
67
70
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
result_instance.instance_eval do
|
72
|
-
def created_at
|
73
|
-
@created_at ||= Time.now.in_time_zone
|
74
|
-
end
|
75
|
-
end
|
71
|
+
def clear_changes_information(result_instance)
|
72
|
+
if result_instance.respond_to?(:clear_changes_information)
|
73
|
+
result_instance.clear_changes_information
|
76
74
|
end
|
75
|
+
end
|
77
76
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
if updated_at_no_default
|
82
|
-
result_instance.instance_eval do
|
83
|
-
def updated_at
|
84
|
-
@updated_at ||= Time.current
|
85
|
-
end
|
86
|
-
end
|
77
|
+
def set_timestamps(result_instance)
|
78
|
+
if missing_created_at?(result_instance)
|
79
|
+
result_instance.created_at = Time.current
|
87
80
|
end
|
88
|
-
end
|
89
81
|
|
90
|
-
|
91
|
-
|
92
|
-
result_instance.extend ActiveModelDirtyBackport
|
82
|
+
if missing_updated_at?(result_instance)
|
83
|
+
result_instance.updated_at = Time.current
|
93
84
|
end
|
85
|
+
end
|
94
86
|
|
95
|
-
|
87
|
+
def missing_created_at?(result_instance)
|
88
|
+
result_instance.respond_to?(:created_at) &&
|
89
|
+
result_instance.respond_to?(:created_at=) &&
|
90
|
+
result_instance.created_at.blank?
|
96
91
|
end
|
97
|
-
end
|
98
92
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
93
|
+
def missing_updated_at?(result_instance)
|
94
|
+
result_instance.respond_to?(:updated_at) &&
|
95
|
+
result_instance.respond_to?(:updated_at=) &&
|
96
|
+
result_instance.updated_at.blank?
|
103
97
|
end
|
104
98
|
end
|
105
99
|
end
|
@@ -29,7 +29,7 @@ module FactoryBot
|
|
29
29
|
raise ArgumentError, "count missing for #{strategy_name}_list"
|
30
30
|
end
|
31
31
|
|
32
|
-
amount
|
32
|
+
Array.new(amount) { send(strategy_name, name, *traits_and_overrides, &block) }
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
@@ -37,7 +37,7 @@ module FactoryBot
|
|
37
37
|
strategy_name = @strategy_name
|
38
38
|
|
39
39
|
define_syntax_method("#{strategy_name}_pair") do |name, *traits_and_overrides, &block|
|
40
|
-
2
|
40
|
+
Array.new(2) { send(strategy_name, name, *traits_and_overrides, &block) }
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
data/lib/factory_bot/syntax.rb
CHANGED
@@ -59,7 +59,7 @@ module FactoryBot
|
|
59
59
|
end
|
60
60
|
|
61
61
|
class ModifyDSL
|
62
|
-
def factory(name,
|
62
|
+
def factory(name, _options = {}, &block)
|
63
63
|
factory = FactoryBot.factory_by_name(name)
|
64
64
|
proxy = FactoryBot::DefinitionProxy.new(factory.definition.overridable)
|
65
65
|
proxy.instance_eval(&block)
|
data/lib/factory_bot/trait.rb
CHANGED
@@ -4,7 +4,7 @@ module FactoryBot
|
|
4
4
|
attr_reader :name, :definition
|
5
5
|
|
6
6
|
def initialize(name, &block)
|
7
|
-
@name = name
|
7
|
+
@name = name.to_sym
|
8
8
|
@block = block
|
9
9
|
@definition = Definition.new(@name)
|
10
10
|
|
@@ -25,6 +25,7 @@ module FactoryBot
|
|
25
25
|
end
|
26
26
|
|
27
27
|
protected
|
28
|
+
|
28
29
|
attr_reader :block
|
29
30
|
end
|
30
31
|
end
|