cucumber_factory 2.0.2 → 2.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eeed19e5c878629c3f87a038821a955401c40c19ca323577d7e84e3ae019f764
4
- data.tar.gz: 2d3b57e9b739be6e69d28240c7553eec3882b2e200ca64c402a8cc646bcdc169
3
+ metadata.gz: 8f3cf136399f60bcca2308f17e39c1846de1e443157ac433bcdb94f6937a3333
4
+ data.tar.gz: 5983deb45accf5811e0af7f251a15f37062600c7decbf543a021b3338578a9bc
5
5
  SHA512:
6
- metadata.gz: 752a2cbe68fa53254741a792770ab0252f320a218fb3c39fe85679bcf6d8e1289fdee354042bb342d96789266c6f8ac02819393ee375d628def84679de281cad
7
- data.tar.gz: aa2eb84a898e7d52f10b7272ad8f7c04a9d1dea4096d0a7fab04d9158a887f46839e7d36b83f9aec945b13b18f0b4550de19fe9df0897ccc1235f22f990b2b59
6
+ metadata.gz: bb54944c1e92864af9cfcdaca67dfe3988577394907fce3c682b02ea900b50bc89d6d89eb6cdc3cdb90cfc89c199391e02dbfd50ef158ba46f0ccb2129ef8100
7
+ data.tar.gz: 9d90540b249f759377eb7cde97dc567fb61bada43f09c19ad6afaa73fff53e97acfd781ff8014515b9a0b04b8d8772663b8fc367cc9e743e9b61a26f1db839e9
data/.gitignore CHANGED
@@ -6,3 +6,4 @@ pkg
6
6
  .rvmrc
7
7
  log/*.log
8
8
  spec/support/database.yml
9
+ uploads/
@@ -13,6 +13,59 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
13
13
 
14
14
  ### Compatible changes
15
15
 
16
+ -
17
+
18
+ ## 2.3.1 - 2020-10-01
19
+
20
+ ### Compatible changes
21
+
22
+ - Lowered the priority of all steps in this gem to avoid issues with overlapping steps.
23
+
24
+ ## 2.3.0 - 2020-09-24
25
+
26
+ ### Compatible changes
27
+
28
+ - Added a step to add file objects to a model:
29
+ ```cucumber
30
+ Given there is a user with the avatar file:"path/to/avatar.jpg"
31
+ ```
32
+ Both single and double quotes are supported.
33
+
34
+ ## 2.2.0 - 2020-09-23
35
+
36
+ ### Compatible changes
37
+
38
+ - A step was added that allows modifying existing records with a similar syntax to creating new records:
39
+ ```cucumber
40
+ (Given "Bob" is a user)
41
+ And "Bob" has the email "foo@bar.com" and is subscribed
42
+ ```
43
+ - This step will also work with doc strings or tables:
44
+ ```cucumber
45
+ (Given "Bob" is a user)
46
+ And the user above has these attributes:
47
+ | name | Bob |
48
+ | email | foo@bar.com |
49
+ ```
50
+
51
+ ## 2.1.1 - 2020-05-20
52
+
53
+ ### Compatible changes
54
+
55
+ - Cucumber 2.1.0 introduced some regressions which are being addressed with this patch:
56
+ - Fix the assignment of polymorphic associations.
57
+ - Restore the support for inherited traits within nested factories.
58
+
59
+ ## 2.1.0 - 2020-03-09
60
+
61
+ ### Compatible changes
62
+
63
+ - Allow associations to be set for [transient attributes](https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#transient-attributes) if they are named after the model. For example, when there is a `Role` model and the`user` factory has a transient attribute `role`, the following steps are now valid:
64
+ ```
65
+ Given there is a role
66
+ And there is a user with the role above
67
+ ```
68
+
16
69
  ## 2.0.2 - 2020-03-26
17
70
 
18
71
  ### Compatible changes
@@ -12,5 +12,9 @@ gem 'rake', '>=10.0.4'
12
12
  gem 'database_cleaner', '~>1.0.0'
13
13
  gem 'gemika'
14
14
 
15
+ # Test dependencies
16
+ gem 'factory_bot', '< 5'
17
+ gem 'carrierwave', '~> 1.0'
18
+
15
19
  # Gem under test
16
20
  gem 'cucumber_factory', :path => '.'
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cucumber_factory (2.0.2)
4
+ cucumber_factory (2.3.1)
5
5
  activerecord
6
6
  activesupport
7
7
  cucumber
@@ -24,6 +24,10 @@ GEM
24
24
  tzinfo (~> 1.1)
25
25
  arel (6.0.4)
26
26
  builder (3.2.4)
27
+ carrierwave (1.2.3)
28
+ activemodel (>= 4.0.0)
29
+ activesupport (>= 4.0.0)
30
+ mime-types (>= 1.16)
27
31
  concurrent-ruby (1.1.6)
28
32
  cucumber (1.3.20)
29
33
  builder (>= 2.1.2)
@@ -35,11 +39,16 @@ GEM
35
39
  cucumber
36
40
  database_cleaner (1.0.1)
37
41
  diff-lcs (1.3)
42
+ factory_bot (4.11.1)
43
+ activesupport (>= 3.0.0)
38
44
  gemika (0.4.0)
39
45
  gherkin (2.12.2)
40
46
  multi_json (~> 1.3)
41
47
  i18n (0.9.5)
42
48
  concurrent-ruby (~> 1.0)
49
+ mime-types (3.2.2)
50
+ mime-types-data (~> 3.2015)
51
+ mime-types-data (3.2018.0812)
43
52
  minitest (5.12.0)
44
53
  multi_json (1.14.1)
45
54
  multi_test (0.1.2)
@@ -68,9 +77,11 @@ PLATFORMS
68
77
  DEPENDENCIES
69
78
  activerecord (~> 4.2.0)
70
79
  activesupport (~> 4.2.0)
80
+ carrierwave (~> 1.0)
71
81
  cucumber (~> 1.3.20)
72
82
  cucumber_factory!
73
83
  database_cleaner (~> 1.0.0)
84
+ factory_bot (< 5)
74
85
  gemika
75
86
  mysql2
76
87
  rake (>= 10.0.4)
@@ -12,5 +12,9 @@ gem 'rake'
12
12
  gem 'database_cleaner'
13
13
  gem 'gemika'
14
14
 
15
+ # Test dependencies
16
+ gem 'factory_bot', '< 5' # 5.0 requires Ruby >= 2.3
17
+ gem 'carrierwave', '~> 1.0' # 2.0 requires Rails >= 5 and Ruby >= 2.2
18
+
15
19
  # Gem under test
16
20
  gem 'cucumber_factory', :path => '.'
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cucumber_factory (2.0.2)
4
+ cucumber_factory (2.3.1)
5
5
  activerecord
6
6
  activesupport
7
7
  cucumber
@@ -24,6 +24,10 @@ GEM
24
24
  tzinfo (~> 1.1)
25
25
  arel (6.0.4)
26
26
  builder (3.2.3)
27
+ carrierwave (1.2.3)
28
+ activemodel (>= 4.0.0)
29
+ activesupport (>= 4.0.0)
30
+ mime-types (>= 1.16)
27
31
  concurrent-ruby (1.0.5)
28
32
  cucumber (2.4.0)
29
33
  builder (>= 2.1.2)
@@ -40,10 +44,15 @@ GEM
40
44
  cucumber
41
45
  database_cleaner (1.6.2)
42
46
  diff-lcs (1.3)
47
+ factory_bot (4.11.1)
48
+ activesupport (>= 3.0.0)
43
49
  gemika (0.3.2)
44
50
  gherkin (4.1.3)
45
51
  i18n (0.9.5)
46
52
  concurrent-ruby (~> 1.0)
53
+ mime-types (3.2.2)
54
+ mime-types-data (~> 3.2015)
55
+ mime-types-data (3.2018.0812)
47
56
  minitest (5.11.3)
48
57
  multi_json (1.13.1)
49
58
  multi_test (0.1.2)
@@ -72,9 +81,11 @@ PLATFORMS
72
81
  DEPENDENCIES
73
82
  activerecord (~> 4.2.0)
74
83
  activesupport (~> 4.2.0)
84
+ carrierwave (~> 1.0)
75
85
  cucumber (~> 2.4.0)
76
86
  cucumber_factory!
77
87
  database_cleaner
88
+ factory_bot (< 5)
78
89
  gemika
79
90
  mysql2
80
91
  rake
@@ -12,5 +12,9 @@ gem 'rake'
12
12
  gem 'database_cleaner'
13
13
  gem 'gemika'
14
14
 
15
+ # Test dependencies
16
+ gem 'factory_bot'
17
+ gem 'carrierwave'
18
+
15
19
  # Gem under test
16
20
  gem 'cucumber_factory', :path => '.'
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cucumber_factory (2.0.2)
4
+ cucumber_factory (2.3.1)
5
5
  activerecord
6
6
  activesupport
7
7
  cucumber
@@ -24,6 +24,10 @@ GEM
24
24
  arel (7.1.4)
25
25
  backports (3.11.1)
26
26
  builder (3.2.3)
27
+ carrierwave (1.2.3)
28
+ activemodel (>= 4.0.0)
29
+ activesupport (>= 4.0.0)
30
+ mime-types (>= 1.16)
27
31
  concurrent-ruby (1.0.5)
28
32
  cucumber (3.0.2)
29
33
  builder (>= 2.1.2)
@@ -45,10 +49,15 @@ GEM
45
49
  cucumber
46
50
  database_cleaner (1.6.2)
47
51
  diff-lcs (1.3)
52
+ factory_bot (5.1.1)
53
+ activesupport (>= 4.2.0)
48
54
  gemika (0.3.2)
49
55
  gherkin (4.1.3)
50
56
  i18n (0.9.5)
51
57
  concurrent-ruby (~> 1.0)
58
+ mime-types (3.2.2)
59
+ mime-types-data (~> 3.2015)
60
+ mime-types-data (3.2018.0812)
52
61
  minitest (5.11.3)
53
62
  multi_json (1.13.1)
54
63
  multi_test (0.1.2)
@@ -77,9 +86,11 @@ PLATFORMS
77
86
  DEPENDENCIES
78
87
  activerecord (~> 5.0.0)
79
88
  activesupport (~> 5.0.0)
89
+ carrierwave
80
90
  cucumber (~> 3.0.0)
81
91
  cucumber_factory!
82
92
  database_cleaner
93
+ factory_bot
83
94
  gemika
84
95
  mysql2
85
96
  rake
@@ -12,5 +12,9 @@ gem 'rake'
12
12
  gem 'database_cleaner'
13
13
  gem 'gemika'
14
14
 
15
+ # Test dependencies
16
+ gem 'factory_bot'
17
+ gem 'carrierwave'
18
+
15
19
  # Gem under test
16
20
  gem 'cucumber_factory', :path => '.'
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cucumber_factory (2.0.2)
4
+ cucumber_factory (2.3.1)
5
5
  activerecord
6
6
  activesupport
7
7
  cucumber
@@ -24,6 +24,10 @@ GEM
24
24
  arel (8.0.0)
25
25
  backports (3.11.1)
26
26
  builder (3.2.3)
27
+ carrierwave (1.2.3)
28
+ activemodel (>= 4.0.0)
29
+ activesupport (>= 4.0.0)
30
+ mime-types (>= 1.16)
27
31
  concurrent-ruby (1.0.5)
28
32
  cucumber (3.1.0)
29
33
  builder (>= 2.1.2)
@@ -45,10 +49,15 @@ GEM
45
49
  cucumber
46
50
  database_cleaner (1.6.2)
47
51
  diff-lcs (1.3)
52
+ factory_bot (5.1.1)
53
+ activesupport (>= 4.2.0)
48
54
  gemika (0.3.2)
49
55
  gherkin (5.0.0)
50
56
  i18n (0.9.5)
51
57
  concurrent-ruby (~> 1.0)
58
+ mime-types (3.2.2)
59
+ mime-types-data (~> 3.2015)
60
+ mime-types-data (3.2018.0812)
52
61
  minitest (5.11.3)
53
62
  multi_json (1.13.1)
54
63
  multi_test (0.1.2)
@@ -77,9 +86,11 @@ PLATFORMS
77
86
  DEPENDENCIES
78
87
  activerecord (~> 5.1.0)
79
88
  activesupport (~> 5.1.0)
89
+ carrierwave
80
90
  cucumber (~> 3.1.0)
81
91
  cucumber_factory!
82
92
  database_cleaner
93
+ factory_bot
83
94
  gemika
84
95
  mysql2
85
96
  rake
data/README.md CHANGED
@@ -24,6 +24,13 @@ Quoted strings and numbers denote attribute values:
24
24
  Given there is a movie with the title "Sunshine" and the year 2007
25
25
  ```
26
26
 
27
+ To update an existing record, specify the record and the changes:
28
+ ```
29
+ Given the movie above has the title "Sunset" and the year 2008
30
+ Given the movie "Sunrise" has the year 2009
31
+ ```
32
+ A record can be specified by the `above` keyword, which uses the last created record of this class, or by any string that was used during its creation.
33
+
27
34
  Setting boolean attributes
28
35
  --------------------------
29
36
 
@@ -42,6 +49,13 @@ Given there is a movie which is awesome, popular and successful but not science
42
49
  And there is a director with the income "500000" but with the account balance "-30000"
43
50
  ```
44
51
 
52
+ To update boolean attributes use the keyword `is`:
53
+
54
+ ```cucumber
55
+ Given the movie above is awesome but not popular
56
+ Given the movie above has the year 1979 but is not science fiction
57
+ ```
58
+
45
59
 
46
60
  Setting many attributes with a table
47
61
  ------------------------------------
@@ -62,10 +76,18 @@ Given there is a movie with these attributes:
62
76
  | comedy | false |
63
77
  ```
64
78
 
79
+ ```cucumber
80
+ Given the movie above has these attributes:
81
+ """
82
+ name: Sunshine
83
+ comedy: false
84
+ """
85
+ ```
86
+
65
87
  Setting associations
66
88
  --------------------
67
89
 
68
- You can set `belongs_to` associations by referring to the last created record of as `above`:
90
+ You can set `belongs_to` and `transient` associations by referring to the last created record of as `above`:
69
91
 
70
92
  ```cucumber
71
93
  Given there is a movie with the title "Before Sunrise"
@@ -129,7 +151,16 @@ Given there is a movie with the tags ["comedy", "drama" and "action"]
129
151
  ```
130
152
 
131
153
 
154
+ Setting file attributes
155
+ -----------------------
156
+
157
+ You can set an attribute to a file object with the following syntax:
158
+
159
+ ```cucumber
160
+ Given there is a movie with the image file:'path/to/image.jpg'
161
+ ```
132
162
 
163
+ All paths are relative to the project root, absolute paths are not supported. Please note that file attributes must follow the syntax `file:"PATH"`, both single and double quotes are allowed.
133
164
 
134
165
  Using named factories and traits
135
166
  --------------------------------
@@ -13,6 +13,7 @@ require 'cucumber_priority'
13
13
 
14
14
  # Gem
15
15
  require 'cucumber_factory/build_strategy'
16
+ require 'cucumber_factory/update_strategy'
16
17
  require 'cucumber_factory/factory'
17
18
  require 'cucumber_factory/switcher'
18
19
 
@@ -7,79 +7,115 @@ module CucumberFactory
7
7
  class << self
8
8
 
9
9
  def from_prose(model_prose, variant_prose)
10
- # don't use \w which depends on the system locale
11
- underscored_model_name = model_prose.gsub(/[^A-Za-z0-9_\/]+/, "_")
12
- if variant_prose.present?
13
- variants = /\((.*?)\)/.match(variant_prose)[1].split(/\s*,\s*/)
14
- variants = variants.collect { |variant| variant.downcase.gsub(" ", "_") }
10
+ variants = variants_from_prose(variant_prose)
11
+ factory = factory_bot_factory(model_prose, variants)
12
+
13
+ if factory
14
+ factory.compile # Required to load inherited traits!
15
+ strategy = factory_bot_strategy(factory, model_prose, variants)
16
+ transient_attributes = factory_bot_transient_attributes(factory, variants)
15
17
  else
16
- variants = []
18
+ strategy = alternative_strategy(model_prose, variants)
19
+ transient_attributes = []
17
20
  end
18
21
 
19
- if factory_bot_strategy = factory_bot_strategy(underscored_model_name, variants)
20
- factory_bot_strategy
22
+ [strategy, transient_attributes]
23
+ end
24
+
25
+ def parse_model_class(model_prose)
26
+ underscored_model_name(model_prose).camelize.constantize
27
+ end
28
+
29
+ private
30
+
31
+ def variants_from_prose(variant_prose)
32
+ if variant_prose.present?
33
+ variants = /\((.*?)\)/.match(variant_prose)[1].split(/\s*,\s*/)
34
+ variants.collect { |variant| variant.downcase.gsub(" ", "_").to_sym }
21
35
  else
22
- model_class = underscored_model_name.camelize.constantize
23
- machinist_strategy(model_class, variants) ||
24
- active_record_strategy(model_class) ||
25
- ruby_object_strategy(model_class)
36
+ []
26
37
  end
27
38
  end
28
39
 
29
- private
40
+ def factory_bot_factory(model_prose, variants)
41
+ return unless factory_bot_class
30
42
 
31
- def factory_bot_strategy(factory_name, variants)
32
- factory_class = ::FactoryBot if defined?(FactoryBot)
33
- factory_class ||= ::FactoryGirl if defined?(FactoryGirl)
34
- return unless factory_class
43
+ factory_name = factory_name_from_prose(model_prose)
44
+ factory = factory_bot_class.factories[factory_name]
35
45
 
36
- variants = variants.map(&:to_sym)
37
- factory_name = factory_name.to_s.underscore.gsub('/', '_').to_sym
46
+ if factory.nil? && variants.present?
47
+ factory = factory_bot_class.factories[variants[0]]
48
+ end
38
49
 
39
- factory = factory_class.factories[factory_name]
50
+ factory
51
+ end
40
52
 
41
- if factory.nil? && variants.present? && factory = factory_class.factories[variants[0]]
53
+ def factory_bot_strategy(factory, model_prose, variants)
54
+ return unless factory
55
+
56
+ factory_name = factory_name_from_prose(model_prose)
57
+ if factory_bot_class.factories[factory_name].nil? && variants.present?
42
58
  factory_name, *variants = variants
43
59
  end
44
60
 
45
- if factory
46
- new(factory.build_class) do |attributes|
47
- # Cannot have additional scalar args after a varargs
48
- # argument in Ruby 1.8 and 1.9
49
- args = []
50
- args += variants
51
- args << attributes
52
- factory_class.create(factory_name, *args)
53
- end
61
+ new(factory.build_class) do |attributes|
62
+ # Cannot have additional scalar args after a varargs
63
+ # argument in Ruby 1.8 and 1.9
64
+ args = []
65
+ args += variants
66
+ args << attributes
67
+ factory_bot_class.create(factory_name, *args)
68
+ end
69
+ end
70
+
71
+ def factory_bot_transient_attributes(factory, variants)
72
+ return [] unless factory
73
+
74
+ factory_attributes = factory_bot_attributes(factory, variants)
75
+ class_attributes = factory.build_class.attribute_names.map(&:to_sym)
76
+
77
+ factory_attributes - class_attributes
78
+ end
79
+
80
+ def factory_bot_attributes(factory, variants)
81
+ traits = factory_bot_traits(factory, variants)
82
+ factory.with_traits(traits.map(&:name)).definition.attributes.names
83
+ end
84
+
85
+ def factory_bot_traits(factory, variants)
86
+ factory.definition.defined_traits.select do |trait|
87
+ variants.include?(trait.name.to_sym)
54
88
  end
89
+ end
55
90
 
91
+ def alternative_strategy(model_prose, variants)
92
+ model_class = parse_model_class(model_prose)
93
+ machinist_strategy(model_class, variants) ||
94
+ active_record_strategy(model_class) ||
95
+ ruby_object_strategy(model_class)
56
96
  end
57
97
 
58
98
  def machinist_strategy(model_class, variants)
59
- if model_class.respond_to?(:make)
60
-
61
- new(model_class) do |attributes|
62
- if variants.present?
63
- variants.size == 1 or raise 'Machinist only supports a single variant per blueprint'
64
- model_class.make(variants.first.to_sym, attributes)
65
- else
66
- model_class.make(attributes)
67
- end
68
- end
99
+ return unless model_class.respond_to?(:make)
69
100
 
101
+ new(model_class) do |attributes|
102
+ if variants.present?
103
+ variants.size == 1 or raise 'Machinist only supports a single variant per blueprint'
104
+ model_class.make(variants.first, attributes)
105
+ else
106
+ model_class.make(attributes)
107
+ end
70
108
  end
71
109
  end
72
110
 
73
111
  def active_record_strategy(model_class)
74
- if model_class.respond_to?(:create!)
75
-
76
- new(model_class) do |attributes|
77
- model = model_class.new
78
- CucumberFactory::Switcher.assign_attributes(model, attributes)
79
- model.save!
80
- model
81
- end
112
+ return unless model_class.respond_to?(:create!)
82
113
 
114
+ new(model_class) do |attributes|
115
+ model = model_class.new
116
+ CucumberFactory::Switcher.assign_attributes(model, attributes)
117
+ model.save!
118
+ model
83
119
  end
84
120
  end
85
121
 
@@ -89,6 +125,21 @@ module CucumberFactory
89
125
  end
90
126
  end
91
127
 
128
+ def factory_bot_class
129
+ factory_class = ::FactoryBot if defined?(FactoryBot)
130
+ factory_class ||= ::FactoryGirl if defined?(FactoryGirl)
131
+ factory_class
132
+ end
133
+
134
+ def factory_name_from_prose(model_prose)
135
+ underscored_model_name(model_prose).to_s.underscore.gsub('/', '_').to_sym
136
+ end
137
+
138
+ def underscored_model_name(model_prose)
139
+ # don't use \w which depends on the system locale
140
+ model_prose.gsub(/[^A-Za-z0-9_\/]+/, "_")
141
+ end
142
+
92
143
  end
93
144
 
94
145