factory_bot 6.2.1 → 6.5.1
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/CONTRIBUTING.md +2 -2
- data/GETTING_STARTED.md +90 -6
- data/NEWS.md +93 -1
- data/README.md +27 -22
- data/lib/factory_bot/attribute/dynamic.rb +2 -2
- data/lib/factory_bot/attribute_assigner.rb +1 -1
- data/lib/factory_bot/decorator.rb +5 -17
- data/lib/factory_bot/definition.rb +34 -9
- data/lib/factory_bot/definition_proxy.rb +3 -3
- data/lib/factory_bot/evaluation.rb +3 -7
- data/lib/factory_bot/evaluator.rb +3 -4
- data/lib/factory_bot/factory.rb +14 -4
- data/lib/factory_bot/internal.rb +2 -2
- data/lib/factory_bot/linter.rb +13 -2
- data/lib/factory_bot/registry.rb +15 -3
- data/lib/factory_bot/strategy/stub.rb +19 -7
- data/lib/factory_bot/syntax/default.rb +2 -2
- data/lib/factory_bot/trait.rb +5 -1
- data/lib/factory_bot/version.rb +1 -1
- data/lib/factory_bot.rb +1 -0
- metadata +22 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71c90d06521a4d6e1bbd613bdc1494919b2acde4117153524a11d8fbea53301c
|
4
|
+
data.tar.gz: 7e19bf127cf040c9f59fea525894019358e0502de695cf5957ac5eb91280e1d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff1b56b976b423b91d8f633fdb0d1ed2d13b5c75665547adbb4d6f1d90b15aff35459dcb2fd6479e6dccdfd98ce3a9bd2a13b1ced002704fb84c39e2d5ebb3f3
|
7
|
+
data.tar.gz: dfc7713d8511e0723ab41da77257c901ca2d5abdf04b21b8f81332bd4f6e6568d403a68fc7831529ab8cbed531c25bc068458ee28fb2b1d7f0b7ebeafda02a3a
|
data/CONTRIBUTING.md
CHANGED
@@ -94,12 +94,12 @@ Use [standard] to automatically format your code:
|
|
94
94
|
bundle exec rake standard:fix
|
95
95
|
```
|
96
96
|
|
97
|
-
[repo]: https://github.com/thoughtbot/factory_bot/tree/
|
97
|
+
[repo]: https://github.com/thoughtbot/factory_bot/tree/main
|
98
98
|
[fork]: https://help.github.com/articles/fork-a-repo/
|
99
99
|
[branch]: https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/
|
100
100
|
[pr]: https://help.github.com/articles/using-pull-requests/
|
101
101
|
[standard]: https://github.com/testdouble/standard
|
102
102
|
[appraisal]: https://github.com/thoughtbot/appraisal
|
103
|
-
[reproduction script]: https://github.com/thoughtbot/factory_bot/blob/
|
103
|
+
[reproduction script]: https://github.com/thoughtbot/factory_bot/blob/main/.github/REPRODUCTION_SCRIPT.rb
|
104
104
|
|
105
105
|
Inspired by https://github.com/middleman/middleman-heroku/blob/master/CONTRIBUTING.md
|
data/GETTING_STARTED.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
**Deprecated**
|
2
|
+
|
3
|
+
See our extensive reference, guides, and cookbook in [the factory_bot book][].
|
4
|
+
|
5
|
+
For information on integrations with third party libraries, such as RSpec or
|
6
|
+
Rails, see [the factory_bot wiki][].
|
7
|
+
|
8
|
+
We also have [a detailed introductory video][], available for free on Upcase.
|
9
|
+
|
10
|
+
[a detailed introductory video]: https://upcase.com/videos/factory-bot?utm_source=github&utm_medium=open-source&utm_campaign=factory-girl
|
11
|
+
[the factory_bot book]: https://thoughtbot.github.io/factory_bot
|
12
|
+
[the factory_bot wiki]: https://github.com/thoughtbot/factory_bot/wiki
|
13
|
+
|
14
|
+
This document is deprecated and preserved for historical use. It may disappear
|
15
|
+
at any time.
|
16
|
+
|
1
17
|
Getting Started
|
2
18
|
===============
|
3
19
|
|
@@ -269,6 +285,9 @@ user = create(:user)
|
|
269
285
|
# Returns a hash of attributes that can be used to build a User instance
|
270
286
|
attrs = attributes_for(:user)
|
271
287
|
|
288
|
+
# Integrates with Ruby 3.0's support for pattern matching assignment
|
289
|
+
attributes_for(:user) => {email:, name:, **attrs}
|
290
|
+
|
272
291
|
# Returns an object with all defined attributes stubbed out
|
273
292
|
stub = build_stubbed(:user)
|
274
293
|
|
@@ -281,7 +300,7 @@ end
|
|
281
300
|
### Attribute overrides
|
282
301
|
|
283
302
|
No matter which strategy is used, it's possible to override the defined
|
284
|
-
attributes by passing a
|
303
|
+
attributes by passing a Hash:
|
285
304
|
|
286
305
|
```ruby
|
287
306
|
# Build a User instance and override the first_name property
|
@@ -290,6 +309,29 @@ user.first_name
|
|
290
309
|
# => "Joe"
|
291
310
|
```
|
292
311
|
|
312
|
+
Overriding associations is also supported:
|
313
|
+
|
314
|
+
```ruby
|
315
|
+
account = build(:account, :deluxe)
|
316
|
+
friends = build_list(:user, 2)
|
317
|
+
|
318
|
+
user = build(:user, account: account, friends: friends)
|
319
|
+
```
|
320
|
+
|
321
|
+
Ruby 3.1's support for [omitting values][] from `Hash` literals dovetails with
|
322
|
+
attribute overrides and provides an opportunity to limit the repetition of
|
323
|
+
variable names:
|
324
|
+
|
325
|
+
```ruby
|
326
|
+
account = build(:account, :deluxe)
|
327
|
+
friends = build_list(:user, 2)
|
328
|
+
|
329
|
+
# The keyword arguments correspond to local variable names, so omit their values
|
330
|
+
user = build(:user, account:, friends:)
|
331
|
+
```
|
332
|
+
|
333
|
+
[omitting values]: https://docs.ruby-lang.org/en/3.1/syntax/literals_rdoc.html#label-Hash+Literals
|
334
|
+
|
293
335
|
### `build_stubbed` and `Marshal.dump`
|
294
336
|
|
295
337
|
Note that objects created with `build_stubbed` cannot be serialized with
|
@@ -424,7 +466,7 @@ end
|
|
424
466
|
Method Name / Reserved Word Attributes
|
425
467
|
-------------------------------
|
426
468
|
|
427
|
-
If your attributes conflict with existing methods or reserved words (all methods in the [DefinitionProxy](https://github.com/thoughtbot/factory_bot/blob/
|
469
|
+
If your attributes conflict with existing methods or reserved words (all methods in the [DefinitionProxy](https://github.com/thoughtbot/factory_bot/blob/main/lib/factory_bot/definition_proxy.rb) class) you can define them with `add_attribute`.
|
428
470
|
|
429
471
|
```ruby
|
430
472
|
factory :dna do
|
@@ -929,7 +971,7 @@ end
|
|
929
971
|
Note that this approach works with `build`, `build_stubbed`, and `create`, but
|
930
972
|
the associations will return `nil` when using `attributes_for`.
|
931
973
|
|
932
|
-
Also, note that if you assign any attributes inside a custom `initialize_with`
|
974
|
+
Also, note that if you assign any attributes inside a custom `initialize_with`
|
933
975
|
(e.g. `initialize_with { new(**attributes) }`), those attributes should not refer to `instance`,
|
934
976
|
since it will be `nil`.
|
935
977
|
|
@@ -992,6 +1034,17 @@ factory :user do
|
|
992
1034
|
end
|
993
1035
|
```
|
994
1036
|
|
1037
|
+
With Ruby 2.7's support for [numbered parameters][], inline definitions can be
|
1038
|
+
even more abbreviated:
|
1039
|
+
|
1040
|
+
```ruby
|
1041
|
+
factory :user do
|
1042
|
+
sequence(:email) { "person#{_1}@example.com" }
|
1043
|
+
end
|
1044
|
+
```
|
1045
|
+
|
1046
|
+
[numbered parameters]: https://ruby-doc.org/core-2.7.1/Proc.html#class-Proc-label-Numbered+parameters
|
1047
|
+
|
995
1048
|
### Initial value
|
996
1049
|
|
997
1050
|
You can override the initial value. Any value that responds to the `#next`
|
@@ -1206,11 +1259,11 @@ FactoryBot.define do
|
|
1206
1259
|
created_at { 8.days.ago }
|
1207
1260
|
updated_at { 4.days.ago }
|
1208
1261
|
end
|
1209
|
-
|
1262
|
+
|
1210
1263
|
factory :user, traits: [:timestamps] do
|
1211
1264
|
username { "john_doe" }
|
1212
1265
|
end
|
1213
|
-
|
1266
|
+
|
1214
1267
|
factory :post do
|
1215
1268
|
timestamps
|
1216
1269
|
title { "Traits rock" }
|
@@ -1872,6 +1925,10 @@ class JsonStrategy
|
|
1872
1925
|
def result(evaluation)
|
1873
1926
|
@strategy.result(evaluation).to_json
|
1874
1927
|
end
|
1928
|
+
|
1929
|
+
def to_sym
|
1930
|
+
:json
|
1931
|
+
end
|
1875
1932
|
end
|
1876
1933
|
```
|
1877
1934
|
|
@@ -1912,6 +1969,10 @@ class JsonStrategy
|
|
1912
1969
|
evaluation.notify(:make_json_awesome, json)
|
1913
1970
|
end
|
1914
1971
|
end
|
1972
|
+
|
1973
|
+
def to_sym
|
1974
|
+
:json
|
1975
|
+
end
|
1915
1976
|
end
|
1916
1977
|
|
1917
1978
|
FactoryBot.register_strategy(:json, JsonStrategy)
|
@@ -1966,7 +2027,7 @@ ActiveSupport Instrumentation
|
|
1966
2027
|
|
1967
2028
|
In order to track what factories are created (and with what build strategy),
|
1968
2029
|
`ActiveSupport::Notifications` are included to provide a way to subscribe to
|
1969
|
-
factories being run. One example would be to track factories based on a
|
2030
|
+
factories being compiled and run. One example would be to track factories based on a
|
1970
2031
|
threshold of execution time.
|
1971
2032
|
|
1972
2033
|
```ruby
|
@@ -2000,6 +2061,29 @@ config.after(:suite) do
|
|
2000
2061
|
end
|
2001
2062
|
```
|
2002
2063
|
|
2064
|
+
Another example could involve tracking the attributes and traits that factories are compiled with. If you're using RSpec, you could add `before(:suite)` and `after(:suite)` blocks that subscribe to `factory_bot.compile_factory` notifications:
|
2065
|
+
|
2066
|
+
```ruby
|
2067
|
+
factory_bot_results = {}
|
2068
|
+
config.before(:suite) do
|
2069
|
+
ActiveSupport::Notifications.subscribe("factory_bot.compile_factory") do |name, start, finish, id, payload|
|
2070
|
+
factory_name = payload[:name]
|
2071
|
+
factory_class = payload[:class]
|
2072
|
+
attributes = payload[:attributes]
|
2073
|
+
traits = payload[:traits]
|
2074
|
+
factory_bot_results[factory_class] ||= {}
|
2075
|
+
factory_bot_results[factory_class][factory_name] = {
|
2076
|
+
attributes: attributes.map(&:name)
|
2077
|
+
traits: traits.map(&:name)
|
2078
|
+
}
|
2079
|
+
end
|
2080
|
+
end
|
2081
|
+
|
2082
|
+
config.after(:suite) do
|
2083
|
+
puts factory_bot_results
|
2084
|
+
end
|
2085
|
+
```
|
2086
|
+
|
2003
2087
|
Rails Preloaders and RSpec
|
2004
2088
|
--------------------------
|
2005
2089
|
|
data/NEWS.md
CHANGED
@@ -1,9 +1,99 @@
|
|
1
1
|
# News
|
2
2
|
|
3
|
+
## 6.5.1 (January 31, 2025)
|
4
|
+
|
5
|
+
* Changed: execute linting tests within ActiveRecord transactions when available (Sean Doyle)
|
6
|
+
* Fix: Random test failure when tracking compilation time (CodeMeinster)
|
7
|
+
* Fix: Bump the minimum required activesupport version to 6.1 (Earlopain)
|
8
|
+
* Internal: Update development dependencies (Neil Carvalho)
|
9
|
+
|
10
|
+
## 6.5.0 (September 6, 2024)
|
11
|
+
|
12
|
+
* fix: issue 1621 broken links in ref/factory.md by @elasticspoon in https://github.com/thoughtbot/factory_bot/pull/1623
|
13
|
+
* Add standard settings by @ydah in https://github.com/thoughtbot/factory_bot/pull/1625
|
14
|
+
* Call dynamic-readme reusable workflow by @stefannibrasil in https://github.com/thoughtbot/factory_bot/pull/1628
|
15
|
+
* Update README again by @stefannibrasil in https://github.com/thoughtbot/factory_bot/pull/1630
|
16
|
+
* Only run this workflow if the README has been updated by @stefannibrasil in https://github.com/thoughtbot/factory_bot/pull/1635
|
17
|
+
* Automatically Generated: Update Dynamic Section in README by @github-actions in https://github.com/thoughtbot/factory_bot/pull/1637
|
18
|
+
* Added a case for build_class to handle class names with underscores passed as a string by @m-gizzi in https://github.com/thoughtbot/factory_bot/pull/1642
|
19
|
+
* Add Ruby 3.3 to CI by @berkos in https://github.com/thoughtbot/factory_bot/pull/1615
|
20
|
+
* Update Dependabot configuration by @smaboshe in https://github.com/thoughtbot/factory_bot/pull/1655
|
21
|
+
* Add new maintainers to CODEOWNERS by @sarahraqueld in https://github.com/thoughtbot/factory_bot/pull/1651
|
22
|
+
* Improve docs formatting and fix filename conflicts by @sarahraqueld in https://github.com/thoughtbot/factory_bot/pull/1666
|
23
|
+
* Add a dynamic security workflow and a SECURITY.md file by @sarahraqueld in https://github.com/thoughtbot/factory_bot/pull/1677
|
24
|
+
* Automatically Generated: Update Dynamic Section in SECURITY by @github-actions in https://github.com/thoughtbot/factory_bot/pull/1678
|
25
|
+
* Ensure rails 7.2 compatibility by @Earlopain in https://github.com/thoughtbot/factory_bot/pull/1686
|
26
|
+
* Fix the factory definition in traits documentation by @ddieulivol in https://github.com/thoughtbot/factory_bot/pull/1688
|
27
|
+
|
28
|
+
## 6.4.6 (January 30, 2023)
|
29
|
+
|
30
|
+
* Fix: Bump minimum required Ruby in gemspec (Earlopain).
|
31
|
+
* Fix: Broken link in `FactoryBot.modify` docs (Matt Brictson).
|
32
|
+
* Fix: Broken link in `FactoryBot.lint` docs (Anton Dieterle).
|
33
|
+
|
34
|
+
## 6.4.5 (December 29, 2023)
|
35
|
+
|
36
|
+
* Changed: Support Ruby 3.0+, Rails 6.1+ (Mike Burns).
|
37
|
+
|
38
|
+
## 6.4.4 (December 27, 2023)
|
39
|
+
|
40
|
+
* Internal: Remove observer dependency (Earlopain).
|
41
|
+
|
42
|
+
## 6.4.3 (December 26, 2023)
|
43
|
+
|
44
|
+
* Fix: Support models without ID setters in build_stubbed (Olivier Bellone).
|
45
|
+
* Fix: Explicit observer dependency (Oleg Antonyan).
|
46
|
+
* Internal: Add Rails 7.1 to CI (Olivier Bellone).
|
47
|
+
* Internal: Bump github actions/checkout to v4 (Lorenzo Zabot)
|
48
|
+
* Internal: Stop passing disable-error_highlight in CI (Mike Burns).
|
49
|
+
* Internal: Relax the exception message check (Mike Burns).
|
50
|
+
|
51
|
+
## 6.4.2 (November 22, 2023)
|
52
|
+
|
53
|
+
* Fix: top-level traits pass their class to ActiveSupport::Notifications
|
54
|
+
(makicamel).
|
55
|
+
|
56
|
+
## 6.4.1 (November 20, 2023)
|
57
|
+
|
58
|
+
* Fix: factories with traits pass their class to ActiveSupport::Notifications
|
59
|
+
(makicamel).
|
60
|
+
|
61
|
+
## 6.4.0 (November 17, 2023)
|
62
|
+
|
63
|
+
* Added: if `build_stubbed` detects a UUID primary key, generate the correct
|
64
|
+
type (Peter Boling, Alexandre Ruban).
|
65
|
+
* Docs: show examples of Ruby 3 syntactic sugars (Sean Doyle).
|
66
|
+
* Internal: resolve test warning messages (Mike Burns).
|
67
|
+
|
68
|
+
|
69
|
+
## 6.3.0 (September 1, 2023)
|
70
|
+
|
71
|
+
* Fix: link to changelog for RubyGems (Berkan Ünal).
|
72
|
+
* Fix: integrate with Ruby 3.2's `did_you_mean` library (Daniel Colson).
|
73
|
+
* Changed: explicitly define `#destroyed?` within the `Stub` strategy to return `false` to be consistent
|
74
|
+
with ActiveRecord (Benjamin Fleischer).
|
75
|
+
* Added: announce `factory_bot.compile_factory` notification (Sean Doyle).
|
76
|
+
* Docs: clarify that custom strategies need to define `#to_sym` (Edmund Korley, Jonas S).
|
77
|
+
* Docs: fix CI link in README (Mark Huk).
|
78
|
+
* Docs: fix GitHub links (Robert Fletcher).
|
79
|
+
* Docs: install this library with `bundle add` (Glauco Custódio).
|
80
|
+
* Docs: re-write into mdBook (Mike Burns, Sara Jackson, Stefanni Brasil)
|
81
|
+
* Docs: clarify that automatic trait definitions could introduce new linting errors (Lawrence Chou).
|
82
|
+
* Internal: skip TruffleRuby on Rails 5.0, 5.1, 5.2 (Andrii Konchyn).
|
83
|
+
* Internal: fix typoes throughout codebase (Yudai Takada).
|
84
|
+
* Internal: run CI on `actions/checkout` v3 (Yudai Takada).
|
85
|
+
* Internal: follow standardrb code style (Yudai Takada).
|
86
|
+
* Internal: stop using Hound (Daniel Nolan).
|
87
|
+
* Internal: only run simplecov on C Ruby (Daniel Colson).
|
88
|
+
* Internal: quieter Cucumber (Daniel Colson).
|
89
|
+
* Internal: Ruby 3.2 support (Daniel Colson).
|
90
|
+
* Internal: Mike Burns is the CODEOWNER (Stefanni Brasil).
|
91
|
+
|
3
92
|
## 6.2.1 (March 8, 2022)
|
4
93
|
* Added: CI testing against truffleruby
|
5
94
|
* Changed: Documentation improvements for sequences and traits
|
6
95
|
* Fixed: ActiveSupport::Notifications reporting strategy through associations now report as symbols
|
96
|
+
* BREAKING CHANGE: Custom strategies now need to define a `to_sym` method to specify the strategy identifier
|
7
97
|
* Fixed: `add_attribute` with reserved keywords assigns values correctly
|
8
98
|
|
9
99
|
## 6.2.0 (May 7, 2021)
|
@@ -27,7 +117,9 @@
|
|
27
117
|
* Added: automatic definition of traits for Active Record enum attributes, enabled by default
|
28
118
|
(Note that this required changing where factory_bot constantizes the build
|
29
119
|
class, which may affect applications that were using abstract factories for
|
30
|
-
inheritance. See issue #1409.)
|
120
|
+
inheritance. See issue #1409.) (This may break `FactoryBot.lint` because
|
121
|
+
there may be previously non-existing factory+trait combinations being
|
122
|
+
defined and checked)
|
31
123
|
* Added: `traits_for_enum` method to define traits for non-Active Record enums
|
32
124
|
* Added: `build_stubbed_starting_id=` option to define the starting id for `build_stubbed`
|
33
125
|
* Removed: deprecated methods on the top-level `FactoryBot` module meant only for internal use
|
data/README.md
CHANGED
@@ -16,24 +16,26 @@ Check out the [guide](https://github.com/thoughtbot/factory_bot/blob/4-9-0-stabl
|
|
16
16
|
Documentation
|
17
17
|
-------------
|
18
18
|
|
19
|
-
|
19
|
+
See our extensive reference, guides, and cookbook in [the factory_bot book][].
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
For information on integrations with third party libraries, such as RSpec or
|
22
|
+
Rails, see [the factory_bot wiki][].
|
23
|
+
|
24
|
+
We also have [a detailed introductory video][], available for free on Upcase.
|
23
25
|
|
24
26
|
[a detailed introductory video]: https://upcase.com/videos/factory-bot?utm_source=github&utm_medium=open-source&utm_campaign=factory-girl
|
27
|
+
[the factory_bot book]: https://thoughtbot.github.io/factory_bot
|
28
|
+
[the factory_bot wiki]: https://github.com/thoughtbot/factory_bot/wiki
|
25
29
|
|
26
30
|
Install
|
27
31
|
--------
|
28
32
|
|
29
|
-
|
33
|
+
Run:
|
30
34
|
|
31
35
|
```ruby
|
32
|
-
|
36
|
+
bundle add factory_bot
|
33
37
|
```
|
34
38
|
|
35
|
-
and run `bundle install` from your shell.
|
36
|
-
|
37
39
|
To install the gem manually from your shell, run:
|
38
40
|
|
39
41
|
```shell
|
@@ -43,7 +45,7 @@ gem install factory_bot
|
|
43
45
|
Supported Ruby versions
|
44
46
|
-----------------------
|
45
47
|
|
46
|
-
Supported Ruby versions are listed in [`.github/workflows/build.yml`](https://github.com/thoughtbot/factory_bot/blob/
|
48
|
+
Supported Ruby versions are listed in [`.github/workflows/build.yml`](https://github.com/thoughtbot/factory_bot/blob/main/.github/workflows/build.yml)
|
47
49
|
|
48
50
|
More Information
|
49
51
|
----------------
|
@@ -53,8 +55,8 @@ More Information
|
|
53
55
|
* [Issues](https://github.com/thoughtbot/factory_bot/issues)
|
54
56
|
* [GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS](https://robots.thoughtbot.com/)
|
55
57
|
|
56
|
-
[GETTING_STARTED]: https://github.com/thoughtbot/factory_bot/blob/
|
57
|
-
[NAME]: https://github.com/thoughtbot/factory_bot/blob/
|
58
|
+
[GETTING_STARTED]: https://github.com/thoughtbot/factory_bot/blob/main/GETTING_STARTED.md
|
59
|
+
[NAME]: https://github.com/thoughtbot/factory_bot/blob/main/NAME.md
|
58
60
|
|
59
61
|
Useful Tools
|
60
62
|
------------
|
@@ -64,7 +66,7 @@ Useful Tools
|
|
64
66
|
Contributing
|
65
67
|
------------
|
66
68
|
|
67
|
-
Please see [CONTRIBUTING.md](https://github.com/thoughtbot/factory_bot/blob/
|
69
|
+
Please see [CONTRIBUTING.md](https://github.com/thoughtbot/factory_bot/blob/main/CONTRIBUTING.md).
|
68
70
|
|
69
71
|
factory_bot was originally written by Joe Ferris and is maintained by thoughtbot.
|
70
72
|
Many improvements and bugfixes were contributed by the [open source
|
@@ -73,29 +75,32 @@ community](https://github.com/thoughtbot/factory_bot/graphs/contributors).
|
|
73
75
|
License
|
74
76
|
-------
|
75
77
|
|
76
|
-
factory_bot is Copyright © 2008
|
78
|
+
factory_bot is Copyright © 2008 Joe Ferris and thoughtbot. It is free
|
77
79
|
software, and may be redistributed under the terms specified in the
|
78
80
|
[LICENSE] file.
|
79
81
|
|
80
|
-
[LICENSE]: https://github.com/thoughtbot/factory_bot/blob/
|
82
|
+
[LICENSE]: https://github.com/thoughtbot/factory_bot/blob/main/LICENSE
|
81
83
|
|
84
|
+
<!-- START /templates/footer.md -->
|
85
|
+
## About thoughtbot
|
82
86
|
|
83
|
-
|
84
|
-
----------------
|
85
|
-
|
86
|
-

|
87
|
+

|
87
88
|
|
88
|
-
|
89
|
+
This repo is maintained and funded by thoughtbot, inc.
|
89
90
|
The names and logos for thoughtbot are trademarks of thoughtbot, inc.
|
90
91
|
|
91
92
|
We love open source software!
|
92
|
-
See [our other projects][community]
|
93
|
-
[hire
|
93
|
+
See [our other projects][community].
|
94
|
+
We are [available for hire][hire].
|
94
95
|
|
95
96
|
[community]: https://thoughtbot.com/community?utm_source=github
|
96
97
|
[hire]: https://thoughtbot.com/hire-us?utm_source=github
|
97
|
-
|
98
|
-
|
98
|
+
|
99
|
+
|
100
|
+
<!-- END /templates/footer.md -->
|
101
|
+
|
102
|
+
[ci-image]: https://github.com/thoughtbot/factory_bot/actions/workflows/build.yml/badge.svg?branch=main
|
103
|
+
[ci]: https://github.com/thoughtbot/factory_bot/actions?query=workflow%3ABuild+branch%3Amain
|
99
104
|
[grade-image]: https://codeclimate.com/github/thoughtbot/factory_bot/badges/gpa.svg
|
100
105
|
[grade]: https://codeclimate.com/github/thoughtbot/factory_bot
|
101
106
|
[version-image]: https://badge.fury.io/rb/factory_bot.svg
|
@@ -12,8 +12,8 @@ module FactoryBot
|
|
12
12
|
|
13
13
|
-> {
|
14
14
|
value = case block.arity
|
15
|
-
|
16
|
-
|
15
|
+
when 1, -1, -2 then instance_exec(self, &block)
|
16
|
+
else instance_exec(&block)
|
17
17
|
end
|
18
18
|
raise SequenceAbuseError if FactoryBot::Sequence === value
|
19
19
|
|
@@ -13,7 +13,7 @@ module FactoryBot
|
|
13
13
|
@evaluator.instance = build_class_instance
|
14
14
|
build_class_instance.tap do |instance|
|
15
15
|
attributes_to_set_on_instance.each do |attribute|
|
16
|
-
instance.public_send("#{attribute}=", get(attribute))
|
16
|
+
instance.public_send(:"#{attribute}=", get(attribute))
|
17
17
|
@attribute_names_assigned << attribute
|
18
18
|
end
|
19
19
|
end
|
@@ -6,24 +6,12 @@ module FactoryBot
|
|
6
6
|
@component = component
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
@component.send(...)
|
13
|
-
end
|
14
|
-
|
15
|
-
def send(...)
|
16
|
-
__send__(...)
|
17
|
-
end
|
18
|
-
RUBY
|
19
|
-
else
|
20
|
-
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
|
21
|
-
@component.send(name, *args, &block)
|
22
|
-
end
|
9
|
+
def method_missing(...) # rubocop:disable Style/MethodMissingSuper
|
10
|
+
@component.send(...)
|
11
|
+
end
|
23
12
|
|
24
|
-
|
25
|
-
|
26
|
-
end
|
13
|
+
def send(...)
|
14
|
+
__send__(...)
|
27
15
|
end
|
28
16
|
|
29
17
|
def respond_to_missing?(name, include_private = false)
|
@@ -2,6 +2,7 @@ module FactoryBot
|
|
2
2
|
# @api private
|
3
3
|
class Definition
|
4
4
|
attr_reader :defined_traits, :declarations, :name, :registered_enums
|
5
|
+
attr_accessor :klass
|
5
6
|
|
6
7
|
def initialize(name, base_traits = [])
|
7
8
|
@name = name
|
@@ -51,12 +52,21 @@ module FactoryBot
|
|
51
52
|
|
52
53
|
declarations.attributes
|
53
54
|
|
55
|
+
self.klass ||= klass
|
54
56
|
defined_traits.each do |defined_trait|
|
57
|
+
defined_trait.klass ||= klass
|
55
58
|
base_traits.each { |bt| bt.define_trait defined_trait }
|
56
59
|
additional_traits.each { |at| at.define_trait defined_trait }
|
57
60
|
end
|
58
61
|
|
59
62
|
@compiled = true
|
63
|
+
|
64
|
+
ActiveSupport::Notifications.instrument "factory_bot.compile_factory", {
|
65
|
+
name: name,
|
66
|
+
attributes: declarations.attributes,
|
67
|
+
traits: defined_traits,
|
68
|
+
class: klass || self.klass
|
69
|
+
}
|
60
70
|
end
|
61
71
|
end
|
62
72
|
|
@@ -85,6 +95,10 @@ module FactoryBot
|
|
85
95
|
@defined_traits.add(trait)
|
86
96
|
end
|
87
97
|
|
98
|
+
def defined_traits_names
|
99
|
+
@defined_traits.map(&:name)
|
100
|
+
end
|
101
|
+
|
88
102
|
def register_enum(enum)
|
89
103
|
@registered_enums << enum
|
90
104
|
end
|
@@ -115,15 +129,26 @@ module FactoryBot
|
|
115
129
|
raise error_with_definition_name(error)
|
116
130
|
end
|
117
131
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
" referenced within \"#{name}\" definition"
|
123
|
-
)
|
132
|
+
# detailed_message introduced in Ruby 3.2 for cleaner integration with
|
133
|
+
# did_you_mean. See https://bugs.ruby-lang.org/issues/18564
|
134
|
+
if KeyError.method_defined?(:detailed_message)
|
135
|
+
def error_with_definition_name(error)
|
136
|
+
message = error.message + " referenced within \"#{name}\" definition"
|
124
137
|
|
125
|
-
|
126
|
-
|
138
|
+
error.class.new(message, key: error.key, receiver: error.receiver)
|
139
|
+
.tap { |new_error| new_error.set_backtrace(error.backtrace) }
|
140
|
+
end
|
141
|
+
else
|
142
|
+
def error_with_definition_name(error)
|
143
|
+
message = error.message
|
144
|
+
message.insert(
|
145
|
+
message.index("\nDid you mean?") || message.length,
|
146
|
+
" referenced within \"#{name}\" definition"
|
147
|
+
)
|
148
|
+
|
149
|
+
error.class.new(message).tap do |new_error|
|
150
|
+
new_error.set_backtrace(error.backtrace)
|
151
|
+
end
|
127
152
|
end
|
128
153
|
end
|
129
154
|
|
@@ -132,7 +157,7 @@ module FactoryBot
|
|
132
157
|
end
|
133
158
|
|
134
159
|
def trait_by_name(name)
|
135
|
-
trait_for(name) || Internal.trait_by_name(name)
|
160
|
+
trait_for(name) || Internal.trait_by_name(name, klass)
|
136
161
|
end
|
137
162
|
|
138
163
|
def trait_for(name)
|
@@ -119,8 +119,8 @@ module FactoryBot
|
|
119
119
|
# end
|
120
120
|
#
|
121
121
|
# Except that no globally available sequence will be defined.
|
122
|
-
def sequence(name,
|
123
|
-
sequence = Sequence.new(name,
|
122
|
+
def sequence(name, ...)
|
123
|
+
sequence = Sequence.new(name, ...)
|
124
124
|
FactoryBot::Internal.register_inline_sequence(sequence)
|
125
125
|
add_attribute(name) { increment_sequence(sequence) }
|
126
126
|
end
|
@@ -151,7 +151,7 @@ module FactoryBot
|
|
151
151
|
def association(name, *options)
|
152
152
|
if block_given?
|
153
153
|
raise AssociationDefinitionError.new(
|
154
|
-
"Unexpected block passed to '#{name}' association "\
|
154
|
+
"Unexpected block passed to '#{name}' association " \
|
155
155
|
"in '#{@definition.name}' factory"
|
156
156
|
)
|
157
157
|
else
|
@@ -1,13 +1,10 @@
|
|
1
|
-
require "observer"
|
2
|
-
|
3
1
|
module FactoryBot
|
4
2
|
class Evaluation
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(evaluator, attribute_assigner, to_create)
|
3
|
+
def initialize(evaluator, attribute_assigner, to_create, observer)
|
8
4
|
@evaluator = evaluator
|
9
5
|
@attribute_assigner = attribute_assigner
|
10
6
|
@to_create = to_create
|
7
|
+
@observer = observer
|
11
8
|
end
|
12
9
|
|
13
10
|
delegate :object, :hash, to: :@attribute_assigner
|
@@ -20,8 +17,7 @@ module FactoryBot
|
|
20
17
|
end
|
21
18
|
|
22
19
|
def notify(name, result_instance)
|
23
|
-
|
24
|
-
notify_observers(name, result_instance)
|
20
|
+
@observer.update(name, result_instance)
|
25
21
|
end
|
26
22
|
end
|
27
23
|
end
|
@@ -35,14 +35,13 @@ module FactoryBot
|
|
35
35
|
|
36
36
|
attr_accessor :instance
|
37
37
|
|
38
|
-
def method_missing(method_name,
|
38
|
+
def method_missing(method_name, ...)
|
39
39
|
if @instance.respond_to?(method_name)
|
40
|
-
@instance.send(method_name,
|
40
|
+
@instance.send(method_name, ...)
|
41
41
|
else
|
42
|
-
SyntaxRunner.new.send(method_name,
|
42
|
+
SyntaxRunner.new.send(method_name, ...)
|
43
43
|
end
|
44
44
|
end
|
45
|
-
ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
|
46
45
|
|
47
46
|
def respond_to_missing?(method_name, _include_private = false)
|
48
47
|
@instance.respond_to?(method_name) || SyntaxRunner.new.respond_to?(method_name)
|
data/lib/factory_bot/factory.rb
CHANGED
@@ -17,11 +17,14 @@ module FactoryBot
|
|
17
17
|
end
|
18
18
|
|
19
19
|
delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
|
20
|
-
:defined_traits, :inherit_traits, :append_traits,
|
20
|
+
:defined_traits, :defined_traits_names, :inherit_traits, :append_traits,
|
21
|
+
to: :@definition
|
21
22
|
|
22
23
|
def build_class
|
23
24
|
@build_class ||= if class_name.is_a? Class
|
24
25
|
class_name
|
26
|
+
elsif class_name.to_s.safe_constantize
|
27
|
+
class_name.to_s.safe_constantize
|
25
28
|
else
|
26
29
|
class_name.to_s.camelize.constantize
|
27
30
|
end
|
@@ -36,9 +39,9 @@ module FactoryBot
|
|
36
39
|
evaluator = evaluator_class.new(strategy, overrides.symbolize_keys)
|
37
40
|
attribute_assigner = AttributeAssigner.new(evaluator, build_class, &compiled_constructor)
|
38
41
|
|
42
|
+
observer = CallbacksObserver.new(callbacks, evaluator)
|
39
43
|
evaluation =
|
40
|
-
Evaluation.new(evaluator, attribute_assigner, compiled_to_create)
|
41
|
-
evaluation.add_observer(CallbacksObserver.new(callbacks, evaluator))
|
44
|
+
Evaluation.new(evaluator, attribute_assigner, compiled_to_create, observer)
|
42
45
|
|
43
46
|
strategy.result(evaluation).tap(&block)
|
44
47
|
end
|
@@ -83,7 +86,7 @@ module FactoryBot
|
|
83
86
|
def compile
|
84
87
|
unless @compiled
|
85
88
|
parent.compile
|
86
|
-
|
89
|
+
inherit_parent_traits
|
87
90
|
@definition.compile(build_class)
|
88
91
|
build_hierarchy
|
89
92
|
@compiled = true
|
@@ -151,6 +154,13 @@ module FactoryBot
|
|
151
154
|
end
|
152
155
|
end
|
153
156
|
|
157
|
+
def inherit_parent_traits
|
158
|
+
parent.defined_traits.each do |trait|
|
159
|
+
next if defined_traits_names.include?(trait.name)
|
160
|
+
define_trait(trait.clone)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
154
164
|
def initialize_copy(source)
|
155
165
|
super
|
156
166
|
@definition = @definition.clone
|
data/lib/factory_bot/internal.rb
CHANGED
data/lib/factory_bot/linter.rb
CHANGED
@@ -70,7 +70,7 @@ module FactoryBot
|
|
70
70
|
def lint_factory(factory)
|
71
71
|
result = []
|
72
72
|
begin
|
73
|
-
FactoryBot.public_send(factory_strategy, factory.name)
|
73
|
+
in_transaction { FactoryBot.public_send(factory_strategy, factory.name) }
|
74
74
|
rescue => e
|
75
75
|
result |= [FactoryError.new(e, factory)]
|
76
76
|
end
|
@@ -80,7 +80,7 @@ module FactoryBot
|
|
80
80
|
def lint_traits(factory)
|
81
81
|
result = []
|
82
82
|
factory.definition.defined_traits.map(&:name).each do |trait_name|
|
83
|
-
FactoryBot.public_send(factory_strategy, factory.name, trait_name)
|
83
|
+
in_transaction { FactoryBot.public_send(factory_strategy, factory.name, trait_name) }
|
84
84
|
rescue => e
|
85
85
|
result |= [FactoryTraitError.new(e, factory, trait_name)]
|
86
86
|
end
|
@@ -106,5 +106,16 @@ module FactoryBot
|
|
106
106
|
:message
|
107
107
|
end
|
108
108
|
end
|
109
|
+
|
110
|
+
def in_transaction
|
111
|
+
if defined?(ActiveRecord::Base)
|
112
|
+
ActiveRecord::Base.transaction do
|
113
|
+
yield
|
114
|
+
raise ActiveRecord::Rollback
|
115
|
+
end
|
116
|
+
else
|
117
|
+
yield
|
118
|
+
end
|
119
|
+
end
|
109
120
|
end
|
110
121
|
end
|
data/lib/factory_bot/registry.rb
CHANGED
@@ -39,9 +39,21 @@ module FactoryBot
|
|
39
39
|
|
40
40
|
def key_error_with_custom_message(key_error)
|
41
41
|
message = key_error.message.sub("key not found", "#{@name} not registered")
|
42
|
-
|
43
|
-
|
44
|
-
|
42
|
+
new_key_error(message, key_error).tap do |error|
|
43
|
+
error.set_backtrace(key_error.backtrace)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# detailed_message introduced in Ruby 3.2 for cleaner integration with
|
48
|
+
# did_you_mean. See https://bugs.ruby-lang.org/issues/18564
|
49
|
+
if KeyError.method_defined?(:detailed_message)
|
50
|
+
def new_key_error(message, key_error)
|
51
|
+
KeyError.new(message, key: key_error.key, receiver: key_error.receiver)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
def new_key_error(message, _)
|
55
|
+
KeyError.new(message)
|
56
|
+
end
|
45
57
|
end
|
46
58
|
end
|
47
59
|
end
|
@@ -47,13 +47,17 @@ module FactoryBot
|
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
|
-
def next_id
|
51
|
-
|
50
|
+
def next_id(result_instance)
|
51
|
+
if uuid_primary_key?(result_instance)
|
52
|
+
SecureRandom.uuid
|
53
|
+
else
|
54
|
+
@@next_id += 1
|
55
|
+
end
|
52
56
|
end
|
53
57
|
|
54
58
|
def stub_database_interaction_on_result(result_instance)
|
55
59
|
if has_settable_id?(result_instance)
|
56
|
-
result_instance.id ||= next_id
|
60
|
+
result_instance.id ||= next_id(result_instance)
|
57
61
|
end
|
58
62
|
|
59
63
|
result_instance.instance_eval do
|
@@ -66,12 +70,12 @@ module FactoryBot
|
|
66
70
|
end
|
67
71
|
|
68
72
|
def destroyed?
|
69
|
-
|
73
|
+
false
|
70
74
|
end
|
71
75
|
|
72
76
|
DISABLED_PERSISTENCE_METHODS.each do |write_method|
|
73
77
|
define_singleton_method(write_method) do |*args|
|
74
|
-
raise "stubbed models are not allowed to access the database - "\
|
78
|
+
raise "stubbed models are not allowed to access the database - " \
|
75
79
|
"#{self.class}##{write_method}(#{args.join(",")})"
|
76
80
|
end
|
77
81
|
end
|
@@ -79,8 +83,16 @@ module FactoryBot
|
|
79
83
|
end
|
80
84
|
|
81
85
|
def has_settable_id?(result_instance)
|
82
|
-
|
83
|
-
result_instance.class.primary_key
|
86
|
+
result_instance.respond_to?(:id=) &&
|
87
|
+
(!result_instance.class.respond_to?(:primary_key) ||
|
88
|
+
result_instance.class.primary_key)
|
89
|
+
end
|
90
|
+
|
91
|
+
def uuid_primary_key?(result_instance)
|
92
|
+
result_instance.respond_to?(:column_for_attribute) &&
|
93
|
+
(column = result_instance.column_for_attribute(result_instance.class.primary_key)) &&
|
94
|
+
column.respond_to?(:sql_type) &&
|
95
|
+
column.sql_type == "uuid"
|
84
96
|
end
|
85
97
|
|
86
98
|
def clear_changes_information(result_instance)
|
data/lib/factory_bot/trait.rb
CHANGED
@@ -14,8 +14,12 @@ module FactoryBot
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
+
def clone
|
18
|
+
Trait.new(name, &block)
|
19
|
+
end
|
20
|
+
|
17
21
|
delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
|
18
|
-
:callbacks, :attributes, to: :@definition
|
22
|
+
:callbacks, :attributes, :klass, :klass=, to: :@definition
|
19
23
|
|
20
24
|
def names
|
21
25
|
[@name]
|
data/lib/factory_bot/version.rb
CHANGED
data/lib/factory_bot.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: 6.
|
4
|
+
version: 6.5.1
|
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: 2025-01-31 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version:
|
20
|
+
version: 6.1.0
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version:
|
27
|
+
version: 6.1.0
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: activerecord
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,6 +81,20 @@ dependencies:
|
|
81
81
|
- - ">="
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: mutex_m
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
84
98
|
- !ruby/object:Gem::Dependency
|
85
99
|
name: rake
|
86
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -236,7 +250,8 @@ files:
|
|
236
250
|
homepage: https://github.com/thoughtbot/factory_bot
|
237
251
|
licenses:
|
238
252
|
- MIT
|
239
|
-
metadata:
|
253
|
+
metadata:
|
254
|
+
changelog_uri: https://github.com/thoughtbot/factory_bot/blob/main/NEWS.md
|
240
255
|
post_install_message:
|
241
256
|
rdoc_options: []
|
242
257
|
require_paths:
|
@@ -245,14 +260,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
245
260
|
requirements:
|
246
261
|
- - ">="
|
247
262
|
- !ruby/object:Gem::Version
|
248
|
-
version:
|
263
|
+
version: 3.0.0
|
249
264
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
250
265
|
requirements:
|
251
266
|
- - ">="
|
252
267
|
- !ruby/object:Gem::Version
|
253
268
|
version: '0'
|
254
269
|
requirements: []
|
255
|
-
rubygems_version: 3.
|
270
|
+
rubygems_version: 3.5.22
|
256
271
|
signing_key:
|
257
272
|
specification_version: 4
|
258
273
|
summary: factory_bot provides a framework and DSL for defining and using model instance
|