reform 2.2.4 → 2.6.2
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 +5 -5
- data/.github/workflows/ci.yml +17 -0
- data/.gitignore +5 -1
- data/CHANGES.md +80 -4
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +2 -16
- data/ISSUE_TEMPLATE.md +25 -0
- data/LICENSE.txt +1 -1
- data/README.md +10 -12
- data/Rakefile +6 -10
- data/lib/reform/contract/custom_error.rb +41 -0
- data/lib/reform/contract/validate.rb +53 -23
- data/lib/reform/contract.rb +7 -17
- data/lib/reform/errors.rb +61 -0
- data/lib/reform/form/call.rb +1 -1
- data/lib/reform/form/composition.rb +2 -2
- data/lib/reform/form/dry/input_hash.rb +37 -0
- data/lib/reform/form/dry.rb +25 -35
- data/lib/reform/form/populator.rb +20 -26
- data/lib/reform/form/prepopulate.rb +5 -4
- data/lib/reform/form/validate.rb +29 -14
- data/lib/reform/form.rb +36 -10
- data/lib/reform/result.rb +90 -0
- data/lib/reform/validation/groups.rb +12 -28
- data/lib/reform/validation.rb +19 -11
- data/lib/reform/version.rb +1 -1
- data/lib/reform.rb +1 -0
- data/reform.gemspec +13 -13
- data/test/benchmarking.rb +39 -6
- data/test/call_test.rb +9 -9
- data/test/changed_test.rb +14 -14
- data/test/coercion_test.rb +57 -25
- data/test/composition_test.rb +85 -49
- data/test/contract/custom_error_test.rb +55 -0
- data/test/contract_test.rb +20 -20
- data/test/default_test.rb +4 -4
- data/test/deserialize_test.rb +17 -20
- data/test/docs/validation_test.rb +134 -0
- data/test/errors_test.rb +142 -82
- data/test/feature_test.rb +10 -12
- data/test/fixtures/dry_error_messages.yml +83 -23
- data/test/form_option_test.rb +5 -5
- data/test/form_test.rb +8 -8
- data/test/from_test.rb +18 -22
- data/test/inherit_test.rb +54 -68
- data/test/module_test.rb +27 -32
- data/test/parse_option_test.rb +40 -0
- data/test/parse_pipeline_test.rb +4 -4
- data/test/populate_test.rb +217 -100
- data/test/populator_skip_test.rb +11 -11
- data/test/prepopulator_test.rb +24 -25
- data/test/read_only_test.rb +12 -1
- data/test/readable_test.rb +9 -9
- data/test/reform_test.rb +47 -66
- data/test/save_test.rb +35 -23
- data/test/setup_test.rb +17 -17
- data/test/skip_if_test.rb +33 -22
- data/test/skip_setter_and_getter_test.rb +9 -10
- data/test/test_helper.rb +23 -14
- data/test/validate_test.rb +165 -145
- data/test/validation/dry_validation_test.rb +630 -146
- data/test/validation/result_test.rb +77 -0
- data/test/validation_library_provided_test.rb +16 -0
- data/test/virtual_test.rb +47 -7
- data/test/writeable_test.rb +38 -9
- metadata +46 -38
- data/.travis.yml +0 -11
- data/gemfiles/Gemfile.disposable-0.3 +0 -6
- data/lib/reform/contract/errors.rb +0 -43
- data/lib/reform/form/mongoid.rb +0 -37
- data/lib/reform/form/orm.rb +0 -26
- data/lib/reform/mongoid.rb +0 -4
- data/test/deprecation_test.rb +0 -27
- data/test/readonly_test.rb +0 -14
- data/test/validation/dry_test.rb +0 -60
- data/test/validation/errors.yml +0 -4
|
@@ -1,231 +1,556 @@
|
|
|
1
1
|
require "test_helper"
|
|
2
2
|
require "reform/form/dry"
|
|
3
|
+
require "reform/form/coercion"
|
|
4
|
+
#---
|
|
5
|
+
# one "nested" Schema per form.
|
|
6
|
+
class DryValidationErrorsAPITest < Minitest::Spec
|
|
7
|
+
Album = Struct.new(:title, :artist, :songs)
|
|
8
|
+
Song = Struct.new(:title)
|
|
9
|
+
Artist = Struct.new(:email, :label)
|
|
10
|
+
Label = Struct.new(:location)
|
|
11
|
+
|
|
12
|
+
class AlbumForm < TestForm
|
|
13
|
+
property :title
|
|
14
|
+
|
|
15
|
+
validation do
|
|
16
|
+
params do
|
|
17
|
+
required(:title).filled(min_size?: 2)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
property :artist do
|
|
22
|
+
property :email
|
|
23
|
+
|
|
24
|
+
validation do
|
|
25
|
+
params { required(:email).filled }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
property :label do
|
|
29
|
+
property :location
|
|
30
|
+
|
|
31
|
+
validation do
|
|
32
|
+
params { required(:location).filled }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# note the validation block is *in* the collection block, per item, so to speak.
|
|
38
|
+
collection :songs do
|
|
39
|
+
property :title
|
|
40
|
+
|
|
41
|
+
validation do
|
|
42
|
+
config.messages.load_paths << "test/fixtures/dry_error_messages.yml"
|
|
43
|
+
|
|
44
|
+
params { required(:title).filled }
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
let(:form) { AlbumForm.new(Album.new(nil, Artist.new(nil, Label.new), [Song.new(nil), Song.new(nil)])) }
|
|
50
|
+
|
|
51
|
+
it "everything wrong" do
|
|
52
|
+
result = form.(title: nil, artist: {email: ""}, songs: [{title: "Clams have feelings too"}, {title: ""}])
|
|
53
|
+
|
|
54
|
+
assert_equal result.success?, false
|
|
55
|
+
|
|
56
|
+
assert_equal form.errors.messages, title: ["must be filled", "size cannot be less than 2"], "artist.email": ["must be filled"], "artist.label.location": ["must be filled"], "songs.title": ["must be filled"]
|
|
57
|
+
assert_equal form.artist.errors.messages, email: ["must be filled"], "label.location": ["must be filled"]
|
|
58
|
+
assert_equal form.artist.label.errors.messages, location: ["must be filled"]
|
|
59
|
+
assert_equal form.songs[0].errors.messages, {}
|
|
60
|
+
assert_equal form.songs[1].errors.messages, title: ["must be filled"]
|
|
61
|
+
|
|
62
|
+
# #errors[]
|
|
63
|
+
assert_equal form.errors[:nonsense], []
|
|
64
|
+
assert_equal form.errors[:title], ["must be filled", "size cannot be less than 2"]
|
|
65
|
+
assert_equal form.artist.errors[:email], ["must be filled"]
|
|
66
|
+
assert_equal form.artist.label.errors[:location], ["must be filled"]
|
|
67
|
+
assert_equal form.songs[0].errors[:title], []
|
|
68
|
+
assert_equal form.songs[1].errors[:title], ["must be filled"]
|
|
69
|
+
|
|
70
|
+
# #to_result
|
|
71
|
+
assert_equal form.to_result.errors, title: ["must be filled"]
|
|
72
|
+
assert_equal form.to_result.messages, title: ["must be filled", "size cannot be less than 2"]
|
|
73
|
+
assert_equal form.to_result.hints, title: ["size cannot be less than 2"]
|
|
74
|
+
assert_equal form.artist.to_result.errors, email: ["must be filled"]
|
|
75
|
+
assert_equal form.artist.to_result.messages, email: ["must be filled"]
|
|
76
|
+
assert_equal form.artist.to_result.hints, {}
|
|
77
|
+
assert_equal form.artist.label.to_result.errors, location: ["must be filled"]
|
|
78
|
+
assert_equal form.artist.label.to_result.messages, location: ["must be filled"]
|
|
79
|
+
assert_equal form.artist.label.to_result.hints, {}
|
|
80
|
+
assert_equal form.songs[0].to_result.errors, {}
|
|
81
|
+
assert_equal form.songs[0].to_result.messages, {}
|
|
82
|
+
assert_equal form.songs[0].to_result.hints, {}
|
|
83
|
+
assert_equal form.songs[1].to_result.errors, title: ["must be filled"]
|
|
84
|
+
assert_equal form.songs[1].to_result.messages, title: ["must be filled"]
|
|
85
|
+
assert_equal form.songs[1].to_result.hints, {}
|
|
86
|
+
assert_equal form.songs[1].to_result.errors(locale: :de), title: ["muss abgefüllt sein"]
|
|
87
|
+
# seems like dry-v when calling Dry::Schema::Result#messages locale option is ignored
|
|
88
|
+
# started a topic in their forum https://discourse.dry-rb.org/t/dry-result-messages-ignore-locale-option/910
|
|
89
|
+
# assert_equal form.songs[1].to_result.messages(locale: :de), (title: ["muss abgefüllt sein"])
|
|
90
|
+
assert_equal form.songs[1].to_result.hints(locale: :de), ({})
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "only nested property is invalid." do
|
|
94
|
+
result = form.(title: "Black Star", artist: {email: ""})
|
|
95
|
+
|
|
96
|
+
assert_equal result.success?, false
|
|
97
|
+
|
|
98
|
+
# errors.messages
|
|
99
|
+
assert_equal form.errors.messages, "artist.email": ["must be filled"], "artist.label.location": ["must be filled"], "songs.title": ["must be filled"]
|
|
100
|
+
assert_equal form.artist.errors.messages, email: ["must be filled"], "label.location": ["must be filled"]
|
|
101
|
+
assert_equal form.artist.label.errors.messages, location: ["must be filled"]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it "nested collection invalid" do
|
|
105
|
+
result = form.(title: "Black Star", artist: {email: "uhm", label: {location: "Hannover"}}, songs: [{title: ""}])
|
|
106
|
+
|
|
107
|
+
assert_equal result.success?, false
|
|
108
|
+
assert_equal form.errors.messages, "songs.title": ["must be filled"]
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
#---
|
|
112
|
+
#- validation .each
|
|
113
|
+
class CollectionExternalValidationsForm < TestForm
|
|
114
|
+
collection :songs do
|
|
115
|
+
property :title
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
validation do
|
|
119
|
+
params do
|
|
120
|
+
required(:songs).each do
|
|
121
|
+
schema do
|
|
122
|
+
required(:title).filled
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
it do
|
|
130
|
+
form = CollectionExternalValidationsForm.new(Album.new(nil, nil, [Song.new, Song.new]))
|
|
131
|
+
form.validate(songs: [{title: "Liar"}, {title: ""}])
|
|
132
|
+
|
|
133
|
+
assert_equal form.errors.messages, "songs.title": ["must be filled"]
|
|
134
|
+
assert_equal form.songs[0].errors.messages, {}
|
|
135
|
+
assert_equal form.songs[1].errors.messages, title: ["must be filled"]
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
class DryValidationExplicitSchemaTest < Minitest::Spec
|
|
140
|
+
Session = Struct.new(:name, :email)
|
|
141
|
+
SessionContract = Dry::Validation.Contract do
|
|
142
|
+
params do
|
|
143
|
+
required(:name).filled
|
|
144
|
+
required(:email).filled
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
class SessionForm < TestForm
|
|
149
|
+
include Coercion
|
|
150
|
+
|
|
151
|
+
property :name
|
|
152
|
+
property :email
|
|
153
|
+
|
|
154
|
+
validation contract: SessionContract
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
let(:form) { SessionForm.new(Session.new) }
|
|
158
|
+
|
|
159
|
+
# valid.
|
|
160
|
+
it do
|
|
161
|
+
assert form.validate(name: "Helloween", email: "yep")
|
|
162
|
+
assert_equal form.errors.messages.inspect, "{}"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
it "invalid" do
|
|
166
|
+
assert_equal form.validate(name: "", email: "yep"), false
|
|
167
|
+
assert_equal form.errors.messages.inspect, "{:name=>[\"must be filled\"]}"
|
|
168
|
+
end
|
|
169
|
+
end
|
|
3
170
|
|
|
4
171
|
class DryValidationDefaultGroupTest < Minitest::Spec
|
|
5
|
-
Session = Struct.new(:username, :email, :password, :confirm_password)
|
|
172
|
+
Session = Struct.new(:username, :email, :password, :confirm_password, :starts_at, :active, :color)
|
|
6
173
|
|
|
7
|
-
class SessionForm <
|
|
8
|
-
include
|
|
174
|
+
class SessionForm < TestForm
|
|
175
|
+
include Coercion
|
|
9
176
|
|
|
10
177
|
property :username
|
|
11
178
|
property :email
|
|
12
179
|
property :password
|
|
13
180
|
property :confirm_password
|
|
181
|
+
property :starts_at, type: Types::Params::DateTime
|
|
182
|
+
property :active, type: Types::Params::Bool
|
|
183
|
+
property :color
|
|
14
184
|
|
|
15
185
|
validation do
|
|
16
|
-
|
|
17
|
-
|
|
186
|
+
params do
|
|
187
|
+
required(:username).filled
|
|
188
|
+
required(:email).filled
|
|
189
|
+
required(:starts_at).filled(:date_time?)
|
|
190
|
+
required(:active).filled(:bool?)
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
validation name: :another_block do
|
|
195
|
+
params { required(:confirm_password).filled }
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
validation name: :dynamic_args do
|
|
199
|
+
option :form
|
|
200
|
+
params { optional(:color) }
|
|
201
|
+
rule(:color) do
|
|
202
|
+
if value
|
|
203
|
+
key.failure("must be one of: #{form.colors}") unless form.colors.include? value
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def colors
|
|
209
|
+
%(red orange green)
|
|
18
210
|
end
|
|
19
211
|
end
|
|
20
212
|
|
|
21
|
-
let
|
|
213
|
+
let(:form) { SessionForm.new(Session.new) }
|
|
22
214
|
|
|
23
215
|
# valid.
|
|
24
216
|
it do
|
|
25
|
-
form.validate(
|
|
26
|
-
|
|
27
|
-
|
|
217
|
+
assert form.validate(
|
|
218
|
+
username: "Helloween",
|
|
219
|
+
email: "yep",
|
|
220
|
+
starts_at: "01/01/2000 - 11:00",
|
|
221
|
+
active: "true",
|
|
222
|
+
confirm_password: "pA55w0rd"
|
|
223
|
+
)
|
|
224
|
+
assert form.active
|
|
225
|
+
assert_equal "{}", form.errors.messages.inspect
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
it "invalid" do
|
|
229
|
+
assert_equal form.validate(
|
|
230
|
+
username: "Helloween",
|
|
231
|
+
email: "yep",
|
|
232
|
+
active: "1",
|
|
233
|
+
starts_at: "01/01/2000 - 11:00",
|
|
234
|
+
color: "purple"
|
|
235
|
+
), false
|
|
236
|
+
assert form.active
|
|
237
|
+
assert_equal form.errors.messages.inspect, "{:confirm_password=>[\"must be filled\"], :color=>[\"must be one of: red orange green\"]}"
|
|
28
238
|
end
|
|
29
239
|
end
|
|
30
240
|
|
|
31
241
|
class ValidationGroupsTest < MiniTest::Spec
|
|
32
242
|
describe "basic validations" do
|
|
33
|
-
Session = Struct.new(:username, :email, :password, :confirm_password)
|
|
34
|
-
|
|
35
|
-
class SessionForm < Reform::Form
|
|
36
|
-
include Reform::Form::Dry::Validations
|
|
243
|
+
Session = Struct.new(:username, :email, :password, :confirm_password, :special_class)
|
|
244
|
+
SomeClass = Struct.new(:id)
|
|
37
245
|
|
|
246
|
+
class SessionForm < TestForm
|
|
38
247
|
property :username
|
|
39
248
|
property :email
|
|
40
249
|
property :password
|
|
41
250
|
property :confirm_password
|
|
251
|
+
property :special_class
|
|
42
252
|
|
|
43
|
-
validation
|
|
44
|
-
|
|
45
|
-
|
|
253
|
+
validation do
|
|
254
|
+
params do
|
|
255
|
+
required(:username).filled
|
|
256
|
+
required(:email).filled
|
|
257
|
+
required(:special_class).filled(type?: SomeClass)
|
|
258
|
+
end
|
|
46
259
|
end
|
|
47
260
|
|
|
48
|
-
validation :email, if: :default do
|
|
49
|
-
|
|
261
|
+
validation name: :email, if: :default do
|
|
262
|
+
params { required(:email).filled(min_size?: 3) }
|
|
50
263
|
end
|
|
51
264
|
|
|
52
|
-
validation :
|
|
53
|
-
|
|
265
|
+
validation name: :password, if: :email do
|
|
266
|
+
params { required(:password).filled(min_size?: 2) }
|
|
54
267
|
end
|
|
55
268
|
|
|
56
|
-
validation :confirm, if: :default, after: :email do
|
|
57
|
-
|
|
269
|
+
validation name: :confirm, if: :default, after: :email do
|
|
270
|
+
params { required(:confirm_password).filled(min_size?: 2) }
|
|
58
271
|
end
|
|
59
272
|
end
|
|
60
273
|
|
|
61
|
-
let
|
|
274
|
+
let(:form) { SessionForm.new(Session.new) }
|
|
62
275
|
|
|
63
276
|
# valid.
|
|
64
277
|
it do
|
|
65
|
-
form.validate(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
278
|
+
assert form.validate(
|
|
279
|
+
username: "Helloween",
|
|
280
|
+
special_class: SomeClass.new(id: 15),
|
|
281
|
+
email: "yep",
|
|
282
|
+
password: "99",
|
|
283
|
+
confirm_password: "99"
|
|
284
|
+
)
|
|
285
|
+
assert_equal form.errors.messages.inspect, "{}"
|
|
70
286
|
end
|
|
71
287
|
|
|
72
288
|
# invalid.
|
|
73
289
|
it do
|
|
74
|
-
form.validate({})
|
|
75
|
-
form.errors.messages
|
|
290
|
+
assert_equal form.validate({}), false
|
|
291
|
+
assert_equal form.errors.messages, username: ["must be filled"], email: ["must be filled"], special_class: ["must be filled", "must be ValidationGroupsTest::SomeClass"]
|
|
76
292
|
end
|
|
77
293
|
|
|
78
294
|
# partially invalid.
|
|
79
295
|
# 2nd group fails.
|
|
80
296
|
it do
|
|
81
|
-
form.validate(username: "Helloween", email: "yo", confirm_password:"9"
|
|
82
|
-
form.errors.messages.inspect
|
|
297
|
+
assert_equal form.validate(username: "Helloween", email: "yo", confirm_password: "9", special_class: SomeClass.new(id: 15)), false
|
|
298
|
+
assert_equal form.errors.messages.inspect, "{:email=>[\"size cannot be less than 3\"], :confirm_password=>[\"size cannot be less than 2\"]}"
|
|
83
299
|
end
|
|
84
300
|
# 3rd group fails.
|
|
85
301
|
it do
|
|
86
|
-
form.validate(username: "Helloween", email: "yo!", confirm_password:"9"
|
|
87
|
-
form.errors.messages.inspect
|
|
88
|
-
.must_equal "{:confirm_password=>[\"size cannot be less than 2\"], :password=>[\"is missing\", \"size cannot be less than 2\"]}"
|
|
302
|
+
assert_equal form.validate(username: "Helloween", email: "yo!", confirm_password: "9", special_class: SomeClass.new(id: 15)), false
|
|
303
|
+
assert_equal form.errors.messages.inspect, "{:confirm_password=>[\"size cannot be less than 2\"], :password=>[\"must be filled\", \"size cannot be less than 2\"]}"
|
|
89
304
|
end
|
|
90
305
|
# 4th group with after: fails.
|
|
91
306
|
it do
|
|
92
|
-
form.validate(username: "Helloween", email: "yo!", password: "", confirm_password: "9"
|
|
93
|
-
form.errors.messages.inspect
|
|
307
|
+
assert_equal form.validate(username: "Helloween", email: "yo!", password: "1", confirm_password: "9", special_class: SomeClass.new(id: 15)), false
|
|
308
|
+
assert_equal form.errors.messages.inspect, "{:confirm_password=>[\"size cannot be less than 2\"], :password=>[\"size cannot be less than 2\"]}"
|
|
94
309
|
end
|
|
95
310
|
end
|
|
96
311
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
312
|
+
class ValidationWithOptionsTest < MiniTest::Spec
|
|
313
|
+
describe "basic validations" do
|
|
314
|
+
Session = Struct.new(:username)
|
|
315
|
+
class SessionForm < TestForm
|
|
316
|
+
property :username
|
|
317
|
+
|
|
318
|
+
validation name: :default, with: {user: OpenStruct.new(name: "Nick")} do
|
|
319
|
+
option :user
|
|
320
|
+
params do
|
|
321
|
+
required(:username).filled
|
|
322
|
+
end
|
|
323
|
+
rule(:username) do
|
|
324
|
+
key.failure("must be equal to #{user.name}") unless user.name == value
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
let(:form) { SessionForm.new(Session.new) }
|
|
100
330
|
|
|
331
|
+
# valid.
|
|
332
|
+
it do
|
|
333
|
+
assert form.validate(username: "Nick")
|
|
334
|
+
assert_equal form.errors.messages.inspect, "{}"
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# invalid.
|
|
338
|
+
it do
|
|
339
|
+
assert_equal form.validate(username: "Fred"), false
|
|
340
|
+
assert_equal form.errors.messages.inspect, "{:username=>[\"must be equal to Nick\"]}"
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
#---
|
|
346
|
+
describe "with custom schema" do
|
|
347
|
+
Session2 = Struct.new(:username, :email, :password)
|
|
348
|
+
|
|
349
|
+
MyContract = Dry::Schema.Params do
|
|
350
|
+
config.messages.load_paths << "test/fixtures/dry_error_messages.yml"
|
|
351
|
+
|
|
352
|
+
required(:password).filled(min_size?: 6)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
class Session2Form < TestForm
|
|
356
|
+
property :username
|
|
357
|
+
property :email
|
|
358
|
+
property :password
|
|
359
|
+
|
|
360
|
+
validation contract: MyContract do
|
|
361
|
+
params do
|
|
362
|
+
required(:username).filled
|
|
363
|
+
required(:email).filled
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
rule(:email) do
|
|
367
|
+
key.failure(:good_musical_taste?) unless value.is_a? String
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
let(:form) { Session2Form.new(Session2.new) }
|
|
373
|
+
|
|
374
|
+
# valid.
|
|
375
|
+
it do
|
|
376
|
+
skip "waiting dry-v to add this as feature https://github.com/dry-rb/dry-schema/issues/33"
|
|
377
|
+
assert form.validate(username: "Helloween", email: "yep", password: "extrasafe")
|
|
378
|
+
assert_equal form.errors.messages.inspect, "{}"
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# invalid.
|
|
382
|
+
it do
|
|
383
|
+
skip "waiting dry-v to add this as feature https://github.com/dry-rb/dry-schema/issues/33"
|
|
384
|
+
assert_equal form.validate({}), false
|
|
385
|
+
assert_equal form.errors.messages, password: ["must be filled", "size cannot be less than 6"], username: ["must be filled"], email: ["must be filled", "you're a bad person"]
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
it do
|
|
389
|
+
skip "waiting dry-v to add this as feature https://github.com/dry-rb/dry-schema/issues/33"
|
|
390
|
+
assert_equal form.validate(email: 1), false
|
|
391
|
+
assert_equal form.errors.messages.inspect, "{:password=>[\"must be filled\", \"size cannot be less than 6\"], :username=>[\"must be filled\"], :email=>[\"you're a bad person\"]}"
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
describe "MIXED nested validations" do
|
|
396
|
+
class AlbumForm < TestForm
|
|
101
397
|
property :title
|
|
102
398
|
|
|
103
399
|
property :hit do
|
|
104
400
|
property :title
|
|
105
401
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
# key(:title, &:filled?)
|
|
110
|
-
# end
|
|
402
|
+
validation do
|
|
403
|
+
params { required(:title).filled }
|
|
404
|
+
end
|
|
111
405
|
end
|
|
112
406
|
|
|
113
407
|
collection :songs do
|
|
114
408
|
property :title
|
|
409
|
+
|
|
410
|
+
validation do
|
|
411
|
+
params { required(:title).filled }
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
# we test this one by running an each / schema dry-v check on the main block
|
|
416
|
+
collection :producers do
|
|
417
|
+
property :name
|
|
115
418
|
end
|
|
116
419
|
|
|
117
420
|
property :band do
|
|
118
421
|
property :name
|
|
119
422
|
property :label do
|
|
120
|
-
property :
|
|
423
|
+
property :location
|
|
121
424
|
end
|
|
122
425
|
end
|
|
123
426
|
|
|
124
|
-
validation
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
427
|
+
validation do
|
|
428
|
+
config.messages.load_paths << "test/fixtures/dry_error_messages.yml"
|
|
429
|
+
params do
|
|
430
|
+
required(:title).filled
|
|
431
|
+
required(:band).hash do
|
|
432
|
+
required(:name).filled
|
|
433
|
+
required(:label).hash do
|
|
434
|
+
required(:location).filled
|
|
435
|
+
end
|
|
132
436
|
end
|
|
133
|
-
end
|
|
134
437
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
# message need to be defined on fixtures/dry_error_messages
|
|
138
|
-
# d-v expects you to define your custome messages on the .yml file
|
|
139
|
-
def good_musical_taste?(value)
|
|
140
|
-
value != 'Nickelback'
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def form_access_validation?(value)
|
|
144
|
-
form.title == 'Reform'
|
|
438
|
+
required(:producers).each do
|
|
439
|
+
hash { required(:name).filled }
|
|
145
440
|
end
|
|
146
441
|
end
|
|
147
442
|
|
|
148
|
-
|
|
149
|
-
|
|
443
|
+
rule(:title) do
|
|
444
|
+
key.failure(:good_musical_taste?) unless value != "Nickelback"
|
|
445
|
+
end
|
|
150
446
|
end
|
|
151
447
|
end
|
|
152
448
|
|
|
153
|
-
let
|
|
449
|
+
let(:album) do
|
|
154
450
|
OpenStruct.new(
|
|
155
|
-
:
|
|
156
|
-
:
|
|
157
|
-
:
|
|
158
|
-
:
|
|
451
|
+
hit: OpenStruct.new,
|
|
452
|
+
songs: [OpenStruct.new, OpenStruct.new],
|
|
453
|
+
band: Struct.new(:name, :label).new("", OpenStruct.new),
|
|
454
|
+
producers: [OpenStruct.new, OpenStruct.new, OpenStruct.new],
|
|
159
455
|
)
|
|
160
456
|
end
|
|
161
|
-
let (:song) { OpenStruct.new(:title => "Downtown") }
|
|
162
|
-
let (:songs) { [ song = OpenStruct.new(:title => "Calling"), song ] }
|
|
163
|
-
let (:form) { AlbumForm.new(album) }
|
|
164
457
|
|
|
165
|
-
|
|
166
|
-
|
|
458
|
+
let(:form) { AlbumForm.new(album) }
|
|
459
|
+
|
|
460
|
+
it "maps errors to form objects correctly" do
|
|
167
461
|
result = form.validate(
|
|
168
|
-
"title" => "
|
|
169
|
-
"songs" => [
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
],
|
|
173
|
-
"band" => {"label" => {"name" => "Epitaph"}},
|
|
462
|
+
"title" => "Nickelback",
|
|
463
|
+
"songs" => [{"title" => ""}, {"title" => ""}],
|
|
464
|
+
"band" => {"size" => "", "label" => {"location" => ""}},
|
|
465
|
+
"producers" => [{"name" => ""}, {"name" => "something lovely"}]
|
|
174
466
|
)
|
|
175
467
|
|
|
176
|
-
result
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
end
|
|
468
|
+
assert_equal result, false
|
|
469
|
+
# from nested validation
|
|
470
|
+
assert_equal form.errors.messages, title: ["you're a bad person"], "hit.title": ["must be filled"], "songs.title": ["must be filled"], "producers.name": ["must be filled"], "band.name": ["must be filled"], "band.label.location": ["must be filled"]
|
|
180
471
|
|
|
472
|
+
# songs have their own validation.
|
|
473
|
+
assert_equal form.songs[0].errors.messages, title: ["must be filled"]
|
|
474
|
+
# hit got its own validation group.
|
|
475
|
+
assert_equal form.hit.errors.messages, title: ["must be filled"]
|
|
181
476
|
|
|
182
|
-
|
|
477
|
+
assert_equal form.band.label.errors.messages, location: ["must be filled"]
|
|
478
|
+
assert_equal form.band.errors.messages, name: ["must be filled"], "label.location": ["must be filled"]
|
|
479
|
+
assert_equal form.producers[0].errors.messages, name: ["must be filled"]
|
|
183
480
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
481
|
+
# TODO: use the same form structure as the top one and do the same test against messages, errors and hints.
|
|
482
|
+
assert_equal form.producers[0].to_result.errors, name: ["must be filled"]
|
|
483
|
+
assert_equal form.producers[0].to_result.messages, name: ["must be filled"]
|
|
484
|
+
assert_equal form.producers[0].to_result.hints, {}
|
|
485
|
+
end
|
|
188
486
|
|
|
189
|
-
|
|
487
|
+
# FIXME: fix the "must be filled error"
|
|
190
488
|
|
|
191
|
-
|
|
192
|
-
|
|
489
|
+
it "renders full messages correctly" do
|
|
490
|
+
result = form.validate(
|
|
491
|
+
"title" => "",
|
|
492
|
+
"songs" => [{"title" => ""}, {"title" => ""}],
|
|
493
|
+
"band" => {"size" => "", "label" => {"name" => ""}},
|
|
494
|
+
"producers" => [{"name" => ""}, {"name" => ""}, {"name" => "something lovely"}]
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
assert_equal result, false
|
|
498
|
+
assert_equal form.band.errors.full_messages, ["Name must be filled", "Label Location must be filled"]
|
|
499
|
+
assert_equal form.band.label.errors.full_messages, ["Location must be filled"]
|
|
500
|
+
assert_equal form.producers.first.errors.full_messages, ["Name must be filled"]
|
|
501
|
+
assert_equal form.errors.full_messages, ["Title must be filled", "Hit Title must be filled", "Songs Title must be filled", "Producers Name must be filled", "Band Name must be filled", "Band Label Location must be filled"]
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
describe "only 1 nested validation" do
|
|
505
|
+
class AlbumFormWith1NestedVal < TestForm
|
|
506
|
+
property :title
|
|
507
|
+
property :band do
|
|
508
|
+
property :name
|
|
509
|
+
property :label do
|
|
510
|
+
property :location
|
|
193
511
|
end
|
|
194
512
|
end
|
|
195
|
-
end.must_raise(NoMethodError)
|
|
196
|
-
# e.message.must_equal 'validates() is not supported by Dry Validation backend.'
|
|
197
513
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
include Reform::Form::Dry::Validations
|
|
514
|
+
validation do
|
|
515
|
+
config.messages.load_paths << "test/fixtures/dry_error_messages.yml"
|
|
201
516
|
|
|
202
|
-
|
|
517
|
+
params do
|
|
518
|
+
required(:title).filled
|
|
203
519
|
|
|
204
|
-
|
|
205
|
-
|
|
520
|
+
required(:band).schema do
|
|
521
|
+
required(:name).filled
|
|
522
|
+
required(:label).schema do
|
|
523
|
+
required(:location).filled
|
|
524
|
+
end
|
|
525
|
+
end
|
|
206
526
|
end
|
|
207
527
|
end
|
|
208
|
-
end
|
|
209
|
-
# e.message.must_equal 'validate() is not supported by Dry Validation backend.'
|
|
528
|
+
end
|
|
210
529
|
|
|
211
|
-
|
|
212
|
-
class FailingForm < Reform::Form
|
|
213
|
-
include Reform::Form::Dry::Validations
|
|
530
|
+
let(:form) { AlbumFormWith1NestedVal.new(album) }
|
|
214
531
|
|
|
215
|
-
|
|
532
|
+
it "allows to access dry's result semantics per nested form" do
|
|
533
|
+
form.validate(
|
|
534
|
+
"title" => "",
|
|
535
|
+
"songs" => [{"title" => ""}, {"title" => ""}],
|
|
536
|
+
"band" => {"size" => "", "label" => {"name" => ""}},
|
|
537
|
+
"producers" => [{"name" => ""}, {"name" => ""}, {"name" => "something lovely"}]
|
|
538
|
+
)
|
|
216
539
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
540
|
+
assert_equal form.to_result.errors, title: ["must be filled"]
|
|
541
|
+
assert_equal form.band.to_result.errors, name: ["must be filled"]
|
|
542
|
+
assert_equal form.band.label.to_result.errors, location: ["must be filled"]
|
|
543
|
+
|
|
544
|
+
# with locale: "de"
|
|
545
|
+
assert_equal form.to_result.errors(locale: :de), title: ["muss abgefüllt sein"]
|
|
546
|
+
assert_equal form.band.to_result.errors(locale: :de), name: ["muss abgefüllt sein"]
|
|
547
|
+
assert_equal form.band.label.to_result.errors(locale: :de), location: ["muss abgefüllt sein"]
|
|
548
|
+
end
|
|
223
549
|
end
|
|
224
550
|
end
|
|
225
551
|
|
|
226
|
-
|
|
227
552
|
# describe "same-named group" do
|
|
228
|
-
# class OverwritingForm <
|
|
553
|
+
# class OverwritingForm < TestForm
|
|
229
554
|
# include Reform::Form::Dry::Validations
|
|
230
555
|
|
|
231
556
|
# property :username
|
|
@@ -240,7 +565,7 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
240
565
|
# end
|
|
241
566
|
# end
|
|
242
567
|
|
|
243
|
-
# let
|
|
568
|
+
# let(:form) { OverwritingForm.new(Session.new) }
|
|
244
569
|
|
|
245
570
|
# # valid.
|
|
246
571
|
# it do
|
|
@@ -254,82 +579,241 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
254
579
|
# end
|
|
255
580
|
# end
|
|
256
581
|
|
|
257
|
-
|
|
258
582
|
describe "inherit: true in same group" do
|
|
259
|
-
class InheritSameGroupForm <
|
|
260
|
-
include Reform::Form::Dry::Validations
|
|
261
|
-
|
|
583
|
+
class InheritSameGroupForm < TestForm
|
|
262
584
|
property :username
|
|
263
585
|
property :email
|
|
586
|
+
property :full_name, virtual: true
|
|
264
587
|
|
|
265
|
-
validation :
|
|
266
|
-
|
|
588
|
+
validation name: :username do
|
|
589
|
+
params do
|
|
590
|
+
required(:username).filled
|
|
591
|
+
required(:full_name).filled
|
|
592
|
+
end
|
|
267
593
|
end
|
|
268
594
|
|
|
269
|
-
validation :
|
|
270
|
-
|
|
595
|
+
validation name: :username, inherit: true do # extends the above.
|
|
596
|
+
params do
|
|
597
|
+
optional(:username).maybe(:string)
|
|
598
|
+
required(:email).filled
|
|
599
|
+
end
|
|
271
600
|
end
|
|
272
601
|
end
|
|
273
602
|
|
|
274
|
-
let
|
|
603
|
+
let(:form) { InheritSameGroupForm.new(Session.new) }
|
|
275
604
|
|
|
276
605
|
# valid.
|
|
277
606
|
it do
|
|
278
|
-
|
|
607
|
+
skip "waiting dry-v to add this as feature https://github.com/dry-rb/dry-schema/issues/33"
|
|
608
|
+
assert form.validate(email: 9)
|
|
279
609
|
end
|
|
280
610
|
|
|
281
611
|
# invalid.
|
|
282
612
|
it do
|
|
283
|
-
|
|
284
|
-
form.
|
|
613
|
+
skip "waiting dry-v to add this as feature https://github.com/dry-rb/dry-schema/issues/33"
|
|
614
|
+
assert_equal form.validate({}), false
|
|
615
|
+
assert_equal form.errors.messages, email: ["must be filled"], full_name: ["must be filled"]
|
|
285
616
|
end
|
|
286
617
|
end
|
|
287
618
|
|
|
288
|
-
|
|
289
619
|
describe "if: with lambda" do
|
|
290
|
-
class IfWithLambdaForm <
|
|
291
|
-
include Reform::Form::Dry::Validations # ::build_errors.
|
|
292
|
-
|
|
620
|
+
class IfWithLambdaForm < TestForm
|
|
293
621
|
property :username
|
|
294
622
|
property :email
|
|
295
623
|
property :password
|
|
296
624
|
|
|
297
|
-
validation :email do
|
|
298
|
-
|
|
625
|
+
validation name: :email do
|
|
626
|
+
params { required(:email).filled }
|
|
299
627
|
end
|
|
300
628
|
|
|
301
629
|
# run this is :email group is true.
|
|
302
|
-
validation :after_email, if:
|
|
303
|
-
|
|
630
|
+
validation name: :after_email, if: ->(results) { results[:email].success? } do # extends the above.
|
|
631
|
+
params { required(:username).filled }
|
|
304
632
|
end
|
|
305
633
|
|
|
306
634
|
# block gets evaled in form instance context.
|
|
307
|
-
validation :password, if:
|
|
308
|
-
|
|
635
|
+
validation name: :password, if: ->(results) { email == "john@trb.org" } do
|
|
636
|
+
params { required(:password).filled }
|
|
309
637
|
end
|
|
310
638
|
end
|
|
311
639
|
|
|
312
|
-
let
|
|
640
|
+
let(:form) { IfWithLambdaForm.new(Session.new) }
|
|
313
641
|
|
|
314
642
|
# valid.
|
|
315
643
|
it do
|
|
316
|
-
form.validate(
|
|
644
|
+
assert form.validate(username: "Strung Out", email: 9)
|
|
317
645
|
end
|
|
318
646
|
|
|
319
647
|
# invalid.
|
|
320
648
|
it do
|
|
321
|
-
form.validate(
|
|
322
|
-
form.errors.messages.inspect
|
|
649
|
+
assert_equal form.validate(email: 9), false
|
|
650
|
+
assert_equal form.errors.messages.inspect, "{:username=>[\"must be filled\"]}"
|
|
323
651
|
end
|
|
324
652
|
end
|
|
325
653
|
|
|
654
|
+
class NestedSchemaValidationTest < MiniTest::Spec
|
|
655
|
+
AddressSchema = Dry::Schema.Params do
|
|
656
|
+
required(:company).filled(:int?)
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
class OrderForm < TestForm
|
|
660
|
+
property :delivery_address do
|
|
661
|
+
property :company
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
validation do
|
|
665
|
+
params { required(:delivery_address).schema(AddressSchema) }
|
|
666
|
+
end
|
|
667
|
+
end
|
|
668
|
+
|
|
669
|
+
let(:company) { Struct.new(:company) }
|
|
670
|
+
let(:order) { Struct.new(:delivery_address) }
|
|
671
|
+
let(:form) { OrderForm.new(order.new(company.new)) }
|
|
672
|
+
|
|
673
|
+
it "has company error" do
|
|
674
|
+
assert_equal form.validate(delivery_address: {company: "not int"}), false
|
|
675
|
+
assert_equal form.errors.messages, :"delivery_address.company" => ["must be an integer"]
|
|
676
|
+
end
|
|
677
|
+
end
|
|
678
|
+
|
|
679
|
+
class NestedSchemaValidationWithFormTest < MiniTest::Spec
|
|
680
|
+
class CompanyForm < TestForm
|
|
681
|
+
property :company
|
|
682
|
+
|
|
683
|
+
validation do
|
|
684
|
+
params { required(:company).filled(:int?) }
|
|
685
|
+
end
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
class OrderFormWithForm < TestForm
|
|
689
|
+
property :delivery_address, form: CompanyForm
|
|
690
|
+
end
|
|
691
|
+
|
|
692
|
+
let(:company) { Struct.new(:company) }
|
|
693
|
+
let(:order) { Struct.new(:delivery_address) }
|
|
694
|
+
let(:form) { OrderFormWithForm.new(order.new(company.new)) }
|
|
695
|
+
|
|
696
|
+
it "has company error" do
|
|
697
|
+
assert_equal form.validate(delivery_address: {company: "not int"}), false
|
|
698
|
+
assert_equal form.errors.messages, :"delivery_address.company" => ["must be an integer"]
|
|
699
|
+
end
|
|
700
|
+
end
|
|
701
|
+
|
|
702
|
+
class CollectionPropertyWithCustomRuleTest < MiniTest::Spec
|
|
703
|
+
Artist = Struct.new(:first_name, :last_name)
|
|
704
|
+
Song = Struct.new(:title, :enabled)
|
|
705
|
+
Album = Struct.new(:title, :songs, :artist)
|
|
706
|
+
|
|
707
|
+
class AlbumForm < TestForm
|
|
708
|
+
property :title
|
|
709
|
+
|
|
710
|
+
collection :songs, virtual: true, populate_if_empty: Song do
|
|
711
|
+
property :title
|
|
712
|
+
property :enabled
|
|
713
|
+
|
|
714
|
+
validation do
|
|
715
|
+
params { required(:title).filled }
|
|
716
|
+
end
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
property :artist, populate_if_empty: Artist do
|
|
720
|
+
property :first_name
|
|
721
|
+
property :last_name
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
validation do
|
|
725
|
+
config.messages.load_paths << "test/fixtures/dry_error_messages.yml"
|
|
726
|
+
|
|
727
|
+
params do
|
|
728
|
+
required(:songs).filled
|
|
729
|
+
required(:artist).filled
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
rule(:songs) do
|
|
733
|
+
key.failure(:a_song?) unless value.any? { |el| el && el[:enabled] }
|
|
734
|
+
end
|
|
735
|
+
|
|
736
|
+
rule(:artist) do
|
|
737
|
+
key.failure(:with_last_name?) unless value[:last_name]
|
|
738
|
+
end
|
|
739
|
+
end
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
it "validates fails and shows the correct errors" do
|
|
743
|
+
form = AlbumForm.new(Album.new(nil, [], nil))
|
|
744
|
+
assert_equal form.validate(
|
|
745
|
+
"songs" => [
|
|
746
|
+
{"title" => "One", "enabled" => false},
|
|
747
|
+
{"title" => nil, "enabled" => false},
|
|
748
|
+
{"title" => "Three", "enabled" => false}
|
|
749
|
+
],
|
|
750
|
+
"artist" => {"last_name" => nil}
|
|
751
|
+
), false
|
|
752
|
+
assert_equal form.songs.size, 3
|
|
753
|
+
|
|
754
|
+
assert_equal form.errors.messages, {
|
|
755
|
+
:songs => ["must have at least one enabled song"],
|
|
756
|
+
:artist => ["must have last name"],
|
|
757
|
+
:"songs.title" => ["must be filled"]
|
|
758
|
+
}
|
|
759
|
+
end
|
|
760
|
+
end
|
|
761
|
+
|
|
762
|
+
class DryVWithSchemaAndParams < MiniTest::Spec
|
|
763
|
+
Foo = Struct.new(:age)
|
|
764
|
+
|
|
765
|
+
class ParamsForm < TestForm
|
|
766
|
+
property :age
|
|
767
|
+
|
|
768
|
+
validation do
|
|
769
|
+
params { required(:age).value(:integer) }
|
|
770
|
+
|
|
771
|
+
rule(:age) { key.failure("value exceeded") if value > 999 }
|
|
772
|
+
end
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
class SchemaForm < TestForm
|
|
776
|
+
property :age
|
|
777
|
+
|
|
778
|
+
validation do
|
|
779
|
+
schema { required(:age).value(:integer) }
|
|
780
|
+
|
|
781
|
+
rule(:age) { key.failure("value exceeded") if value > 999 }
|
|
782
|
+
end
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
it "using params" do
|
|
786
|
+
model = Foo.new
|
|
787
|
+
form = ParamsForm.new(model)
|
|
788
|
+
assert form.validate(age: "99")
|
|
789
|
+
form.sync
|
|
790
|
+
assert_equal model.age, "99"
|
|
791
|
+
|
|
792
|
+
form = ParamsForm.new(Foo.new)
|
|
793
|
+
assert_equal form.validate(age: "1000"), false
|
|
794
|
+
assert_equal form.errors.messages, age: ["value exceeded"]
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
it "using schema" do
|
|
798
|
+
model = Foo.new
|
|
799
|
+
form = SchemaForm.new(model)
|
|
800
|
+
assert_equal form.validate(age: "99"), false
|
|
801
|
+
assert form.validate(age: 99)
|
|
802
|
+
form.sync
|
|
803
|
+
assert_equal model.age, 99
|
|
804
|
+
|
|
805
|
+
form = SchemaForm.new(Foo.new)
|
|
806
|
+
assert_equal form.validate(age: 1000), false
|
|
807
|
+
assert_equal form.errors.messages, age: ["value exceeded"]
|
|
808
|
+
end
|
|
809
|
+
end
|
|
326
810
|
|
|
327
811
|
# Currenty dry-v don't support that option, it doesn't make sense
|
|
328
812
|
# I've talked to @solnic and he plans to add a "hint" feature to show
|
|
329
813
|
# more errors messages than only those that have failed.
|
|
330
814
|
#
|
|
331
815
|
# describe "multiple errors for property" do
|
|
332
|
-
# class MultipleErrorsForPropertyForm <
|
|
816
|
+
# class MultipleErrorsForPropertyForm < TestForm
|
|
333
817
|
# include Reform::Form::Dry::Validations
|
|
334
818
|
|
|
335
819
|
# property :username
|
|
@@ -341,7 +825,7 @@ class ValidationGroupsTest < MiniTest::Spec
|
|
|
341
825
|
# end
|
|
342
826
|
# end
|
|
343
827
|
|
|
344
|
-
# let
|
|
828
|
+
# let(:form) { MultipleErrorsForPropertyForm.new(Session.new) }
|
|
345
829
|
|
|
346
830
|
# # valid.
|
|
347
831
|
# it do
|