factory_bot 5.0.1 → 5.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/GETTING_STARTED.md +22 -14
- data/NEWS.md +23 -1
- data/README.md +15 -8
- data/lib/factory_bot.rb +50 -88
- data/lib/factory_bot/attribute/dynamic.rb +1 -0
- data/lib/factory_bot/attribute_assigner.rb +1 -1
- data/lib/factory_bot/callback.rb +2 -2
- data/lib/factory_bot/configuration.rb +1 -1
- data/lib/factory_bot/declaration/association.rb +11 -0
- data/lib/factory_bot/declaration/implicit.rb +4 -1
- data/lib/factory_bot/decorator.rb +1 -1
- data/lib/factory_bot/decorator/invocation_tracker.rb +1 -1
- data/lib/factory_bot/definition.rb +6 -4
- data/lib/factory_bot/definition_hierarchy.rb +1 -11
- data/lib/factory_bot/definition_proxy.rb +14 -7
- data/lib/factory_bot/errors.rb +3 -0
- data/lib/factory_bot/evaluator.rb +2 -2
- data/lib/factory_bot/factory.rb +1 -1
- data/lib/factory_bot/factory_runner.rb +2 -2
- data/lib/factory_bot/internal.rb +81 -1
- data/lib/factory_bot/linter.rb +4 -4
- data/lib/factory_bot/null_factory.rb +1 -1
- data/lib/factory_bot/registry.rb +2 -2
- data/lib/factory_bot/reload.rb +2 -2
- data/lib/factory_bot/strategy/stub.rb +10 -3
- data/lib/factory_bot/strategy_calculator.rb +1 -1
- data/lib/factory_bot/strategy_syntax_method_registrar.rb +12 -1
- data/lib/factory_bot/syntax/default.rb +11 -23
- data/lib/factory_bot/syntax/methods.rb +3 -3
- data/lib/factory_bot/trait.rb +5 -3
- data/lib/factory_bot/version.rb +1 -1
- metadata +12 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 802da48aa95dce3321f20d0173c5dcf041c5393fb0c270fb8ae2029ce12b6ed9
|
4
|
+
data.tar.gz: 0aa227896ef66ccf100f88b1aa4e9aa26c5bc657fee76739a73e15072bc80572
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63554d6765398f0c524cb8cd45b1a0da83da1d8aba9f359d0e4c44e42cdbd0d93edb8e38c668e0310ad709905c5cd6a3c35e640ad8c45a06a8b7d4090b4e6161
|
7
|
+
data.tar.gz: fe3be69bdd601384da0a7f2ec7e1fcf00ae7d4984c65423e31e94c1b7f3d7bb04345371daaea19d794365972b59f69f9f3403b0ef8b8ef7d7349d89404284ac2
|
data/GETTING_STARTED.md
CHANGED
@@ -30,7 +30,7 @@ Configure your test suite
|
|
30
30
|
|
31
31
|
### RSpec
|
32
32
|
|
33
|
-
If you're using Rails
|
33
|
+
If you're using Rails, add the following configuration to `spec/support/factory_bot.rb` and be sure to require that file in `rails_helper.rb`:
|
34
34
|
|
35
35
|
```ruby
|
36
36
|
RSpec.configure do |config|
|
@@ -387,7 +387,7 @@ post.new_record? # => true
|
|
387
387
|
post.author.new_record? # => false
|
388
388
|
```
|
389
389
|
|
390
|
-
To not save the associated object, specify strategy: :build in the factory:
|
390
|
+
To not save the associated object, specify `strategy: :build` in the factory:
|
391
391
|
|
392
392
|
```ruby
|
393
393
|
FactoryBot.use_parent_strategy = false
|
@@ -510,20 +510,20 @@ create(:profile_with_languages, languages_count: 15).languages.length # 15
|
|
510
510
|
|
511
511
|
Polymorphic associations can be handled with traits:
|
512
512
|
|
513
|
-
```
|
513
|
+
```ruby
|
514
514
|
FactoryBot.define do
|
515
515
|
factory :video
|
516
516
|
factory :photo
|
517
517
|
|
518
518
|
factory :comment do
|
519
|
-
for_photo
|
519
|
+
for_photo # default to the :for_photo trait if none is specified
|
520
520
|
|
521
521
|
trait :for_video do
|
522
|
-
association
|
522
|
+
association :commentable, factory: :video
|
523
523
|
end
|
524
524
|
|
525
525
|
trait :for_photo do
|
526
|
-
association
|
526
|
+
association :commentable, factory: :photo
|
527
527
|
end
|
528
528
|
end
|
529
529
|
end
|
@@ -531,7 +531,7 @@ end
|
|
531
531
|
|
532
532
|
This allows us to do:
|
533
533
|
|
534
|
-
```
|
534
|
+
```ruby
|
535
535
|
create(:comment)
|
536
536
|
create(:comment, :for_video)
|
537
537
|
create(:comment, :for_photo)
|
@@ -961,7 +961,7 @@ If a gem were to give you a User factory:
|
|
961
961
|
```ruby
|
962
962
|
FactoryBot.define do
|
963
963
|
factory :user do
|
964
|
-
full_name "John Doe"
|
964
|
+
full_name { "John Doe" }
|
965
965
|
sequence(:username) { |n| "user#{n}" }
|
966
966
|
password { "password" }
|
967
967
|
end
|
@@ -1018,6 +1018,14 @@ To set the attributes for each of the factories, you can pass in a hash as you n
|
|
1018
1018
|
twenty_year_olds = build_list(:user, 25, date_of_birth: 20.years.ago)
|
1019
1019
|
```
|
1020
1020
|
|
1021
|
+
In order to set different attributes for each factory, these methods may be passed a block, with the factory and the index as parameters:
|
1022
|
+
|
1023
|
+
```ruby
|
1024
|
+
twenty_somethings = build_list(:user, 10) do |user, i|
|
1025
|
+
user.date_of_birth = (20 + i).years.ago
|
1026
|
+
end
|
1027
|
+
```
|
1028
|
+
|
1021
1029
|
`build_stubbed_list` will give you fully stubbed out instances:
|
1022
1030
|
|
1023
1031
|
```ruby
|
@@ -1067,9 +1075,10 @@ namespace :factory_bot do
|
|
1067
1075
|
desc "Verify that all FactoryBot factories are valid"
|
1068
1076
|
task lint: :environment do
|
1069
1077
|
if Rails.env.test?
|
1070
|
-
|
1071
|
-
|
1078
|
+
conn = ActiveRecord::Base.connection
|
1079
|
+
conn.transaction do
|
1072
1080
|
FactoryBot.lint
|
1081
|
+
raise ActiveRecord::Rollback
|
1073
1082
|
end
|
1074
1083
|
else
|
1075
1084
|
system("bundle exec rake factory_bot:lint RAILS_ENV='test'")
|
@@ -1081,8 +1090,7 @@ end
|
|
1081
1090
|
|
1082
1091
|
After calling `FactoryBot.lint`, you'll likely want to clear out the
|
1083
1092
|
database, as records will most likely be created. The provided example above
|
1084
|
-
uses
|
1085
|
-
gem to your Gemfile under the appropriate groups.
|
1093
|
+
uses an sql transaction and rollback to leave the database clean.
|
1086
1094
|
|
1087
1095
|
You can lint factories selectively by passing only factories you want linted:
|
1088
1096
|
|
@@ -1413,12 +1421,12 @@ with associations, as below:
|
|
1413
1421
|
|
1414
1422
|
```ruby
|
1415
1423
|
FactoryBot.define do
|
1416
|
-
factory :united_states, class: Location do
|
1424
|
+
factory :united_states, class: "Location" do
|
1417
1425
|
name { 'United States' }
|
1418
1426
|
association :location_group, factory: :north_america
|
1419
1427
|
end
|
1420
1428
|
|
1421
|
-
factory :north_america, class: LocationGroup do
|
1429
|
+
factory :north_america, class: "LocationGroup" do
|
1422
1430
|
name { 'North America' }
|
1423
1431
|
end
|
1424
1432
|
end
|
data/NEWS.md
CHANGED
@@ -1,10 +1,32 @@
|
|
1
1
|
# News
|
2
2
|
|
3
|
+
## 5.2.0 (April 24, 2020)
|
4
|
+
* Added: Pass index to block for `*_list` methods
|
5
|
+
* Deprecated: top-level methods meant only for internal use: `callbacks`, `configuration`, `constructor`, `initialize_with`, `register_sequence`, `resent_configuration`, `skip_create`, `to_create`
|
6
|
+
|
7
|
+
## 5.1.2 (March 25, 2020)
|
8
|
+
* Fixed: Ruby 2.7 keyword deprecation warning in FactoryBot.lint
|
9
|
+
|
10
|
+
## 5.1.1 (October 2, 2019)
|
11
|
+
* Improved: performance of traits
|
12
|
+
* Fixed: registering strategies on JRuby
|
13
|
+
|
14
|
+
## 5.1.0 (September 21, 2019)
|
15
|
+
* Added: "Did you mean?" style error message to help with typos in association declarations
|
16
|
+
* Changed: `NoMethodError` for static attributes now offers a "Did you mean?" style message
|
17
|
+
* Fixed: avoid undefining inherited evaluator methods
|
18
|
+
* Fixed: avoid stubbing id for records without a primary key
|
19
|
+
* Fixed: raise a helpful error for self-referencing traits to avoid a `SystemStackError`
|
20
|
+
* Deprecated: top-level methods meant only for internal use: `allow_class_lookup`, `allow_class_lookup`=, `register_trait`, `trait_by_name`, `traits`, `sequence_by_name`, `sequences`, `factory_by_name`, `register_factory`, `callback_names`, `register_callback`, `register_default_callbacks`, `register_default_strategies`, `strategies`
|
21
|
+
|
22
|
+
## 5.0.2 (February 22, 2019)
|
23
|
+
* Bugfix: raise "Trait not registered" error when passing invalid trait arguments
|
24
|
+
|
3
25
|
## 5.0.1 (February 15, 2019)
|
4
26
|
* Bugfix: Do not raise error when two sequences have the same name
|
5
27
|
in two traits that have the same name
|
6
28
|
|
7
|
-
## 5.0.0
|
29
|
+
## 5.0.0 (February 1, 2019)
|
8
30
|
* Added: Verbose option to include full backtraces in the linting output
|
9
31
|
* Changed: use_parent_strategy now defaults to true, so by default the
|
10
32
|
build strategy will build, rather than create associations
|
data/README.md
CHANGED
@@ -5,7 +5,7 @@ factory_bot is a fixtures replacement with a straightforward definition syntax,
|
|
5
5
|
If you want to use factory_bot with Rails, see
|
6
6
|
[factory_bot_rails](https://github.com/thoughtbot/factory_bot_rails).
|
7
7
|
|
8
|
-
_[Interested in the history of the project name?]
|
8
|
+
_[Interested in the history of the project name?][NAME]_
|
9
9
|
|
10
10
|
|
11
11
|
### Transitioning from factory\_girl?
|
@@ -59,30 +59,37 @@ More Information
|
|
59
59
|
* [Issues](https://github.com/thoughtbot/factory_bot/issues)
|
60
60
|
* [GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS](https://robots.thoughtbot.com/)
|
61
61
|
|
62
|
-
|
62
|
+
[GETTING_STARTED]: https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md
|
63
|
+
[NAME]: https://github.com/thoughtbot/factory_bot/blob/master/NAME.md
|
63
64
|
|
64
|
-
|
65
|
+
Useful Tools
|
66
|
+
------------
|
67
|
+
|
68
|
+
* [FactoryTrace](https://github.com/djezzzl/factory_trace) - helps to find unused factories and traits.
|
65
69
|
|
66
70
|
Contributing
|
67
71
|
------------
|
68
72
|
|
69
73
|
Please see [CONTRIBUTING.md](https://github.com/thoughtbot/factory_bot/blob/master/CONTRIBUTING.md).
|
70
74
|
|
71
|
-
factory_bot was originally written by Joe Ferris and is
|
72
|
-
|
75
|
+
factory_bot was originally written by Joe Ferris and is maintained by thoughtbot.
|
76
|
+
Many improvements and bugfixes were contributed by the [open source
|
73
77
|
community](https://github.com/thoughtbot/factory_bot/graphs/contributors).
|
74
78
|
|
75
79
|
License
|
76
80
|
-------
|
77
81
|
|
78
|
-
factory_bot is Copyright © 2008-
|
82
|
+
factory_bot is Copyright © 2008-2020 Joe Ferris and thoughtbot. It is free
|
79
83
|
software, and may be redistributed under the terms specified in the
|
80
|
-
[LICENSE]
|
84
|
+
[LICENSE] file.
|
85
|
+
|
86
|
+
[LICENSE]: https://github.com/thoughtbot/factory_bot/blob/master/LICENSE
|
87
|
+
|
81
88
|
|
82
89
|
About thoughtbot
|
83
90
|
----------------
|
84
91
|
|
85
|
-
![thoughtbot](https://
|
92
|
+
![thoughtbot](https://thoughtbot.com/brand_assets/93:44.svg)
|
86
93
|
|
87
94
|
factory_bot is maintained and funded by thoughtbot, inc.
|
88
95
|
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
data/lib/factory_bot.rb
CHANGED
@@ -4,6 +4,7 @@ require "active_support/core_ext/module/attribute_accessors"
|
|
4
4
|
require "active_support/deprecation"
|
5
5
|
require "active_support/notifications"
|
6
6
|
|
7
|
+
require "factory_bot/internal"
|
7
8
|
require "factory_bot/definition_hierarchy"
|
8
9
|
require "factory_bot/configuration"
|
9
10
|
require "factory_bot/errors"
|
@@ -45,18 +46,9 @@ require "factory_bot/decorator/invocation_tracker"
|
|
45
46
|
require "factory_bot/decorator/new_constructor"
|
46
47
|
require "factory_bot/linter"
|
47
48
|
require "factory_bot/version"
|
48
|
-
require "factory_bot/internal"
|
49
49
|
|
50
50
|
module FactoryBot
|
51
|
-
|
52
|
-
|
53
|
-
def self.configuration
|
54
|
-
Internal.configuration
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.reset_configuration
|
58
|
-
Internal.reset_configuration
|
59
|
-
end
|
51
|
+
Deprecation = ActiveSupport::Deprecation.new("6.0", "factory_bot")
|
60
52
|
|
61
53
|
mattr_accessor :use_parent_strategy, instance_accessor: false
|
62
54
|
self.use_parent_strategy = true
|
@@ -71,93 +63,63 @@ module FactoryBot
|
|
71
63
|
def self.lint(*args)
|
72
64
|
options = args.extract_options!
|
73
65
|
factories_to_lint = args[0] || FactoryBot.factories
|
74
|
-
Linter.new(factories_to_lint, options).lint!
|
66
|
+
Linter.new(factories_to_lint, **options).lint!
|
75
67
|
end
|
76
68
|
|
77
69
|
class << self
|
78
|
-
delegate :
|
79
|
-
:sequences,
|
80
|
-
:traits,
|
70
|
+
delegate :callback_names,
|
81
71
|
:callbacks,
|
72
|
+
:configuration,
|
73
|
+
:constructor,
|
74
|
+
:factories,
|
75
|
+
:factory_by_name,
|
76
|
+
:initialize_with,
|
77
|
+
:register_callback,
|
78
|
+
:register_default_callbacks,
|
79
|
+
:register_default_strategies,
|
80
|
+
:register_factory,
|
81
|
+
:register_sequence,
|
82
|
+
:register_strategy,
|
83
|
+
:register_trait,
|
84
|
+
:reset_configuration,
|
85
|
+
:rewind_sequences,
|
86
|
+
:sequence_by_name,
|
87
|
+
:sequences,
|
88
|
+
:skip_create,
|
82
89
|
:strategies,
|
83
|
-
:
|
90
|
+
:strategy_by_name,
|
84
91
|
:to_create,
|
85
|
-
:
|
86
|
-
:
|
87
|
-
:
|
88
|
-
to: :configuration
|
92
|
+
:trait_by_name,
|
93
|
+
:traits,
|
94
|
+
to: Internal
|
89
95
|
|
90
96
|
attr_accessor :allow_class_lookup
|
91
|
-
deprecate :allow_class_lookup, :allow_class_lookup=, deprecator: DEPRECATOR
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.register_factory(factory)
|
95
|
-
factory.names.each do |name|
|
96
|
-
factories.register(name, factory)
|
97
|
-
end
|
98
|
-
factory
|
99
|
-
end
|
100
|
-
|
101
|
-
def self.factory_by_name(name)
|
102
|
-
factories.find(name)
|
103
|
-
end
|
104
|
-
|
105
|
-
def self.register_sequence(sequence)
|
106
|
-
sequence.names.each do |name|
|
107
|
-
sequences.register(name, sequence)
|
108
|
-
end
|
109
|
-
sequence
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.sequence_by_name(name)
|
113
|
-
sequences.find(name)
|
114
|
-
end
|
115
|
-
|
116
|
-
def self.rewind_sequences
|
117
|
-
sequences.each(&:rewind)
|
118
|
-
Internal.rewind_inline_sequences
|
119
|
-
end
|
120
|
-
|
121
|
-
def self.register_trait(trait)
|
122
|
-
trait.names.each do |name|
|
123
|
-
traits.register(name, trait)
|
124
|
-
end
|
125
|
-
trait
|
126
|
-
end
|
127
|
-
|
128
|
-
def self.trait_by_name(name)
|
129
|
-
traits.find(name)
|
130
|
-
end
|
131
|
-
|
132
|
-
def self.register_strategy(strategy_name, strategy_class)
|
133
|
-
strategies.register(strategy_name, strategy_class)
|
134
|
-
StrategySyntaxMethodRegistrar.new(strategy_name).define_strategy_methods
|
135
|
-
end
|
136
|
-
|
137
|
-
def self.strategy_by_name(name)
|
138
|
-
strategies.find(name)
|
139
|
-
end
|
140
|
-
|
141
|
-
def self.register_default_strategies
|
142
|
-
register_strategy(:build, FactoryBot::Strategy::Build)
|
143
|
-
register_strategy(:create, FactoryBot::Strategy::Create)
|
144
|
-
register_strategy(:attributes_for, FactoryBot::Strategy::AttributesFor)
|
145
|
-
register_strategy(:build_stubbed, FactoryBot::Strategy::Stub)
|
146
|
-
register_strategy(:null, FactoryBot::Strategy::Null)
|
147
|
-
end
|
148
|
-
|
149
|
-
def self.register_default_callbacks
|
150
|
-
register_callback(:after_build)
|
151
|
-
register_callback(:after_create)
|
152
|
-
register_callback(:after_stub)
|
153
|
-
register_callback(:before_create)
|
154
|
-
end
|
155
97
|
|
156
|
-
|
157
|
-
|
158
|
-
|
98
|
+
deprecate :allow_class_lookup,
|
99
|
+
:allow_class_lookup=,
|
100
|
+
:callback_names,
|
101
|
+
:callbacks,
|
102
|
+
:configuration,
|
103
|
+
:constructor,
|
104
|
+
:factory_by_name,
|
105
|
+
:initialize_with,
|
106
|
+
:register_callback,
|
107
|
+
:register_default_callbacks,
|
108
|
+
:register_default_strategies,
|
109
|
+
:register_factory,
|
110
|
+
:register_sequence,
|
111
|
+
:register_trait,
|
112
|
+
:reset_configuration,
|
113
|
+
:sequence_by_name,
|
114
|
+
:sequences,
|
115
|
+
:skip_create,
|
116
|
+
:strategies,
|
117
|
+
:to_create,
|
118
|
+
:trait_by_name,
|
119
|
+
:traits,
|
120
|
+
deprecator: Deprecation
|
159
121
|
end
|
160
122
|
end
|
161
123
|
|
162
|
-
FactoryBot.register_default_strategies
|
163
|
-
FactoryBot.register_default_callbacks
|
124
|
+
FactoryBot::Internal.register_default_strategies
|
125
|
+
FactoryBot::Internal.register_default_callbacks
|
@@ -2,7 +2,7 @@ module FactoryBot
|
|
2
2
|
# @api private
|
3
3
|
class AttributeAssigner
|
4
4
|
def initialize(evaluator, build_class, &instance_builder)
|
5
|
-
@build_class
|
5
|
+
@build_class = build_class
|
6
6
|
@instance_builder = instance_builder
|
7
7
|
@evaluator = evaluator
|
8
8
|
@attribute_list = evaluator.class.attribute_list
|
data/lib/factory_bot/callback.rb
CHANGED
@@ -28,9 +28,9 @@ module FactoryBot
|
|
28
28
|
private
|
29
29
|
|
30
30
|
def ensure_valid_callback_name!
|
31
|
-
unless FactoryBot.callback_names.include?(name)
|
31
|
+
unless FactoryBot::Internal.callback_names.include?(name)
|
32
32
|
raise InvalidCallbackNameError, "#{name} is not a valid callback name. " +
|
33
|
-
"Valid callback names are #{FactoryBot.callback_names.inspect}"
|
33
|
+
"Valid callback names are #{FactoryBot::Internal.callback_names.inspect}"
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
@@ -22,9 +22,20 @@ module FactoryBot
|
|
22
22
|
private
|
23
23
|
|
24
24
|
def build
|
25
|
+
ensure_factory_is_not_a_declaration!
|
26
|
+
|
25
27
|
factory_name = @overrides[:factory] || name
|
26
28
|
[Attribute::Association.new(name, factory_name, [@traits, @overrides.except(:factory)].flatten)]
|
27
29
|
end
|
30
|
+
|
31
|
+
def ensure_factory_is_not_a_declaration!
|
32
|
+
if @overrides[:factory].is_a?(Declaration)
|
33
|
+
raise ArgumentError.new(<<~MSG)
|
34
|
+
Association '#{name}' received an invalid factory argument.
|
35
|
+
Did you mean? 'factory: :#{@overrides[:factory].name}'
|
36
|
+
MSG
|
37
|
+
end
|
38
|
+
end
|
28
39
|
end
|
29
40
|
end
|
30
41
|
end
|
@@ -23,8 +23,11 @@ module FactoryBot
|
|
23
23
|
def build
|
24
24
|
if FactoryBot.factories.registered?(name)
|
25
25
|
[Attribute::Association.new(name, name, {})]
|
26
|
-
elsif FactoryBot.sequences.registered?(name)
|
26
|
+
elsif FactoryBot::Internal.sequences.registered?(name)
|
27
27
|
[Attribute::Sequence.new(name, name, @ignored)]
|
28
|
+
elsif @factory.name.to_s == name.to_s
|
29
|
+
message = "Self-referencing trait '#{@name}'"
|
30
|
+
raise TraitDefinitionError, message
|
28
31
|
else
|
29
32
|
@factory.inherit_traits([name])
|
30
33
|
[]
|
@@ -6,7 +6,7 @@ module FactoryBot
|
|
6
6
|
@component = component
|
7
7
|
end
|
8
8
|
|
9
|
-
def method_missing(name, *args, &block) # rubocop:disable Style/
|
9
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MethodMissingSuper
|
10
10
|
@component.send(name, *args, &block)
|
11
11
|
end
|
12
12
|
|
@@ -49,7 +49,7 @@ module FactoryBot
|
|
49
49
|
|
50
50
|
defined_traits.each do |defined_trait|
|
51
51
|
base_traits.each { |bt| bt.define_trait defined_trait }
|
52
|
-
additional_traits.each { |
|
52
|
+
additional_traits.each { |at| at.define_trait defined_trait }
|
53
53
|
end
|
54
54
|
|
55
55
|
@compiled = true
|
@@ -95,7 +95,7 @@ module FactoryBot
|
|
95
95
|
|
96
96
|
def callback(*names, &block)
|
97
97
|
names.each do |name|
|
98
|
-
FactoryBot.register_callback(name)
|
98
|
+
FactoryBot::Internal.register_callback(name)
|
99
99
|
add_callback(Callback.new(name, block))
|
100
100
|
end
|
101
101
|
end
|
@@ -111,17 +111,19 @@ module FactoryBot
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def trait_by_name(name)
|
114
|
-
trait_for(name) ||
|
114
|
+
trait_for(name) || Internal.trait_by_name(name)
|
115
115
|
end
|
116
116
|
|
117
117
|
def trait_for(name)
|
118
|
-
defined_traits.
|
118
|
+
@defined_traits_by_name ||= defined_traits.each_with_object({}) { |t, memo| memo[t.name] ||= t }
|
119
|
+
@defined_traits_by_name[name.to_s]
|
119
120
|
end
|
120
121
|
|
121
122
|
def initialize_copy(source)
|
122
123
|
super
|
123
124
|
@attributes = nil
|
124
125
|
@compiled = false
|
126
|
+
@defined_traits_by_name = nil
|
125
127
|
end
|
126
128
|
|
127
129
|
def aggregate_from_traits_and_self(method_name, &block)
|
@@ -1,16 +1,6 @@
|
|
1
1
|
module FactoryBot
|
2
2
|
class DefinitionHierarchy
|
3
|
-
|
4
|
-
FactoryBot.callbacks
|
5
|
-
end
|
6
|
-
|
7
|
-
def constructor
|
8
|
-
FactoryBot.constructor
|
9
|
-
end
|
10
|
-
|
11
|
-
def to_create
|
12
|
-
FactoryBot.to_create
|
13
|
-
end
|
3
|
+
delegate :callbacks, :constructor, :to_create, to: Internal
|
14
4
|
|
15
5
|
def self.build_from_definition(definition)
|
16
6
|
build_to_create(&definition.to_create)
|
@@ -88,15 +88,18 @@ module FactoryBot
|
|
88
88
|
# end
|
89
89
|
#
|
90
90
|
# are equivalent.
|
91
|
-
def method_missing(name, *args, &block) # rubocop:disable Style/
|
92
|
-
|
91
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing, Style/MethodMissingSuper
|
92
|
+
association_options = args.first
|
93
|
+
|
94
|
+
if association_options.nil?
|
93
95
|
__declare_attribute__(name, block)
|
94
|
-
elsif
|
95
|
-
association(name,
|
96
|
+
elsif __valid_association_options?(association_options)
|
97
|
+
association(name, association_options)
|
96
98
|
else
|
97
|
-
raise NoMethodError.new(
|
98
|
-
|
99
|
-
|
99
|
+
raise NoMethodError.new(<<~MSG)
|
100
|
+
undefined method '#{name}' in '#{@definition.name}' factory
|
101
|
+
Did you mean? '#{name} { #{association_options.inspect} }'
|
102
|
+
MSG
|
100
103
|
end
|
101
104
|
end
|
102
105
|
|
@@ -187,5 +190,9 @@ module FactoryBot
|
|
187
190
|
add_attribute(name, &block)
|
188
191
|
end
|
189
192
|
end
|
193
|
+
|
194
|
+
def __valid_association_options?(options)
|
195
|
+
options.respond_to?(:has_key?) && options.has_key?(:factory)
|
196
|
+
end
|
190
197
|
end
|
191
198
|
end
|
data/lib/factory_bot/errors.rb
CHANGED
@@ -2,6 +2,9 @@ module FactoryBot
|
|
2
2
|
# Raised when a factory is defined that attempts to instantiate itself.
|
3
3
|
class AssociationDefinitionError < RuntimeError; end
|
4
4
|
|
5
|
+
# Raised when a trait is defined that references itself.
|
6
|
+
class TraitDefinitionError < RuntimeError; end
|
7
|
+
|
5
8
|
# Raised when a callback is defined that has an invalid name
|
6
9
|
class InvalidCallbackNameError < RuntimeError; end
|
7
10
|
|
@@ -37,7 +37,7 @@ module FactoryBot
|
|
37
37
|
@instance = object_instance
|
38
38
|
end
|
39
39
|
|
40
|
-
def method_missing(method_name, *args, &block) # rubocop:disable Style/
|
40
|
+
def method_missing(method_name, *args, &block) # rubocop:disable Style/MethodMissingSuper
|
41
41
|
if @instance.respond_to?(method_name)
|
42
42
|
@instance.send(method_name, *args, &block)
|
43
43
|
else
|
@@ -66,7 +66,7 @@ module FactoryBot
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def self.define_attribute(name, &block)
|
69
|
-
if
|
69
|
+
if instance_methods(false).include?(name) || private_instance_methods(false).include?(name)
|
70
70
|
undef_method(name)
|
71
71
|
end
|
72
72
|
|
data/lib/factory_bot/factory.rb
CHANGED
@@ -5,11 +5,11 @@ 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
|
9
9
|
end
|
10
10
|
|
11
11
|
def run(runner_strategy = @strategy, &block)
|
12
|
-
factory = FactoryBot.factory_by_name(@name)
|
12
|
+
factory = FactoryBot::Internal.factory_by_name(@name)
|
13
13
|
|
14
14
|
factory.compile
|
15
15
|
|
data/lib/factory_bot/internal.rb
CHANGED
@@ -2,7 +2,20 @@ module FactoryBot
|
|
2
2
|
# @api private
|
3
3
|
module Internal
|
4
4
|
class << self
|
5
|
-
delegate :
|
5
|
+
delegate :after,
|
6
|
+
:before,
|
7
|
+
:callback_names,
|
8
|
+
:callbacks,
|
9
|
+
:constructor,
|
10
|
+
:factories,
|
11
|
+
:initialize_with,
|
12
|
+
:inline_sequences,
|
13
|
+
:sequences,
|
14
|
+
:skip_create,
|
15
|
+
:strategies,
|
16
|
+
:to_create,
|
17
|
+
:traits,
|
18
|
+
to: :configuration
|
6
19
|
|
7
20
|
def configuration
|
8
21
|
@configuration ||= Configuration.new
|
@@ -19,6 +32,73 @@ module FactoryBot
|
|
19
32
|
def rewind_inline_sequences
|
20
33
|
inline_sequences.each(&:rewind)
|
21
34
|
end
|
35
|
+
|
36
|
+
def register_trait(trait)
|
37
|
+
trait.names.each do |name|
|
38
|
+
traits.register(name, trait)
|
39
|
+
end
|
40
|
+
trait
|
41
|
+
end
|
42
|
+
|
43
|
+
def trait_by_name(name)
|
44
|
+
traits.find(name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def register_sequence(sequence)
|
48
|
+
sequence.names.each do |name|
|
49
|
+
sequences.register(name, sequence)
|
50
|
+
end
|
51
|
+
sequence
|
52
|
+
end
|
53
|
+
|
54
|
+
def sequence_by_name(name)
|
55
|
+
sequences.find(name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def rewind_sequences
|
59
|
+
sequences.each(&:rewind)
|
60
|
+
rewind_inline_sequences
|
61
|
+
end
|
62
|
+
|
63
|
+
def register_factory(factory)
|
64
|
+
factory.names.each do |name|
|
65
|
+
factories.register(name, factory)
|
66
|
+
end
|
67
|
+
factory
|
68
|
+
end
|
69
|
+
|
70
|
+
def factory_by_name(name)
|
71
|
+
factories.find(name)
|
72
|
+
end
|
73
|
+
|
74
|
+
def register_strategy(strategy_name, strategy_class)
|
75
|
+
strategies.register(strategy_name, strategy_class)
|
76
|
+
StrategySyntaxMethodRegistrar.new(strategy_name).define_strategy_methods
|
77
|
+
end
|
78
|
+
|
79
|
+
def strategy_by_name(name)
|
80
|
+
strategies.find(name)
|
81
|
+
end
|
82
|
+
|
83
|
+
def register_default_strategies
|
84
|
+
register_strategy(:build, FactoryBot::Strategy::Build)
|
85
|
+
register_strategy(:create, FactoryBot::Strategy::Create)
|
86
|
+
register_strategy(:attributes_for, FactoryBot::Strategy::AttributesFor)
|
87
|
+
register_strategy(:build_stubbed, FactoryBot::Strategy::Stub)
|
88
|
+
register_strategy(:null, FactoryBot::Strategy::Null)
|
89
|
+
end
|
90
|
+
|
91
|
+
def register_default_callbacks
|
92
|
+
register_callback(:after_create)
|
93
|
+
register_callback(:after_build)
|
94
|
+
register_callback(:after_stub)
|
95
|
+
register_callback(:before_create)
|
96
|
+
end
|
97
|
+
|
98
|
+
def register_callback(name)
|
99
|
+
name = name.to_sym
|
100
|
+
callback_names << name
|
101
|
+
end
|
22
102
|
end
|
23
103
|
end
|
24
104
|
end
|
data/lib/factory_bot/linter.rb
CHANGED
@@ -72,8 +72,8 @@ module FactoryBot
|
|
72
72
|
result = []
|
73
73
|
begin
|
74
74
|
FactoryBot.public_send(factory_strategy, factory.name)
|
75
|
-
rescue StandardError =>
|
76
|
-
result |= [FactoryError.new(
|
75
|
+
rescue StandardError => e
|
76
|
+
result |= [FactoryError.new(e, factory)]
|
77
77
|
end
|
78
78
|
result
|
79
79
|
end
|
@@ -83,9 +83,9 @@ module FactoryBot
|
|
83
83
|
factory.definition.defined_traits.map(&:name).each do |trait_name|
|
84
84
|
begin
|
85
85
|
FactoryBot.public_send(factory_strategy, factory.name, trait_name)
|
86
|
-
rescue StandardError =>
|
86
|
+
rescue StandardError => e
|
87
87
|
result |=
|
88
|
-
[FactoryTraitError.new(
|
88
|
+
[FactoryTraitError.new(e, factory, trait_name)]
|
89
89
|
end
|
90
90
|
end
|
91
91
|
result
|
data/lib/factory_bot/registry.rb
CHANGED
data/lib/factory_bot/reload.rb
CHANGED
@@ -44,15 +44,17 @@ module FactoryBot
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def stub_database_interaction_on_result(result_instance)
|
47
|
-
result_instance
|
47
|
+
if has_settable_id?(result_instance)
|
48
|
+
result_instance.id ||= next_id
|
49
|
+
end
|
48
50
|
|
49
51
|
result_instance.instance_eval do
|
50
52
|
def persisted?
|
51
|
-
|
53
|
+
true
|
52
54
|
end
|
53
55
|
|
54
56
|
def new_record?
|
55
|
-
|
57
|
+
false
|
56
58
|
end
|
57
59
|
|
58
60
|
def destroyed?
|
@@ -68,6 +70,11 @@ module FactoryBot
|
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
73
|
+
def has_settable_id?(result_instance)
|
74
|
+
!result_instance.class.respond_to?(:primary_key) ||
|
75
|
+
result_instance.class.primary_key
|
76
|
+
end
|
77
|
+
|
71
78
|
def clear_changes_information(result_instance)
|
72
79
|
if result_instance.respond_to?(:clear_changes_information)
|
73
80
|
result_instance.clear_changes_information
|
@@ -11,6 +11,14 @@ module FactoryBot
|
|
11
11
|
define_pair_strategy_method
|
12
12
|
end
|
13
13
|
|
14
|
+
def self.with_index(block, index)
|
15
|
+
if block&.arity == 2
|
16
|
+
->(instance) { block.call(instance, index) }
|
17
|
+
else
|
18
|
+
block
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
14
22
|
private
|
15
23
|
|
16
24
|
def define_singular_strategy_method
|
@@ -29,7 +37,10 @@ module FactoryBot
|
|
29
37
|
raise ArgumentError, "count missing for #{strategy_name}_list"
|
30
38
|
end
|
31
39
|
|
32
|
-
Array.new(amount)
|
40
|
+
Array.new(amount) do |i|
|
41
|
+
block_with_index = StrategySyntaxMethodRegistrar.with_index(block, i)
|
42
|
+
send(strategy_name, name, *traits_and_overrides, &block_with_index)
|
43
|
+
end
|
33
44
|
end
|
34
45
|
end
|
35
46
|
|
@@ -17,7 +17,7 @@ module FactoryBot
|
|
17
17
|
proxy = FactoryBot::DefinitionProxy.new(factory.definition)
|
18
18
|
proxy.instance_eval(&block) if block_given?
|
19
19
|
|
20
|
-
|
20
|
+
Internal.register_factory(factory)
|
21
21
|
|
22
22
|
proxy.child_factories.each do |(child_name, child_options, child_block)|
|
23
23
|
parent_factory = child_options.delete(:parent) || name
|
@@ -26,41 +26,29 @@ module FactoryBot
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def sequence(name, *args, &block)
|
29
|
-
|
29
|
+
Internal.register_sequence(Sequence.new(name, *args, &block))
|
30
30
|
end
|
31
31
|
|
32
32
|
def trait(name, &block)
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_create(&block)
|
37
|
-
FactoryBot.to_create(&block)
|
38
|
-
end
|
39
|
-
|
40
|
-
def skip_create
|
41
|
-
FactoryBot.skip_create
|
42
|
-
end
|
43
|
-
|
44
|
-
def initialize_with(&block)
|
45
|
-
FactoryBot.initialize_with(&block)
|
33
|
+
Internal.register_trait(Trait.new(name, &block))
|
46
34
|
end
|
47
35
|
|
48
36
|
def self.run(block)
|
49
37
|
new.instance_eval(&block)
|
50
38
|
end
|
51
39
|
|
52
|
-
delegate :
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
40
|
+
delegate :after,
|
41
|
+
:before,
|
42
|
+
:callback,
|
43
|
+
:initialize_with,
|
44
|
+
:skip_create,
|
45
|
+
:to_create,
|
46
|
+
to: FactoryBot::Internal
|
59
47
|
end
|
60
48
|
|
61
49
|
class ModifyDSL
|
62
50
|
def factory(name, _options = {}, &block)
|
63
|
-
factory =
|
51
|
+
factory = Internal.factory_by_name(name)
|
64
52
|
proxy = FactoryBot::DefinitionProxy.new(factory.definition.overridable)
|
65
53
|
proxy.instance_eval(&block)
|
66
54
|
end
|
@@ -30,7 +30,7 @@ module FactoryBot
|
|
30
30
|
## # factory with traits and attribute override
|
31
31
|
## build_stubbed_list(:user, 15, :admin, :male, name: "John Doe")
|
32
32
|
module Methods
|
33
|
-
# @!parse FactoryBot.register_default_strategies
|
33
|
+
# @!parse FactoryBot::Internal.register_default_strategies
|
34
34
|
# @!method build(name, *traits_and_overrides, &block)
|
35
35
|
# (see #strategy_method)
|
36
36
|
# Builds a registered factory by name.
|
@@ -111,7 +111,7 @@ module FactoryBot
|
|
111
111
|
# Returns:
|
112
112
|
# The next value in the sequence. (Object)
|
113
113
|
def generate(name)
|
114
|
-
|
114
|
+
Internal.sequence_by_name(name).next
|
115
115
|
end
|
116
116
|
|
117
117
|
# Generates and returns the list of values in a sequence.
|
@@ -126,7 +126,7 @@ module FactoryBot
|
|
126
126
|
# The next value in the sequence. (Object)
|
127
127
|
def generate_list(name, count)
|
128
128
|
(1..count).map do
|
129
|
-
|
129
|
+
Internal.sequence_by_name(name).next
|
130
130
|
end
|
131
131
|
end
|
132
132
|
end
|
data/lib/factory_bot/trait.rb
CHANGED
@@ -4,12 +4,14 @@ module FactoryBot
|
|
4
4
|
attr_reader :name, :definition
|
5
5
|
|
6
6
|
def initialize(name, &block)
|
7
|
-
@name = name.
|
7
|
+
@name = name.to_s
|
8
8
|
@block = block
|
9
9
|
@definition = Definition.new(@name)
|
10
|
-
|
11
10
|
proxy = FactoryBot::DefinitionProxy.new(@definition)
|
12
|
-
|
11
|
+
|
12
|
+
if block_given?
|
13
|
+
proxy.instance_eval(&@block)
|
14
|
+
end
|
13
15
|
end
|
14
16
|
|
15
17
|
delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
|
data/lib/factory_bot/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factory_bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.0
|
4
|
+
version: 5.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Clayton
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-04-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -127,18 +127,18 @@ dependencies:
|
|
127
127
|
name: rubocop
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
129
129
|
requirements:
|
130
|
-
- -
|
130
|
+
- - ">="
|
131
131
|
- !ruby/object:Gem::Version
|
132
|
-
version: '0
|
132
|
+
version: '0'
|
133
133
|
type: :development
|
134
134
|
prerelease: false
|
135
135
|
version_requirements: !ruby/object:Gem::Requirement
|
136
136
|
requirements:
|
137
|
-
- -
|
137
|
+
- - ">="
|
138
138
|
- !ruby/object:Gem::Version
|
139
|
-
version: '0
|
139
|
+
version: '0'
|
140
140
|
- !ruby/object:Gem::Dependency
|
141
|
-
name:
|
141
|
+
name: rubocop-performance
|
142
142
|
requirement: !ruby/object:Gem::Requirement
|
143
143
|
requirements:
|
144
144
|
- - ">="
|
@@ -152,7 +152,7 @@ dependencies:
|
|
152
152
|
- !ruby/object:Gem::Version
|
153
153
|
version: '0'
|
154
154
|
- !ruby/object:Gem::Dependency
|
155
|
-
name:
|
155
|
+
name: rubocop-rails
|
156
156
|
requirement: !ruby/object:Gem::Requirement
|
157
157
|
requirements:
|
158
158
|
- - ">="
|
@@ -166,7 +166,7 @@ dependencies:
|
|
166
166
|
- !ruby/object:Gem::Version
|
167
167
|
version: '0'
|
168
168
|
- !ruby/object:Gem::Dependency
|
169
|
-
name:
|
169
|
+
name: simplecov
|
170
170
|
requirement: !ruby/object:Gem::Requirement
|
171
171
|
requirements:
|
172
172
|
- - ">="
|
@@ -263,7 +263,8 @@ files:
|
|
263
263
|
homepage: https://github.com/thoughtbot/factory_bot
|
264
264
|
licenses:
|
265
265
|
- MIT
|
266
|
-
metadata:
|
266
|
+
metadata:
|
267
|
+
changelog_uri: https://github.com/thoughtbot/factory_bot/blob/master/NEWS.md
|
267
268
|
post_install_message:
|
268
269
|
rdoc_options: []
|
269
270
|
require_paths:
|
@@ -279,8 +280,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
279
280
|
- !ruby/object:Gem::Version
|
280
281
|
version: '0'
|
281
282
|
requirements: []
|
282
|
-
|
283
|
-
rubygems_version: 2.7.7
|
283
|
+
rubygems_version: 3.0.3
|
284
284
|
signing_key:
|
285
285
|
specification_version: 4
|
286
286
|
summary: factory_bot provides a framework and DSL for defining and using model instance
|