reform 2.3.3 → 2.5.0

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