factory_bot 6.1.0 → 6.2.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 +6 -0
- data/GETTING_STARTED.md +294 -73
- data/NEWS.md +13 -0
- data/README.md +3 -3
- data/lib/factory_bot/aliases.rb +1 -1
- data/lib/factory_bot/attribute/dynamic.rb +1 -1
- data/lib/factory_bot/attribute_assigner.rb +3 -2
- data/lib/factory_bot/callback.rb +1 -1
- data/lib/factory_bot/decorator/invocation_tracker.rb +4 -10
- data/lib/factory_bot/decorator.rb +1 -1
- data/lib/factory_bot/definition.rb +15 -1
- data/lib/factory_bot/definition_proxy.rb +1 -1
- data/lib/factory_bot/evaluator.rb +7 -16
- data/lib/factory_bot/registry.rb +1 -1
- data/lib/factory_bot/strategy/attributes_for.rb +4 -0
- data/lib/factory_bot/strategy/build.rb +4 -0
- data/lib/factory_bot/strategy/create.rb +4 -0
- data/lib/factory_bot/strategy/null.rb +4 -0
- data/lib/factory_bot/strategy/stub.rb +4 -0
- data/lib/factory_bot/syntax/default.rb +1 -1
- data/lib/factory_bot/trait.rb +1 -1
- data/lib/factory_bot/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3bcbbd8bee01abdb25a5cfdbbbbca29396f587236f0c20f8300adbf6e32f783c
|
4
|
+
data.tar.gz: 94d8e73507ae61edba7fb3129ee74c4fe9998a8fb78614ecba9966199561c8e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e97d9530810f0de00f6e0129df37db52722ee8d430f7b118ffdcebdc0eecc1e1532356b7c8e01cc85265c04f18eb174d3d5ff09fe235c5f30ceb7b5e16432508
|
7
|
+
data.tar.gz: 71b77c30b16c89588d6946505be547374321597e8e16f89673766cda94b22188dc28070a34144ae126dad93042de0173e1d92173237ae1e929a3131e85569a51
|
data/CONTRIBUTING.md
CHANGED
@@ -51,6 +51,12 @@ Here are some ways *you* can contribute:
|
|
51
51
|
asking for help. We love helping!
|
52
52
|
* Please don't update the Gem version.
|
53
53
|
|
54
|
+
## Setting up
|
55
|
+
|
56
|
+
```sh
|
57
|
+
bundle install
|
58
|
+
```
|
59
|
+
|
54
60
|
## Running the test suite
|
55
61
|
|
56
62
|
The default rake task will run the full test suite and [standard]:
|
data/GETTING_STARTED.md
CHANGED
@@ -37,12 +37,15 @@ Getting Started
|
|
37
37
|
* [Associations](#associations)
|
38
38
|
+ [Implicit definition](#implicit-definition)
|
39
39
|
+ [Explicit definition](#explicit-definition)
|
40
|
+
+ [Inline definition](#inline-definition)
|
40
41
|
+ [Specifying the factory](#specifying-the-factory)
|
41
42
|
+ [Overriding attributes](#overriding-attributes)
|
43
|
+
+ [Association overrides](#association-overrides)
|
42
44
|
+ [Build strategies](#build-strategies-1)
|
43
45
|
+ [`has_many` associations](#has_many-associations)
|
44
46
|
+ [`has_and_belongs_to_many` associations](#has_and_belongs_to_many-associations)
|
45
47
|
+ [Polymorphic associations](#polymorphic-associations)
|
48
|
+
+ [Interconnected associations](#interconnected-associations)
|
46
49
|
* [Sequences](#sequences)
|
47
50
|
+ [Global sequences](#global-sequences)
|
48
51
|
+ [With dynamic attributes](#with-dynamic-attributes)
|
@@ -197,17 +200,15 @@ It is also possible to explicitly specify the class:
|
|
197
200
|
|
198
201
|
```ruby
|
199
202
|
# This will use the User class (otherwise Admin would have been guessed)
|
200
|
-
factory :admin, class: User
|
203
|
+
factory :admin, class: "User"
|
201
204
|
```
|
202
205
|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
which factory\_bot will constantize later, once you start building objects:
|
206
|
+
You can pass a constant as well, if the constant is available (note that this
|
207
|
+
can cause test performance problems in large Rails applications, since
|
208
|
+
referring to the constant will cause it to be eagerly loaded).
|
207
209
|
|
208
210
|
```ruby
|
209
|
-
|
210
|
-
factory :access_token, class: "Doorkeeper::AccessToken"
|
211
|
+
factory :access_token, class: User
|
211
212
|
```
|
212
213
|
|
213
214
|
### Hash attributes
|
@@ -312,17 +313,17 @@ factory :user, aliases: [:author, :commenter] do
|
|
312
313
|
end
|
313
314
|
|
314
315
|
factory :post do
|
315
|
-
author
|
316
|
-
# instead of
|
316
|
+
# The alias allows us to write author instead of
|
317
317
|
# association :author, factory: :user
|
318
|
+
author
|
318
319
|
title { "How to read a book effectively" }
|
319
320
|
body { "There are five steps involved." }
|
320
321
|
end
|
321
322
|
|
322
323
|
factory :comment do
|
323
|
-
commenter
|
324
|
-
# instead of
|
324
|
+
# The alias allows us to write commenter instead of
|
325
325
|
# association :commenter, factory: :user
|
326
|
+
commenter
|
326
327
|
body { "Great article!" }
|
327
328
|
end
|
328
329
|
```
|
@@ -346,6 +347,7 @@ create(:user, last_name: "Doe").email
|
|
346
347
|
|
347
348
|
Transient Attributes
|
348
349
|
--------------------
|
350
|
+
Transient attributes are attributes only available within the factory definition, and not set on the object being built. This allows for more complex logic inside factories.
|
349
351
|
|
350
352
|
### With other attributes
|
351
353
|
|
@@ -505,6 +507,19 @@ factory :post do
|
|
505
507
|
end
|
506
508
|
```
|
507
509
|
|
510
|
+
### Inline definition
|
511
|
+
|
512
|
+
You can also define associations inline within regular attributes,
|
513
|
+
but note that the value will be `nil`
|
514
|
+
when using the `attributes_for` strategy.
|
515
|
+
|
516
|
+
```ruby
|
517
|
+
factory :post do
|
518
|
+
# ...
|
519
|
+
author { association :author }
|
520
|
+
end
|
521
|
+
```
|
522
|
+
|
508
523
|
### Specifying the factory
|
509
524
|
|
510
525
|
You can specify a different factory (although [Aliases](#aliases) might also
|
@@ -528,6 +543,15 @@ factory :post do
|
|
528
543
|
end
|
529
544
|
```
|
530
545
|
|
546
|
+
Inline:
|
547
|
+
|
548
|
+
```ruby
|
549
|
+
factory :post do
|
550
|
+
# ...
|
551
|
+
author { association :user }
|
552
|
+
end
|
553
|
+
```
|
554
|
+
|
531
555
|
### Overriding attributes
|
532
556
|
|
533
557
|
You can also override attributes.
|
@@ -551,6 +575,35 @@ factory :post do
|
|
551
575
|
end
|
552
576
|
```
|
553
577
|
|
578
|
+
Or inline using attributes from the factory:
|
579
|
+
|
580
|
+
```rb
|
581
|
+
factory :post do
|
582
|
+
# ...
|
583
|
+
author_last_name { "Writely" }
|
584
|
+
author { association :author, last_name: author_last_name }
|
585
|
+
end
|
586
|
+
```
|
587
|
+
|
588
|
+
### Association overrides
|
589
|
+
|
590
|
+
Attribute overrides can be used to link associated objects:
|
591
|
+
|
592
|
+
```ruby
|
593
|
+
FactoryBot.define do
|
594
|
+
factory :author do
|
595
|
+
name { 'Taylor' }
|
596
|
+
end
|
597
|
+
|
598
|
+
factory :post do
|
599
|
+
author
|
600
|
+
end
|
601
|
+
end
|
602
|
+
|
603
|
+
eunji = build(:author, name: 'Eunji')
|
604
|
+
post = build(:post, author: eunji)
|
605
|
+
```
|
606
|
+
|
554
607
|
### Build strategies
|
555
608
|
|
556
609
|
In factory\_bot 5, associations default to using the same build strategy as
|
@@ -620,27 +673,51 @@ factory :post do
|
|
620
673
|
|
621
674
|
### `has_many` associations
|
622
675
|
|
623
|
-
|
624
|
-
|
625
|
-
|
676
|
+
There are a few ways to generate data for a `has_many` relationship. The
|
677
|
+
simplest approach is to write a helper method in plain Ruby to tie together the
|
678
|
+
different records:
|
626
679
|
|
627
680
|
```ruby
|
628
681
|
FactoryBot.define do
|
682
|
+
factory :post do
|
683
|
+
title { "Through the Looking Glass" }
|
684
|
+
user
|
685
|
+
end
|
686
|
+
|
687
|
+
factory :user do
|
688
|
+
name { "Rachel Sanchez" }
|
689
|
+
end
|
690
|
+
end
|
691
|
+
|
692
|
+
def user_with_posts(posts_count: 5)
|
693
|
+
FactoryBot.create(:user) do |user|
|
694
|
+
FactoryBot.create_list(:post, posts_count, user: user)
|
695
|
+
end
|
696
|
+
end
|
697
|
+
|
698
|
+
create(:user).posts.length # 0
|
699
|
+
user_with_posts.posts.length # 5
|
700
|
+
user_with_posts(posts_count: 15).posts.length # 15
|
701
|
+
```
|
629
702
|
|
630
|
-
|
703
|
+
If you prefer to keep the object creation fully within factory\_bot, you can
|
704
|
+
build the posts in an `after(:create)` callback.
|
705
|
+
|
706
|
+
|
707
|
+
```ruby
|
708
|
+
FactoryBot.define do
|
631
709
|
factory :post do
|
632
710
|
title { "Through the Looking Glass" }
|
633
711
|
user
|
634
712
|
end
|
635
713
|
|
636
|
-
# user factory without associated posts
|
637
714
|
factory :user do
|
638
715
|
name { "John Doe" }
|
639
716
|
|
640
717
|
# user_with_posts will create post data after the user has been created
|
641
718
|
factory :user_with_posts do
|
642
|
-
# posts_count is declared as a transient attribute
|
643
|
-
#
|
719
|
+
# posts_count is declared as a transient attribute available in the
|
720
|
+
# callback via the evaluator
|
644
721
|
transient do
|
645
722
|
posts_count { 5 }
|
646
723
|
end
|
@@ -651,71 +728,122 @@ FactoryBot.define do
|
|
651
728
|
# to create and we make sure the user is associated properly to the post
|
652
729
|
after(:create) do |user, evaluator|
|
653
730
|
create_list(:post, evaluator.posts_count, user: user)
|
731
|
+
|
732
|
+
# You may need to reload the record here, depending on your application
|
733
|
+
user.reload
|
654
734
|
end
|
655
735
|
end
|
656
736
|
end
|
657
737
|
end
|
738
|
+
|
739
|
+
create(:user).posts.length # 0
|
740
|
+
create(:user_with_posts).posts.length # 5
|
741
|
+
create(:user_with_posts, posts_count: 15).posts.length # 15
|
658
742
|
```
|
659
743
|
|
660
|
-
|
744
|
+
Or, for a solution that works with `build`, `build_stubbed`, and `create`
|
745
|
+
(although it doesn't work well with `attributes_for`), you can use inline
|
746
|
+
associations:
|
661
747
|
|
662
748
|
```ruby
|
749
|
+
FactoryBot.define do
|
750
|
+
factory :post do
|
751
|
+
title { "Through the Looking Glass" }
|
752
|
+
user
|
753
|
+
end
|
754
|
+
|
755
|
+
factory :user do
|
756
|
+
name { "Taylor Kim" }
|
757
|
+
|
758
|
+
factory :user_with_posts do
|
759
|
+
posts { [association(:post)] }
|
760
|
+
end
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
663
764
|
create(:user).posts.length # 0
|
765
|
+
create(:user_with_posts).posts.length # 1
|
766
|
+
build(:user_with_posts).posts.length # 1
|
767
|
+
build_stubbed(:user_with_posts).posts.length # 1
|
768
|
+
```
|
769
|
+
|
770
|
+
For more flexibility you can combine this with the `posts_count` transient
|
771
|
+
attribute from the callback example:
|
772
|
+
|
773
|
+
```ruby
|
774
|
+
FactoryBot.define do
|
775
|
+
factory :post do
|
776
|
+
title { "Through the Looking Glass" }
|
777
|
+
user
|
778
|
+
end
|
779
|
+
|
780
|
+
factory :user do
|
781
|
+
name { "Adiza Kumato" }
|
782
|
+
|
783
|
+
factory :user_with_posts do
|
784
|
+
transient do
|
785
|
+
posts_count { 5 }
|
786
|
+
end
|
787
|
+
|
788
|
+
posts do
|
789
|
+
Array.new(posts_count) { association(:post) }
|
790
|
+
end
|
791
|
+
end
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
664
795
|
create(:user_with_posts).posts.length # 5
|
665
796
|
create(:user_with_posts, posts_count: 15).posts.length # 15
|
797
|
+
build(:user_with_posts, posts_count: 15).posts.length # 15
|
798
|
+
build_stubbed(:user_with_posts, posts_count: 15).posts.length # 15
|
666
799
|
```
|
667
800
|
|
668
801
|
### `has_and_belongs_to_many` associations
|
669
802
|
|
670
803
|
Generating data for a `has_and_belongs_to_many` relationship is very similar
|
671
|
-
to the above `has_many` relationship, with a small change
|
804
|
+
to the above `has_many` relationship, with a small change: you need to pass an
|
672
805
|
array of objects to the model's pluralized attribute name rather than a single
|
673
806
|
object to the singular version of the attribute name.
|
674
807
|
|
675
|
-
Here's an example with two models that are related via
|
676
|
-
`has_and_belongs_to_many`:
|
677
808
|
|
678
809
|
```ruby
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
factory :language do
|
683
|
-
title { "Through the Looking Glass" }
|
684
|
-
profile
|
810
|
+
def profile_with_languages(languages_count: 2)
|
811
|
+
FactoryBot.create(:profile) do |profile|
|
812
|
+
FactoryBot.create_list(:language, languages_count, profiles: [profile])
|
685
813
|
end
|
814
|
+
end
|
815
|
+
```
|
686
816
|
|
687
|
-
|
688
|
-
factory :profile do
|
689
|
-
name { "John Doe" }
|
817
|
+
Or with the callback approach:
|
690
818
|
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
transient do
|
697
|
-
languages_count { 5 }
|
698
|
-
end
|
819
|
+
```ruby
|
820
|
+
factory :profile_with_languages do
|
821
|
+
transient do
|
822
|
+
languages_count { 2 }
|
823
|
+
end
|
699
824
|
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
# records to create and we make sure the profile is associated properly
|
704
|
-
# to the language
|
705
|
-
after(:create) do |profile, evaluator|
|
706
|
-
create_list(:language, evaluator.languages_count, profiles: [profile])
|
707
|
-
end
|
708
|
-
end
|
825
|
+
after(:create) do |profile, evaluator|
|
826
|
+
create_list(:language, evaluator.languages_count, profiles: [profile])
|
827
|
+
profile.reload
|
709
828
|
end
|
710
829
|
end
|
711
830
|
```
|
712
831
|
|
713
|
-
|
832
|
+
Or the inline association approach (note the use of the `instance` method here
|
833
|
+
to refer to the profile being built):
|
714
834
|
|
715
835
|
```ruby
|
716
|
-
|
717
|
-
|
718
|
-
|
836
|
+
factory :profile_with_languages do
|
837
|
+
transient do
|
838
|
+
languages_count { 2 }
|
839
|
+
end
|
840
|
+
|
841
|
+
languages do
|
842
|
+
Array.new(languages_count) do
|
843
|
+
association(:language, profiles: [instance])
|
844
|
+
end
|
845
|
+
end
|
846
|
+
end
|
719
847
|
```
|
720
848
|
|
721
849
|
### Polymorphic associations
|
@@ -749,6 +877,61 @@ create(:comment, :for_video)
|
|
749
877
|
create(:comment, :for_photo)
|
750
878
|
```
|
751
879
|
|
880
|
+
### Interconnected associations
|
881
|
+
|
882
|
+
There are limitless ways objects might be interconnected, and
|
883
|
+
factory\_bot may not always be suited to handle those relationships. In some
|
884
|
+
cases it makes sense to use factory\_bot to build each individual object, and
|
885
|
+
then to write helper methods in plain Ruby to tie those objects together.
|
886
|
+
|
887
|
+
That said, some more complex, interconnected relationships can be built in factory\_bot
|
888
|
+
using inline associations with reference to the `instance` being built.
|
889
|
+
|
890
|
+
Let's say your models look like this, where an associated `Student` and
|
891
|
+
`Profile` should both belong to the same `School`:
|
892
|
+
|
893
|
+
```ruby
|
894
|
+
class Student < ApplicationRecord
|
895
|
+
belongs_to :school
|
896
|
+
has_one :profile
|
897
|
+
end
|
898
|
+
|
899
|
+
class Profile < ApplicationRecord
|
900
|
+
belongs_to :school
|
901
|
+
belongs_to :student
|
902
|
+
end
|
903
|
+
|
904
|
+
class School < ApplicationRecord
|
905
|
+
has_many :students
|
906
|
+
has_many :profiles
|
907
|
+
end
|
908
|
+
```
|
909
|
+
|
910
|
+
We can ensure the student and profile are connected to each other and to the
|
911
|
+
same school with a factory like this:
|
912
|
+
|
913
|
+
```ruby
|
914
|
+
FactoryBot.define do
|
915
|
+
factory :student do
|
916
|
+
school
|
917
|
+
profile { association :profile, student: instance, school: school }
|
918
|
+
end
|
919
|
+
|
920
|
+
factory :profile do
|
921
|
+
school
|
922
|
+
student { association :student, profile: instance, school: school }
|
923
|
+
end
|
924
|
+
|
925
|
+
factory :school
|
926
|
+
end
|
927
|
+
```
|
928
|
+
|
929
|
+
Note that this approach works with `build`, `build_stubbed`, and `create`, but
|
930
|
+
the associations will return `nil` when using `attributes_for`.
|
931
|
+
|
932
|
+
Also, note that if you assign any attributes inside a custom `initialize_with`
|
933
|
+
(e.g. `initialize_with { new(**attributes) }`), those attributes should not refer to `instance`,
|
934
|
+
since it will be `nil`.
|
752
935
|
|
753
936
|
Sequences
|
754
937
|
---------
|
@@ -811,7 +994,7 @@ end
|
|
811
994
|
|
812
995
|
### Initial value
|
813
996
|
|
814
|
-
You can override the initial value. Any value that
|
997
|
+
You can override the initial value. Any value that responds to the `#next`
|
815
998
|
method will work (e.g. 1, 2, 3, 'a', 'b', 'c')
|
816
999
|
|
817
1000
|
```ruby
|
@@ -830,6 +1013,15 @@ factory :post do
|
|
830
1013
|
end
|
831
1014
|
```
|
832
1015
|
|
1016
|
+
Please note, that the value for the sequence could be any Enumerable instance,
|
1017
|
+
as long as it responds to `#next`:
|
1018
|
+
|
1019
|
+
```ruby
|
1020
|
+
factory :task do
|
1021
|
+
sequence :priority, %i[low medium high urgent].cycle
|
1022
|
+
end
|
1023
|
+
```
|
1024
|
+
|
833
1025
|
### Aliases
|
834
1026
|
|
835
1027
|
Sequences can also have aliases. The sequence aliases share the same counter:
|
@@ -960,16 +1152,16 @@ factory :user do
|
|
960
1152
|
name { "Friendly User" }
|
961
1153
|
login { name }
|
962
1154
|
|
963
|
-
trait :
|
1155
|
+
trait :active do
|
964
1156
|
name { "John Doe" }
|
965
|
-
|
966
|
-
login { "#{name} (
|
1157
|
+
status { :active }
|
1158
|
+
login { "#{name} (active)" }
|
967
1159
|
end
|
968
1160
|
|
969
|
-
trait :
|
1161
|
+
trait :inactive do
|
970
1162
|
name { "Jane Doe" }
|
971
|
-
|
972
|
-
login { "#{name} (
|
1163
|
+
status { :inactive }
|
1164
|
+
login { "#{name} (inactive)" }
|
973
1165
|
end
|
974
1166
|
|
975
1167
|
trait :admin do
|
@@ -977,8 +1169,8 @@ factory :user do
|
|
977
1169
|
login { "admin-#{name}" }
|
978
1170
|
end
|
979
1171
|
|
980
|
-
factory :
|
981
|
-
factory :
|
1172
|
+
factory :active_admin, traits: [:active, :admin] # login will be "admin-John Doe"
|
1173
|
+
factory :inactive_admin, traits: [:admin, :inactive] # login will be "Jane Doe (inactive)"
|
982
1174
|
end
|
983
1175
|
```
|
984
1176
|
|
@@ -991,19 +1183,41 @@ factory :user do
|
|
991
1183
|
name { "Friendly User" }
|
992
1184
|
login { name }
|
993
1185
|
|
994
|
-
trait :
|
1186
|
+
trait :active do
|
995
1187
|
name { "John Doe" }
|
996
|
-
|
1188
|
+
status { :active }
|
997
1189
|
login { "#{name} (M)" }
|
998
1190
|
end
|
999
1191
|
|
1000
1192
|
factory :brandon do
|
1001
|
-
|
1193
|
+
active
|
1002
1194
|
name { "Brandon" }
|
1003
1195
|
end
|
1004
1196
|
end
|
1005
1197
|
```
|
1006
1198
|
|
1199
|
+
### As mixins
|
1200
|
+
|
1201
|
+
Traits can be defined outside of factories and used as mixins to compose shared attributes
|
1202
|
+
|
1203
|
+
```ruby
|
1204
|
+
FactoryBot.define do
|
1205
|
+
trait :timestamps do
|
1206
|
+
created_at { 8.days.ago }
|
1207
|
+
updated_at { 4.days.ago }
|
1208
|
+
end
|
1209
|
+
|
1210
|
+
factory :user, traits: [:timestamps] do
|
1211
|
+
username { "john_doe" }
|
1212
|
+
end
|
1213
|
+
|
1214
|
+
factory :post do
|
1215
|
+
timestamps
|
1216
|
+
title { "Traits rock" }
|
1217
|
+
end
|
1218
|
+
end
|
1219
|
+
```
|
1220
|
+
|
1007
1221
|
### Using traits
|
1008
1222
|
|
1009
1223
|
Traits can also be passed in as a list of symbols when you construct an instance
|
@@ -1013,9 +1227,9 @@ from factory\_bot.
|
|
1013
1227
|
factory :user do
|
1014
1228
|
name { "Friendly User" }
|
1015
1229
|
|
1016
|
-
trait :
|
1230
|
+
trait :active do
|
1017
1231
|
name { "John Doe" }
|
1018
|
-
|
1232
|
+
status { :active }
|
1019
1233
|
end
|
1020
1234
|
|
1021
1235
|
trait :admin do
|
@@ -1023,8 +1237,8 @@ factory :user do
|
|
1023
1237
|
end
|
1024
1238
|
end
|
1025
1239
|
|
1026
|
-
# creates an admin user with
|
1027
|
-
create(:user, :admin, :
|
1240
|
+
# creates an admin user with :active status and name "Jon Snow"
|
1241
|
+
create(:user, :admin, :active, name: "Jon Snow")
|
1028
1242
|
```
|
1029
1243
|
|
1030
1244
|
This ability works with `build`, `build_stubbed`, `attributes_for`, and `create`.
|
@@ -1042,8 +1256,8 @@ factory :user do
|
|
1042
1256
|
end
|
1043
1257
|
end
|
1044
1258
|
|
1045
|
-
# creates 3 admin users with
|
1046
|
-
create_list(:user, 3, :admin, :
|
1259
|
+
# creates 3 admin users with :active status and name "Jon Snow"
|
1260
|
+
create_list(:user, 3, :admin, :active, name: "Jon Snow")
|
1047
1261
|
```
|
1048
1262
|
|
1049
1263
|
### With associations
|
@@ -1342,7 +1556,6 @@ FactoryBot.define do
|
|
1342
1556
|
factory :application_user, parent: :user do
|
1343
1557
|
full_name { "Jane Doe" }
|
1344
1558
|
date_of_birth { 21.years.ago }
|
1345
|
-
gender { "Female" }
|
1346
1559
|
health { 90 }
|
1347
1560
|
end
|
1348
1561
|
end
|
@@ -1355,7 +1568,6 @@ FactoryBot.modify do
|
|
1355
1568
|
factory :user do
|
1356
1569
|
full_name { "Jane Doe" }
|
1357
1570
|
date_of_birth { 21.years.ago }
|
1358
|
-
gender { "Female" }
|
1359
1571
|
health { 90 }
|
1360
1572
|
end
|
1361
1573
|
end
|
@@ -1393,6 +1605,15 @@ twenty_somethings = build_list(:user, 10) do |user, i|
|
|
1393
1605
|
end
|
1394
1606
|
```
|
1395
1607
|
|
1608
|
+
`create_list` passes saved instances into the block. If you modify the instance, you must save it again:
|
1609
|
+
|
1610
|
+
```ruby
|
1611
|
+
twenty_somethings = create_list(:user, 10) do |user, i|
|
1612
|
+
user.date_of_birth = (20 + i).years.ago
|
1613
|
+
user.save!
|
1614
|
+
end
|
1615
|
+
```
|
1616
|
+
|
1396
1617
|
`build_stubbed_list` will give you fully stubbed out instances:
|
1397
1618
|
|
1398
1619
|
```ruby
|
@@ -1567,7 +1788,7 @@ factory :user do
|
|
1567
1788
|
|
1568
1789
|
name "John Doe"
|
1569
1790
|
|
1570
|
-
initialize_with { new(attributes) }
|
1791
|
+
initialize_with { new(**attributes) }
|
1571
1792
|
end
|
1572
1793
|
```
|
1573
1794
|
|
data/NEWS.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# News
|
2
2
|
|
3
|
+
## 6.2.1 (March 8, 2022)
|
4
|
+
* Added: CI testing against truffleruby
|
5
|
+
* Changed: Documentation improvements for sequences and traits
|
6
|
+
* Fixed: ActiveSupport::Notifications reporting strategy through associations now report as symbols
|
7
|
+
* Fixed: `add_attribute` with reserved keywords assigns values correctly
|
8
|
+
|
9
|
+
## 6.2.0 (May 7, 2021)
|
10
|
+
* Added: support for Ruby 3.0
|
11
|
+
* Changed: Include factory or trait name in error messages for missing traits. d05a9a3c
|
12
|
+
* Changed: Switched from Travis CI to GitHub Actions
|
13
|
+
* Fixed: More Ruby 2.7 kwarg deprecation warnings
|
14
|
+
|
3
15
|
## 6.1.0 (July 8, 2020)
|
4
16
|
* Added: public reader for the evaluation instance, helpful for building interrelated associations
|
5
17
|
* Changed: raise a more helpful error when passing an invalid argument to an association
|
@@ -20,6 +32,7 @@
|
|
20
32
|
* Added: `build_stubbed_starting_id=` option to define the starting id for `build_stubbed`
|
21
33
|
* Removed: deprecated methods on the top-level `FactoryBot` module meant only for internal use
|
22
34
|
* Removed: support for EOL versions of Ruby (2.3, 2.4) and Rails (4.2)
|
35
|
+
* Removed: support for "abstract" factories with no associated class; use traits instead.
|
23
36
|
|
24
37
|
## 5.2.0 (April 24, 2020)
|
25
38
|
* Added: Pass index to block for `*_list` methods
|
data/README.md
CHANGED
@@ -43,7 +43,7 @@ gem install factory_bot
|
|
43
43
|
Supported Ruby versions
|
44
44
|
-----------------------
|
45
45
|
|
46
|
-
Supported Ruby versions are listed in [`.
|
46
|
+
Supported Ruby versions are listed in [`.github/workflows/build.yml`](https://github.com/thoughtbot/factory_bot/blob/master/.github/workflows/build.yml)
|
47
47
|
|
48
48
|
More Information
|
49
49
|
----------------
|
@@ -94,8 +94,8 @@ See [our other projects][community] or
|
|
94
94
|
|
95
95
|
[community]: https://thoughtbot.com/community?utm_source=github
|
96
96
|
[hire]: https://thoughtbot.com/hire-us?utm_source=github
|
97
|
-
[ci-image]: https://
|
98
|
-
[ci]: https://
|
97
|
+
[ci-image]: https://github.com/thoughtbot/factory_bot/actions/workflows/build.yml/badge.svg
|
98
|
+
[ci]: https://github.com/thoughtbot/factory_bot/actions?query=workflow%3A.github%2Fworkflows%2Fbuild.yml+branch%3Amaster++
|
99
99
|
[grade-image]: https://codeclimate.com/github/thoughtbot/factory_bot/badges/gpa.svg
|
100
100
|
[grade]: https://codeclimate.com/github/thoughtbot/factory_bot
|
101
101
|
[version-image]: https://badge.fury.io/rb/factory_bot.svg
|
data/lib/factory_bot/aliases.rb
CHANGED
@@ -37,8 +37,9 @@ module FactoryBot
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def decorated_evaluator
|
40
|
-
Decorator::
|
41
|
-
Decorator::
|
40
|
+
Decorator::NewConstructor.new(
|
41
|
+
Decorator::InvocationTracker.new(@evaluator),
|
42
|
+
@build_class
|
42
43
|
)
|
43
44
|
end
|
44
45
|
|
data/lib/factory_bot/callback.rb
CHANGED
@@ -9,7 +9,7 @@ module FactoryBot
|
|
9
9
|
|
10
10
|
def run(instance, evaluator)
|
11
11
|
case block.arity
|
12
|
-
when 1, -1 then syntax_runner.instance_exec(instance, &block)
|
12
|
+
when 1, -1, -2 then syntax_runner.instance_exec(instance, &block)
|
13
13
|
when 2 then syntax_runner.instance_exec(instance, evaluator, &block)
|
14
14
|
else syntax_runner.instance_exec(&block)
|
15
15
|
end
|
@@ -6,17 +6,11 @@ module FactoryBot
|
|
6
6
|
@invoked_methods = []
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
super
|
13
|
-
end
|
14
|
-
else
|
15
|
-
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
|
16
|
-
@invoked_methods << name
|
17
|
-
super
|
18
|
-
end
|
9
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
|
10
|
+
@invoked_methods << name
|
11
|
+
super
|
19
12
|
end
|
13
|
+
ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
|
20
14
|
|
21
15
|
def __invoked_methods__
|
22
16
|
@invoked_methods.uniq
|
@@ -17,7 +17,7 @@ module FactoryBot
|
|
17
17
|
end
|
18
18
|
RUBY
|
19
19
|
else
|
20
|
-
def method_missing(name, *args, &block) # rubocop:disable Style/
|
20
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
|
21
21
|
@component.send(name, *args, &block)
|
22
22
|
end
|
23
23
|
|
@@ -30,7 +30,7 @@ module FactoryBot
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def to_create(&block)
|
33
|
-
if
|
33
|
+
if block
|
34
34
|
@to_create = block
|
35
35
|
else
|
36
36
|
aggregate_from_traits_and_self(:to_create) { @to_create }.last
|
@@ -111,6 +111,20 @@ module FactoryBot
|
|
111
111
|
|
112
112
|
def base_traits
|
113
113
|
@base_traits.map { |name| trait_by_name(name) }
|
114
|
+
rescue KeyError => error
|
115
|
+
raise error_with_definition_name(error)
|
116
|
+
end
|
117
|
+
|
118
|
+
def error_with_definition_name(error)
|
119
|
+
message = error.message
|
120
|
+
message.insert(
|
121
|
+
message.index("\nDid you mean?") || message.length,
|
122
|
+
" referenced within \"#{name}\" definition"
|
123
|
+
)
|
124
|
+
|
125
|
+
error.class.new(message).tap do |new_error|
|
126
|
+
new_error.set_backtrace(error.backtrace)
|
127
|
+
end
|
114
128
|
end
|
115
129
|
|
116
130
|
def additional_traits
|
@@ -88,7 +88,7 @@ module FactoryBot
|
|
88
88
|
# end
|
89
89
|
#
|
90
90
|
# are equivalent.
|
91
|
-
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
|
91
|
+
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
|
92
92
|
association_options = args.first
|
93
93
|
|
94
94
|
if association_options.nil?
|
@@ -24,7 +24,7 @@ module FactoryBot
|
|
24
24
|
def association(factory_name, *traits_and_overrides)
|
25
25
|
overrides = traits_and_overrides.extract_options!
|
26
26
|
strategy_override = overrides.fetch(:strategy) {
|
27
|
-
FactoryBot.use_parent_strategy ? @build_strategy.
|
27
|
+
FactoryBot.use_parent_strategy ? @build_strategy.to_sym : :create
|
28
28
|
}
|
29
29
|
|
30
30
|
traits_and_overrides += [overrides.except(:strategy)]
|
@@ -35,23 +35,14 @@ module FactoryBot
|
|
35
35
|
|
36
36
|
attr_accessor :instance
|
37
37
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
SyntaxRunner.new.send(method_name, *args, **kwargs, &block)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
else
|
47
|
-
def method_missing(method_name, *args, &block) # rubocop:disable Style/MethodMissingSuper, Style/MissingRespondToMissing
|
48
|
-
if @instance.respond_to?(method_name)
|
49
|
-
@instance.send(method_name, *args, &block)
|
50
|
-
else
|
51
|
-
SyntaxRunner.new.send(method_name, *args, &block)
|
52
|
-
end
|
38
|
+
def method_missing(method_name, *args, &block)
|
39
|
+
if @instance.respond_to?(method_name)
|
40
|
+
@instance.send(method_name, *args, &block)
|
41
|
+
else
|
42
|
+
SyntaxRunner.new.send(method_name, *args, &block)
|
53
43
|
end
|
54
44
|
end
|
45
|
+
ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
|
55
46
|
|
56
47
|
def respond_to_missing?(method_name, _include_private = false)
|
57
48
|
@instance.respond_to?(method_name) || SyntaxRunner.new.respond_to?(method_name)
|
data/lib/factory_bot/registry.rb
CHANGED
@@ -15,7 +15,7 @@ module FactoryBot
|
|
15
15
|
def factory(name, options = {}, &block)
|
16
16
|
factory = Factory.new(name, options)
|
17
17
|
proxy = FactoryBot::DefinitionProxy.new(factory.definition)
|
18
|
-
proxy.instance_eval(&block) if
|
18
|
+
proxy.instance_eval(&block) if block
|
19
19
|
|
20
20
|
Internal.register_factory(factory)
|
21
21
|
|
data/lib/factory_bot/trait.rb
CHANGED
data/lib/factory_bot/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factory_bot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.1
|
4
|
+
version: 6.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Clayton
|
8
8
|
- Joe Ferris
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2022-03-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -237,7 +237,7 @@ homepage: https://github.com/thoughtbot/factory_bot
|
|
237
237
|
licenses:
|
238
238
|
- MIT
|
239
239
|
metadata: {}
|
240
|
-
post_install_message:
|
240
|
+
post_install_message:
|
241
241
|
rdoc_options: []
|
242
242
|
require_paths:
|
243
243
|
- lib
|
@@ -252,8 +252,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
252
252
|
- !ruby/object:Gem::Version
|
253
253
|
version: '0'
|
254
254
|
requirements: []
|
255
|
-
rubygems_version: 3.1.
|
256
|
-
signing_key:
|
255
|
+
rubygems_version: 3.1.6
|
256
|
+
signing_key:
|
257
257
|
specification_version: 4
|
258
258
|
summary: factory_bot provides a framework and DSL for defining and using model instance
|
259
259
|
factories.
|