@remoteoss/json-schema-form 0.1.0-beta.0

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.
@@ -0,0 +1,799 @@
1
+ import merge from 'lodash/fp/merge';
2
+
3
+ import { createHeadlessForm } from '../createHeadlessForm';
4
+
5
+ import { JSONSchemaBuilder, mockFieldset, mockRadioInput } from './helpers';
6
+ import { mockMoneyInput } from './helpers.custom';
7
+
8
+ function friendlyError({ formErrors }) {
9
+ // destruct the formErrors directly
10
+ return formErrors;
11
+ }
12
+
13
+ export const mockNumberInput = {
14
+ title: 'Tabs',
15
+ description: 'How many open tabs do you have?',
16
+ 'x-jsf-presentation': {
17
+ inputType: 'number',
18
+ },
19
+ minimum: 5,
20
+ maximum: 30,
21
+ type: 'number',
22
+ };
23
+
24
+ export const mockNumberInputDeprecatedPresentation = {
25
+ title: 'Tabs',
26
+ description: 'How many open tabs do you have?',
27
+ presentation: {
28
+ inputType: 'number',
29
+ },
30
+ minimum: 5,
31
+ maximum: 30,
32
+ type: 'number',
33
+ };
34
+
35
+ const schemaBasic = ({ newProperties, allOf } = {}) =>
36
+ JSONSchemaBuilder()
37
+ .addInput(
38
+ merge(
39
+ {
40
+ parent_age: { ...mockNumberInput, maximum: 100 },
41
+ child_age: mockNumberInput,
42
+ },
43
+ newProperties
44
+ )
45
+ )
46
+ .setRequiredFields(['parent_age'])
47
+ .addAllOf(allOf || [])
48
+ .build();
49
+
50
+ const schemaWithConditional = ({ newProperties } = {}) =>
51
+ JSONSchemaBuilder()
52
+ .addInput(
53
+ merge(
54
+ {
55
+ is_employee: mockRadioInput,
56
+ salary: { ...mockMoneyInput, minimum: 0 },
57
+ bonus: { ...mockMoneyInput, minimum: 0 },
58
+ },
59
+ newProperties
60
+ )
61
+ )
62
+ .setRequiredFields(['is_employee', 'salary'])
63
+ .addAllOf([
64
+ {
65
+ if: {
66
+ properties: {
67
+ is_employee: {
68
+ const: 'yes',
69
+ },
70
+ },
71
+ required: ['is_employee'],
72
+ },
73
+ then: {
74
+ properties: {
75
+ salary: {
76
+ minimum: 100000, // 1000.00€
77
+ },
78
+ },
79
+ required: ['bonus'],
80
+ },
81
+ else: {
82
+ properties: {
83
+ salary: {
84
+ minimum: 0, // 0.00€
85
+ },
86
+ bonus: false,
87
+ },
88
+ },
89
+ },
90
+ ])
91
+ .build();
92
+
93
+ function validateFieldParams(fieldParams, newFieldParams) {
94
+ expect(newFieldParams).toHaveProperty('name', fieldParams.name);
95
+ expect(newFieldParams).toHaveProperty('label', fieldParams.title);
96
+ expect(newFieldParams).toHaveProperty('description', fieldParams.description);
97
+
98
+ if (fieldParams.minimum) {
99
+ expect(newFieldParams).toHaveProperty('minimum', fieldParams.minimum);
100
+ }
101
+ if (fieldParams.maximum) {
102
+ expect(newFieldParams).toHaveProperty('maximum', fieldParams.maximum);
103
+ }
104
+ }
105
+
106
+ function validateNumberParams(fieldParams, newFieldParams) {
107
+ validateFieldParams(fieldParams, newFieldParams);
108
+ expect(newFieldParams).toHaveProperty('inputType', 'number');
109
+ expect(newFieldParams).toHaveProperty('jsonType', 'number');
110
+ }
111
+
112
+ function validateMoneyParams(fieldParams, newFieldParams) {
113
+ validateFieldParams(fieldParams, newFieldParams);
114
+ expect(newFieldParams).toHaveProperty('inputType', 'money');
115
+ expect(newFieldParams).toHaveProperty('jsonType', 'integer');
116
+ }
117
+
118
+ function createScenario({ schema, config }) {
119
+ const form = createHeadlessForm(schema, config);
120
+ const validateForm = (vals) => friendlyError(form.handleValidation(vals));
121
+
122
+ return {
123
+ ...form,
124
+ validateForm,
125
+ };
126
+ }
127
+
128
+ beforeAll(() => {
129
+ jest.spyOn(console, 'warn').mockImplementation(() => {});
130
+ });
131
+
132
+ afterEach(() => {
133
+ // safety-check that every mocked validation is within the range
134
+ // eslint-disable-next-line no-console
135
+ expect(console.warn).not.toHaveBeenCalled();
136
+ });
137
+
138
+ afterAll(() => {
139
+ // eslint-disable-next-line no-console
140
+ console.warn.mockRestore();
141
+ });
142
+
143
+ describe('createHeadlessForm() - custom validations', () => {
144
+ describe('simple validation (eg maximum)', () => {
145
+ it('works as a number', () => {
146
+ const { fields, validateForm } = createScenario({
147
+ schema: schemaBasic(),
148
+ config: {
149
+ customProperties: {
150
+ child_age: {
151
+ maximum: 14,
152
+ },
153
+ },
154
+ },
155
+ });
156
+
157
+ validateNumberParams({ ...mockNumberInput, name: 'child_age', maximum: 14 }, fields[1]);
158
+
159
+ expect(validateForm({})).toEqual({
160
+ parent_age: 'Required field',
161
+ });
162
+
163
+ expect(validateForm({ parent_age: 30, child_age: 15 })).toEqual({
164
+ child_age: 'Must be smaller or equal to 14',
165
+ });
166
+
167
+ expect(validateForm({ parent_age: 30, child_age: 10 })).toBeUndefined();
168
+ });
169
+
170
+ it('works as a function', () => {
171
+ // Friendly Scenario: child_age must be smaller than parent_age.
172
+ const { fields, validateForm } = createScenario({
173
+ schema: schemaBasic(),
174
+ config: {
175
+ customProperties: {
176
+ child_age: {
177
+ maximum: (values, { maximum }) => values.parent_age || maximum,
178
+ },
179
+ },
180
+ },
181
+ });
182
+
183
+ validateNumberParams(
184
+ { ...mockNumberInput, name: 'child_age', maximum: undefined },
185
+ fields[1]
186
+ );
187
+
188
+ expect(validateForm({})).toEqual({
189
+ parent_age: 'Required field',
190
+ });
191
+
192
+ expect(validateForm({ parent_age: 25, child_age: 26 })).toEqual({
193
+ child_age: 'Must be smaller or equal to 25',
194
+ });
195
+ expect(validateForm({ parent_age: 25, child_age: 20 })).toBeUndefined();
196
+ });
197
+
198
+ it('works with minimum and maximum together', () => {
199
+ const { fields, validateForm } = createScenario({
200
+ schema: schemaBasic(),
201
+ config: {
202
+ customProperties: {
203
+ child_age: {
204
+ // dumb example: parents that are less than double the child age,
205
+ // the child must be between 20 and 29yo.
206
+ minimum: (values, { minimum }) =>
207
+ values.parent_age < values.child_age * 3 ? 20 : minimum,
208
+ maximum: (values, { maximum }) =>
209
+ values.parent_age < values.child_age * 3 ? 29 : maximum,
210
+ },
211
+ },
212
+ },
213
+ });
214
+
215
+ validateNumberParams(
216
+ { ...mockNumberInput, name: 'child_age', minimum: 5, maximum: 30 },
217
+ fields[1]
218
+ );
219
+
220
+ // Test the default validations
221
+ expect(validateForm({ parent_age: 50, child_age: 1 })).toEqual({
222
+ child_age: 'Must be greater or equal to 5',
223
+ });
224
+ expect(validateForm({ parent_age: 100, child_age: 31 })).toEqual({
225
+ child_age: 'Must be smaller or equal to 30',
226
+ });
227
+
228
+ // Test the custom validations
229
+ expect(validateForm({ parent_age: 35, child_age: 19 })).toEqual({
230
+ child_age: 'Must be greater or equal to 20',
231
+ });
232
+ expect(validateForm({ parent_age: 40, child_age: 31 })).toEqual({
233
+ child_age: 'Must be smaller or equal to 29',
234
+ });
235
+ });
236
+
237
+ it('works with negative values', () => {
238
+ const { fields, validateForm } = createScenario({
239
+ schema: schemaBasic({
240
+ newProperties: {
241
+ parent_age: {
242
+ minimum: -20,
243
+ maximum: -1,
244
+ },
245
+ },
246
+ }),
247
+ config: {
248
+ customProperties: {
249
+ parent_age: {
250
+ minimum: -15,
251
+ maximum: -5,
252
+ },
253
+ },
254
+ },
255
+ });
256
+
257
+ validateNumberParams(
258
+ { ...mockNumberInput, name: 'parent_age', minimum: -15, maximum: -5 },
259
+ fields[0]
260
+ );
261
+
262
+ expect(validateForm({})).toEqual({
263
+ parent_age: 'Required field',
264
+ });
265
+
266
+ expect(validateForm({ parent_age: -20 })).toEqual({
267
+ parent_age: 'Must be greater or equal to -15',
268
+ });
269
+
270
+ expect(validateForm({ parent_age: -4 })).toEqual({
271
+ parent_age: 'Must be smaller or equal to -5',
272
+ });
273
+
274
+ expect(validateForm({ parent_age: -10 })).toBeUndefined();
275
+ });
276
+
277
+ it('keeps original validation, given an empty validation', () => {
278
+ const { fields, validateForm } = createScenario({
279
+ schema: schemaBasic(),
280
+ config: {
281
+ customProperties: {
282
+ parent_age: {},
283
+ },
284
+ },
285
+ });
286
+
287
+ validateNumberParams({ ...mockNumberInput, name: 'parent_age', maximum: 100 }, fields[0]);
288
+
289
+ expect(validateForm({})).toEqual({
290
+ parent_age: 'Required field',
291
+ });
292
+
293
+ expect(validateForm({ parent_age: 0 })).toEqual({
294
+ parent_age: 'Must be greater or equal to 5',
295
+ });
296
+ });
297
+
298
+ it('applies validation, when original does not exist', () => {
299
+ const { fields, validateForm } = createScenario({
300
+ schema: schemaBasic({
301
+ newProperties: {
302
+ parent_age: { minimum: null, maximum: null },
303
+ },
304
+ }),
305
+ config: {
306
+ customProperties: {
307
+ parent_age: {
308
+ minimum: 1,
309
+ maximum: 20,
310
+ },
311
+ },
312
+ },
313
+ });
314
+
315
+ validateNumberParams(
316
+ { ...mockNumberInput, minimum: 1, maximum: 20, name: 'parent_age' },
317
+ fields[0]
318
+ );
319
+
320
+ expect(validateForm({})).toEqual({
321
+ parent_age: 'Required field',
322
+ });
323
+
324
+ expect(validateForm({ parent_age: 0 })).toEqual({
325
+ parent_age: 'Must be greater or equal to 1',
326
+ });
327
+
328
+ expect(validateForm({ parent_age: 21 })).toEqual({
329
+ parent_age: 'Must be smaller or equal to 20',
330
+ });
331
+ });
332
+ });
333
+
334
+ describe('in fieldsets', () => {
335
+ it('applies custom validation in nested fields', () => {
336
+ const { fields, validateForm } = createScenario({
337
+ schema: JSONSchemaBuilder()
338
+ .addInput({
339
+ animal_age: mockNumberInput,
340
+ second_gen: {
341
+ ...mockFieldset,
342
+ properties: {
343
+ cub_age: mockNumberInput,
344
+ third_gen: {
345
+ ...mockFieldset,
346
+ properties: {
347
+ grandcub_age: mockNumberInput,
348
+ },
349
+ },
350
+ },
351
+ },
352
+ })
353
+ .build(),
354
+ config: {
355
+ customProperties: {
356
+ animal_age: {
357
+ minimum: 24,
358
+ maximum: 28,
359
+ },
360
+ second_gen: {
361
+ cub_age: {
362
+ minimum: 18,
363
+ maximum: 21,
364
+ },
365
+ third_gen: {
366
+ grandcub_age: {
367
+ minimum: 10,
368
+ maximum: 15,
369
+ },
370
+ },
371
+ },
372
+ },
373
+ },
374
+ });
375
+
376
+ const [animalField, secondGenField] = fields;
377
+
378
+ // Assert custom validations
379
+ validateNumberParams(
380
+ {
381
+ ...mockNumberInput,
382
+ name: 'animal_age',
383
+ minimum: 24,
384
+ maximum: 28,
385
+ required: false,
386
+ },
387
+ animalField
388
+ );
389
+ validateNumberParams(
390
+ {
391
+ ...mockNumberInput,
392
+ name: 'cub_age',
393
+ minimum: 18,
394
+ maximum: 21,
395
+ required: false,
396
+ },
397
+ secondGenField.fields[0]
398
+ );
399
+ validateNumberParams(
400
+ {
401
+ ...mockNumberInput,
402
+ name: 'grandcub_age',
403
+ minimum: 10,
404
+ maximum: 15,
405
+ required: false,
406
+ },
407
+ secondGenField.fields[1].fields[0]
408
+ );
409
+
410
+ // Assert minimum values
411
+ expect(
412
+ validateForm({
413
+ animal_age: 1,
414
+ second_gen: {
415
+ cub_age: 1,
416
+ third_gen: {
417
+ grandcub_age: 1,
418
+ },
419
+ },
420
+ })
421
+ ).toEqual({
422
+ animal_age: 'Must be greater or equal to 24',
423
+ second_gen: {
424
+ cub_age: 'Must be greater or equal to 18',
425
+ third_gen: {
426
+ grandcub_age: 'Must be greater or equal to 10',
427
+ },
428
+ },
429
+ });
430
+
431
+ // Assert maximum values
432
+ expect(
433
+ validateForm({
434
+ animal_age: 100,
435
+ second_gen: {
436
+ cub_age: 100,
437
+ third_gen: {
438
+ grandcub_age: 100,
439
+ },
440
+ },
441
+ })
442
+ ).toEqual({
443
+ animal_age: 'Must be smaller or equal to 28',
444
+ second_gen: {
445
+ cub_age: 'Must be smaller or equal to 21',
446
+ third_gen: {
447
+ grandcub_age: 'Must be smaller or equal to 15',
448
+ },
449
+ },
450
+ });
451
+ });
452
+ });
453
+
454
+ describe('in conditional fields', () => {
455
+ const { fields, validateForm } = createScenario({
456
+ schema: schemaWithConditional(),
457
+ config: {
458
+ customProperties: {
459
+ bonus: {
460
+ maximum: (values, { maximum }) => ({
461
+ maximum: values.salary ? values.salary * 2 : maximum,
462
+ 'x-jsf-errorMessage': {
463
+ maximum: `The bonus cannot be twice of the salary ${values.salary}.`,
464
+ },
465
+ }),
466
+ },
467
+ },
468
+ },
469
+ });
470
+
471
+ it('validates conditional visible field', () => {
472
+ // bonus fieldResult
473
+ validateMoneyParams(
474
+ {
475
+ ...mockMoneyInput,
476
+ name: 'bonus',
477
+ minimum: 0,
478
+ maximum: 500000,
479
+ required: false,
480
+ },
481
+ fields[2]
482
+ );
483
+
484
+ // Basic path — the custom validation is triggered
485
+ expect(
486
+ validateForm({
487
+ is_employee: 'yes',
488
+ salary: 150000,
489
+ bonus: 310000,
490
+ })
491
+ ).toEqual({ bonus: 'The bonus cannot be twice of the salary 150000.' });
492
+
493
+ // The values are valid:
494
+ expect(
495
+ validateForm({
496
+ is_employee: 'yes',
497
+ salary: 150000,
498
+ bonus: 20000,
499
+ })
500
+ ).toBeUndefined();
501
+
502
+ expect(validateForm({ is_employee: 'yes', salary: 150000 })).toEqual({
503
+ bonus: 'Required field',
504
+ });
505
+ });
506
+
507
+ it('ignores validation to conditional hidden field', () => {
508
+ expect(
509
+ validateForm({
510
+ is_employee: 'no',
511
+ salary: 150000,
512
+ bonus: 310000,
513
+ // NOTE/Unrelated-bug: Should it throw an error saying this
514
+ // "bonus" value is not expected? the native json schema spec throw an error...
515
+ })
516
+ ).toBeUndefined();
517
+ });
518
+
519
+ it('given an out-of-range validation, logs warning', () => {
520
+ expect(
521
+ validateForm({
522
+ is_employee: 'yes',
523
+ salary: 300000,
524
+ bonus: 500100,
525
+ })
526
+ ).toEqual({
527
+ bonus: 'No more than €5000.00',
528
+ });
529
+
530
+ // eslint-disable-next-line no-console
531
+ expect(console.warn).toHaveBeenNthCalledWith(
532
+ 1,
533
+ 'Custom validation for bonus is not allowed because maximum:600000 is less strict than the original range: 0 to 500000'
534
+ );
535
+ // eslint-disable-next-line no-console
536
+ console.warn.mockClear();
537
+ });
538
+ });
539
+
540
+ // TODO: delete after migration to x-jsf-errorMessage is completed
541
+ describe('with errorMessage (deprecated)', () => {
542
+ /* NOTE: We have 3 type of errors:
543
+ - original error: (created by json-schema-form)
544
+ - errorMessage: (declared on JSON Schema)
545
+ - customValidation.errorMessage: (declared on config)
546
+ */
547
+ it('overrides original error conditionally', () => {
548
+ const { fields, validateForm } = createScenario({
549
+ schema: schemaBasic(),
550
+ config: {
551
+ customProperties: {
552
+ child_age: {
553
+ maximum: (values, { maximum }) => ({
554
+ maximum: values.parent_age || maximum,
555
+ errorMessage: {
556
+ maximum: `The child cannot be older than the parent of ${values.parent_age} yo.`,
557
+ },
558
+ }),
559
+ },
560
+ },
561
+ },
562
+ });
563
+ validateNumberParams(
564
+ {
565
+ ...mockNumberInput,
566
+ name: 'child_age',
567
+ minimum: 5,
568
+ maximum: 30,
569
+ },
570
+ fields[1]
571
+ );
572
+
573
+ expect(validateForm({ parent_age: 18, child_age: 4 })).toEqual({
574
+ child_age: 'Must be greater or equal to 5', // applies the original error message
575
+ });
576
+ expect(validateForm({ parent_age: 18, child_age: 19 })).toEqual({
577
+ child_age: 'The child cannot be older than the parent of 18 yo.', // applies the config.errorMessage
578
+ });
579
+ });
580
+
581
+ it('overrides errorMessage conditionally', () => {
582
+ const { fields, validateForm } = createScenario({
583
+ schema: schemaBasic({
584
+ newProperties: {
585
+ parent_age: {
586
+ maximum: 100,
587
+ },
588
+ child_age: {
589
+ maximum: 40,
590
+ errorMessage: {
591
+ maximum: 'The child cannot be older than 40yo.',
592
+ },
593
+ },
594
+ },
595
+ }),
596
+ config: {
597
+ customProperties: {
598
+ child_age: {
599
+ minimum: (values, { maximum }) => {
600
+ const minimumAge = values.parent_age / 2;
601
+ if (
602
+ maximum > minimumAge && // prevent invalid out-of-range maximum
603
+ values.parent_age > values.child_age * 2 // parent is 2x as big as child age
604
+ ) {
605
+ return {
606
+ minimum: minimumAge,
607
+ errorMessage: {
608
+ minimum: `The child cannot be younger than half of the parent. Must be at least ${minimumAge}yo.`,
609
+ },
610
+ };
611
+ }
612
+
613
+ return null;
614
+ },
615
+ },
616
+ },
617
+ },
618
+ });
619
+ validateNumberParams(
620
+ {
621
+ ...mockNumberInput,
622
+ name: 'child_age',
623
+ minimum: 5,
624
+ maximum: 40,
625
+ },
626
+ fields[1]
627
+ );
628
+
629
+ // applies the errorMessage by default
630
+ expect(validateForm({ parent_age: 50, child_age: 45 })).toEqual({
631
+ child_age: 'The child cannot be older than 40yo.',
632
+ });
633
+ // applies the config.errorMessage if it's triggered
634
+ expect(validateForm({ parent_age: 50, child_age: 10 })).toEqual({
635
+ child_age: `The child cannot be younger than half of the parent. Must be at least 25yo.`,
636
+ });
637
+ });
638
+ });
639
+
640
+ describe('with x-jsf-errorMessage', () => {
641
+ /* NOTE: We have 3 type of errors:
642
+ - original error: (created by json-schema-form)
643
+ - x-jsf-errorMessage: (declared on JSON Schema)
644
+ - customValidation['x-jsf-errorMessage']: (declared on options)
645
+ */
646
+ it('overrides original error conditionally', () => {
647
+ const { fields, validateForm } = createScenario({
648
+ schema: schemaBasic(),
649
+ config: {
650
+ customProperties: {
651
+ child_age: {
652
+ maximum: (values, { maximum }) => ({
653
+ maximum: values.parent_age || maximum,
654
+ 'x-jsf-errorMessage': {
655
+ maximum: `The child cannot be older than the parent of ${values.parent_age} yo.`,
656
+ },
657
+ }),
658
+ },
659
+ },
660
+ },
661
+ });
662
+ validateNumberParams(
663
+ {
664
+ ...mockNumberInput,
665
+ name: 'child_age',
666
+ minimum: 5,
667
+ maximum: 30,
668
+ },
669
+ fields[1]
670
+ );
671
+
672
+ expect(validateForm({ parent_age: 18, child_age: 4 })).toEqual({
673
+ child_age: 'Must be greater or equal to 5', // applies the original error message
674
+ });
675
+ expect(validateForm({ parent_age: 18, child_age: 19 })).toEqual({
676
+ child_age: 'The child cannot be older than the parent of 18 yo.', // applies the config.errorMessage
677
+ });
678
+ });
679
+
680
+ it('overrides errorMessage conditionally', () => {
681
+ const { fields, validateForm } = createScenario({
682
+ schema: schemaBasic({
683
+ newProperties: {
684
+ parent_age: {
685
+ maximum: 100,
686
+ },
687
+ child_age: {
688
+ maximum: 40,
689
+ 'x-jsf-errorMessage': {
690
+ maximum: 'The child cannot be older than 40yo.',
691
+ },
692
+ },
693
+ },
694
+ }),
695
+ config: {
696
+ customProperties: {
697
+ child_age: {
698
+ minimum: (values, { maximum }) => {
699
+ const minimumAge = values.parent_age / 2;
700
+ if (
701
+ maximum > minimumAge && // prevent invalid out-of-range maximum
702
+ values.parent_age > values.child_age * 2 // parent is 2x as big as child age
703
+ ) {
704
+ return {
705
+ minimum: minimumAge,
706
+ 'x-jsf-errorMessage': {
707
+ minimum: `The child cannot be younger than half of the parent. Must be at least ${minimumAge}yo.`,
708
+ },
709
+ };
710
+ }
711
+
712
+ return null;
713
+ },
714
+ },
715
+ },
716
+ },
717
+ });
718
+ validateNumberParams(
719
+ {
720
+ ...mockNumberInput,
721
+ name: 'child_age',
722
+ minimum: 5,
723
+ maximum: 40,
724
+ },
725
+ fields[1]
726
+ );
727
+
728
+ // applies the errorMessage by default
729
+ expect(validateForm({ parent_age: 50, child_age: 45 })).toEqual({
730
+ child_age: 'The child cannot be older than 40yo.',
731
+ });
732
+ // applies the config.errorMessage if it's triggered
733
+ expect(validateForm({ parent_age: 50, child_age: 10 })).toEqual({
734
+ child_age: `The child cannot be younger than half of the parent. Must be at least 25yo.`,
735
+ });
736
+ });
737
+ });
738
+
739
+ describe('invalid validations', () => {
740
+ it('outside the schema range logs warning', () => {
741
+ const { fields, validateForm } = createScenario({
742
+ schema: schemaBasic(),
743
+ config: {
744
+ customProperties: {
745
+ parent_age: {
746
+ minimum: 0,
747
+ },
748
+ },
749
+ },
750
+ });
751
+
752
+ validateNumberParams(
753
+ { ...mockNumberInput, minimum: 5, maximum: 100, name: 'parent_age' },
754
+ fields[0]
755
+ );
756
+
757
+ // Keeps the default validation
758
+ expect(validateForm({ parent_age: 0 })).toEqual({
759
+ parent_age: 'Must be greater or equal to 5',
760
+ });
761
+
762
+ // eslint-disable-next-line no-console
763
+ expect(console.warn).toHaveBeenNthCalledWith(
764
+ 1,
765
+ 'Custom validation for parent_age is not allowed because minimum:0 is less strict than the original range: 5 to 100'
766
+ );
767
+ // eslint-disable-next-line no-console
768
+ console.warn.mockClear();
769
+ });
770
+
771
+ it('null or undefined ignores validation', () => {
772
+ const { fields, validateForm } = createScenario({
773
+ schema: schemaBasic(),
774
+ config: {
775
+ customProperties: {
776
+ parent_age: {
777
+ minimum: undefined,
778
+ maximum: null,
779
+ },
780
+ },
781
+ },
782
+ });
783
+
784
+ // The original validation is kept
785
+ validateNumberParams(
786
+ { ...mockNumberInput, minimum: 5, maximum: 100, name: 'parent_age' },
787
+ fields[0]
788
+ );
789
+
790
+ expect(validateForm({ parent_age: 0 })).toEqual({
791
+ parent_age: 'Must be greater or equal to 5',
792
+ });
793
+
794
+ expect(validateForm({ parent_age: 200 })).toEqual({
795
+ parent_age: 'Must be smaller or equal to 100',
796
+ });
797
+ });
798
+ });
799
+ });