@scalar/validation 0.1.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,1071 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { coerce } from '@/coerce'
4
+ import {
5
+ any,
6
+ array,
7
+ boolean,
8
+ evaluate,
9
+ lazy,
10
+ literal,
11
+ notDefined,
12
+ nullable,
13
+ number,
14
+ object,
15
+ optional,
16
+ record,
17
+ string,
18
+ union,
19
+ } from '@/schema'
20
+
21
+ describe('any', () => {
22
+ const T = any()
23
+ it('Should upcast from string', () => {
24
+ const value = 'hello'
25
+ const result = coerce(T, value)
26
+ expect(result).toBe(value)
27
+ })
28
+ it('Should upcast from number', () => {
29
+ const value = 1
30
+ const result = coerce(T, value)
31
+ expect(result).toBe(value)
32
+ })
33
+ it('Should upcast from boolean', () => {
34
+ const value = false
35
+ const result = coerce(T, value)
36
+ expect(result).toBe(value)
37
+ })
38
+ it('Should upcast from object', () => {
39
+ const value = {}
40
+ const result = coerce(T, value)
41
+ expect(result).toBe(value)
42
+ })
43
+ it('Should upcast from array', () => {
44
+ const value = [1]
45
+ const result = coerce(T, value)
46
+ expect(result).toBe(value)
47
+ })
48
+ it('Should upcast from undefined', () => {
49
+ const value = undefined
50
+ const result = coerce(T, value)
51
+ expect(result).toBe(value)
52
+ })
53
+ it('Should upcast from null', () => {
54
+ const value = null
55
+ const result = coerce(T, value)
56
+ expect(result).toBe(value)
57
+ })
58
+ it('Should preserve', () => {
59
+ const value = { a: 1, b: 2 }
60
+ const result = coerce(T, value)
61
+ expect(result).toEqual({ a: 1, b: 2 })
62
+ })
63
+ })
64
+
65
+ describe('array', () => {
66
+ const T = array(number())
67
+ const E: number[] = []
68
+ it('Should upcast from string', () => {
69
+ const value = 'hello'
70
+ const result = coerce(T, value)
71
+ expect(result).toEqual(E)
72
+ })
73
+ it('Should upcast from number', () => {
74
+ const value = 1
75
+ const result = coerce(T, value)
76
+ expect(result).toEqual(E)
77
+ })
78
+ it('Should upcast from boolean', () => {
79
+ const value = true
80
+ const result = coerce(T, value)
81
+ expect(result).toEqual(E)
82
+ })
83
+ it('Should upcast from object', () => {
84
+ const value = {}
85
+ const result = coerce(T, value)
86
+ expect(result).toEqual(E)
87
+ })
88
+ it('Should upcast from array', () => {
89
+ const value = [1]
90
+ const result = coerce(T, value)
91
+ expect(result).toEqual([1])
92
+ })
93
+ it('Should upcast from undefined', () => {
94
+ const value = undefined
95
+ const result = coerce(T, value)
96
+ expect(result).toEqual(E)
97
+ })
98
+ it('Should upcast from null', () => {
99
+ const value = null
100
+ const result = coerce(T, value)
101
+ expect(result).toEqual(E)
102
+ })
103
+ it('Should upcast from date', () => {
104
+ const value = new Date(100)
105
+ const result = coerce(T, value)
106
+ expect(result).toEqual(E)
107
+ })
108
+ it('Should preserve', () => {
109
+ const value = [6, 7, 8]
110
+ const result = coerce(T, value)
111
+ expect(result).toEqual([6, 7, 8])
112
+ })
113
+ })
114
+
115
+ describe('boolean', () => {
116
+ const T = boolean()
117
+ const E = false
118
+ it('Should upcast from string', () => {
119
+ const value = 'hello'
120
+ const result = coerce(T, value)
121
+ expect(result).toBe(E)
122
+ })
123
+ it('Should upcast from number', () => {
124
+ const value = 0
125
+ const result = coerce(T, value)
126
+ expect(result).toBe(E)
127
+ })
128
+ it('Should upcast from boolean', () => {
129
+ const value = true
130
+ const result = coerce(T, value)
131
+ expect(result).toBe(true)
132
+ })
133
+ it('Should upcast from object', () => {
134
+ const value = {}
135
+ const result = coerce(T, value)
136
+ expect(result).toBe(E)
137
+ })
138
+ it('Should upcast from array', () => {
139
+ const value = [1]
140
+ const result = coerce(T, value)
141
+ expect(result).toBe(E)
142
+ })
143
+ it('Should upcast from undefined', () => {
144
+ const value = undefined
145
+ const result = coerce(T, value)
146
+ expect(result).toBe(E)
147
+ })
148
+ it('Should upcast from null', () => {
149
+ const value = null
150
+ const result = coerce(T, value)
151
+ expect(result).toBe(E)
152
+ })
153
+ it('Should upcast from date', () => {
154
+ const value = new Date(100)
155
+ const result = coerce(T, value)
156
+ expect(result).toBe(E)
157
+ })
158
+ it('Should preserve', () => {
159
+ const value = true
160
+ const result = coerce(T, value)
161
+ expect(result).toBe(true)
162
+ })
163
+ })
164
+
165
+ describe('literal', () => {
166
+ const T = literal('hello')
167
+ const E = 'hello'
168
+ it('Should upcast from string', () => {
169
+ const value = 'world'
170
+ const result = coerce(T, value)
171
+ expect(result).toBe(E)
172
+ })
173
+ it('Should upcast from number', () => {
174
+ const value = 1
175
+ const result = coerce(T, value)
176
+ expect(result).toBe(E)
177
+ })
178
+ it('Should upcast from boolean', () => {
179
+ const value = true
180
+ const result = coerce(T, value)
181
+ expect(result).toBe(E)
182
+ })
183
+ it('Should upcast from object', () => {
184
+ const value = {}
185
+ const result = coerce(T, value)
186
+ expect(result).toBe(E)
187
+ })
188
+ it('Should upcast from array', () => {
189
+ const value = [1]
190
+ const result = coerce(T, value)
191
+ expect(result).toBe(E)
192
+ })
193
+ it('Should upcast from undefined', () => {
194
+ const value = undefined
195
+ const result = coerce(T, value)
196
+ expect(result).toBe(E)
197
+ })
198
+ it('Should upcast from null', () => {
199
+ const value = null
200
+ const result = coerce(T, value)
201
+ expect(result).toBe(E)
202
+ })
203
+ it('Should upcast from date', () => {
204
+ const value = new Date(100)
205
+ const result = coerce(T, value)
206
+ expect(result).toBe(E)
207
+ })
208
+ it('Should preseve', () => {
209
+ const value = 'hello'
210
+ const result = coerce(T, value)
211
+ expect(result).toBe('hello')
212
+ })
213
+ })
214
+
215
+ describe('null', () => {
216
+ const T = nullable()
217
+ const E = null
218
+ it('Should upcast from string', () => {
219
+ const value = 'world'
220
+ const result = coerce(T, value)
221
+ expect(result).toBe(E)
222
+ })
223
+ it('Should upcast from number', () => {
224
+ const value = 1
225
+ const result = coerce(T, value)
226
+ expect(result).toBe(E)
227
+ })
228
+ it('Should upcast from boolean', () => {
229
+ const value = true
230
+ const result = coerce(T, value)
231
+ expect(result).toBe(E)
232
+ })
233
+ it('Should upcast from object', () => {
234
+ const value = {}
235
+ const result = coerce(T, value)
236
+ expect(result).toBe(E)
237
+ })
238
+ it('Should upcast from array', () => {
239
+ const value = [1]
240
+ const result = coerce(T, value)
241
+ expect(result).toBe(E)
242
+ })
243
+ it('Should upcast from undefined', () => {
244
+ const value = undefined
245
+ const result = coerce(T, value)
246
+ expect(result).toBe(E)
247
+ })
248
+ it('Should upcast from null', () => {
249
+ const value = null
250
+ const result = coerce(T, value)
251
+ expect(result).toBe(E)
252
+ })
253
+ it('Should upcast from date', () => {
254
+ const value = new Date(100)
255
+ const result = coerce(T, value)
256
+ expect(result).toBe(E)
257
+ })
258
+ it('Should preseve', () => {
259
+ const value = null
260
+ const result = coerce(T, value)
261
+ expect(result).toBe(null)
262
+ })
263
+ })
264
+
265
+ describe('number', () => {
266
+ const T = number()
267
+ const E = 0
268
+ it('Should upcast from string', () => {
269
+ const value = 'world'
270
+ const result = coerce(T, value)
271
+ expect(result).toBe(E)
272
+ })
273
+ it('Should upcast from number', () => {
274
+ const value = 1
275
+ const result = coerce(T, value)
276
+ expect(result).toBe(1)
277
+ })
278
+ it('Should upcast from object', () => {
279
+ const value = {}
280
+ const result = coerce(T, value)
281
+ expect(result).toBe(E)
282
+ })
283
+ it('Should upcast from array', () => {
284
+ const value = [1]
285
+ const result = coerce(T, value)
286
+ expect(result).toBe(E)
287
+ })
288
+ it('Should upcast from undefined', () => {
289
+ const value = undefined
290
+ const result = coerce(T, value)
291
+ expect(result).toBe(E)
292
+ })
293
+ it('Should upcast from null', () => {
294
+ const value = null
295
+ const result = coerce(T, value)
296
+ expect(result).toBe(E)
297
+ })
298
+ it('Should upcast from date', () => {
299
+ const value = new Date(100)
300
+ const result = coerce(T, value)
301
+ expect(result).toBe(E)
302
+ })
303
+ it('Should preseve', () => {
304
+ const value = 123
305
+ const result = coerce(T, value)
306
+ expect(result).toBe(123)
307
+ })
308
+ })
309
+
310
+ describe('object', () => {
311
+ const T = object({
312
+ a: number(),
313
+ b: number(),
314
+ c: number(),
315
+ x: number(),
316
+ y: number(),
317
+ z: number(),
318
+ })
319
+ const E = {
320
+ x: 0,
321
+ y: 0,
322
+ z: 0,
323
+ a: 0,
324
+ b: 0,
325
+ c: 0,
326
+ }
327
+ it('Should upcast from string', () => {
328
+ const value = 'hello'
329
+ const result = coerce(T, value)
330
+ expect(result).toEqual(E)
331
+ })
332
+ it('Should upcast from number', () => {
333
+ const value = E
334
+ const result = coerce(T, value)
335
+ expect(result).toEqual(E)
336
+ })
337
+ it('Should upcast from boolean', () => {
338
+ const value = true
339
+ const result = coerce(T, value)
340
+ expect(result).toEqual(E)
341
+ })
342
+ it('Should upcast from object', () => {
343
+ const value = {}
344
+ const result = coerce(T, value)
345
+ expect(result).toEqual(E)
346
+ })
347
+ it('Should upcast from array', () => {
348
+ const value = [1]
349
+ const result = coerce(T, value)
350
+ expect(result).toEqual(E)
351
+ })
352
+ it('Should upcast from undefined', () => {
353
+ const value = undefined
354
+ const result = coerce(T, value)
355
+ expect(result).toEqual(E)
356
+ })
357
+ it('Should upcast from null', () => {
358
+ const value = null
359
+ const result = coerce(T, value)
360
+ expect(result).toEqual(E)
361
+ })
362
+ it('Should upcast from date', () => {
363
+ const value = new Date(100)
364
+ const result = coerce(T, value)
365
+ expect(result).toEqual(E)
366
+ })
367
+ it('Should preserve', () => {
368
+ const value = { x: 7, y: 8, z: 9, a: 10, b: 11, c: 12 }
369
+ const result = coerce(T, value)
370
+ expect(result).toEqual({
371
+ x: 7,
372
+ y: 8,
373
+ z: 9,
374
+ a: 10,
375
+ b: 11,
376
+ c: 12,
377
+ })
378
+ })
379
+ it('Should upcast partial object with incorrect properties', () => {
380
+ const value = { x: {}, y: 8, z: 9 }
381
+ const result = coerce(T, value)
382
+ expect(result).toEqual({
383
+ x: 0,
384
+ y: 8,
385
+ z: 9,
386
+ a: 0,
387
+ b: 0,
388
+ c: 0,
389
+ })
390
+ })
391
+ it('Should upcast and preserve partial object and omit unknown properties', () => {
392
+ const value = { x: 7, y: 8, z: 9, unknown: 'foo' }
393
+ const result = coerce(T, value)
394
+ expect(result).toEqual({
395
+ x: 7,
396
+ y: 8,
397
+ z: 9,
398
+ a: 0,
399
+ b: 0,
400
+ c: 0,
401
+ })
402
+ })
403
+ it('Should upcast and remove additional properties', () => {
404
+ const result = coerce(
405
+ object({
406
+ x: number(),
407
+ y: number(),
408
+ }),
409
+ {
410
+ x: 1,
411
+ y: 2,
412
+ z: { b: 1 },
413
+ },
414
+ )
415
+ expect(result).toEqual({
416
+ x: 1,
417
+ y: 2,
418
+ })
419
+ })
420
+ })
421
+
422
+ describe('record', () => {
423
+ const T = record(
424
+ string(),
425
+ object({
426
+ x: number(),
427
+ y: number(),
428
+ z: number(),
429
+ }),
430
+ )
431
+ const E = {}
432
+ it('Should upcast from string', () => {
433
+ const value = 'hello'
434
+ const result = coerce(T, value)
435
+ expect(result).toEqual(E)
436
+ })
437
+ it('Should upcast from number', () => {
438
+ const value = E
439
+ const result = coerce(T, value)
440
+ expect(result).toEqual(E)
441
+ })
442
+ it('Should upcast from boolean', () => {
443
+ const value = true
444
+ const result = coerce(T, value)
445
+ expect(result).toEqual(E)
446
+ })
447
+ it('Should upcast from object', () => {
448
+ const value = {}
449
+ const result = coerce(T, value)
450
+ expect(result).toEqual(E)
451
+ })
452
+ it('Should upcast from array', () => {
453
+ const value = [1]
454
+ const result = coerce(T, value)
455
+ expect(result).toEqual(E)
456
+ })
457
+ it('Should upcast from undefined', () => {
458
+ const value = undefined
459
+ const result = coerce(T, value)
460
+ expect(result).toEqual(E)
461
+ })
462
+ it('Should upcast from null', () => {
463
+ const value = null
464
+ const result = coerce(T, value)
465
+ expect(result).toEqual(E)
466
+ })
467
+ it('Should upcast from date', () => {
468
+ const value = new Date(100)
469
+ const result = coerce(T, value)
470
+ expect(result).toEqual(E)
471
+ })
472
+ it('Should preserve', () => {
473
+ const value = {
474
+ a: { x: 1, y: 2, z: 3 },
475
+ b: { x: 4, y: 5, z: 6 },
476
+ }
477
+ const result = coerce(T, value)
478
+ expect(result).toEqual(value)
479
+ })
480
+ it('Should preserve and patch invalid records', () => {
481
+ const value = {
482
+ a: { x: 1, y: 2, z: 3 },
483
+ b: { x: 4, y: 5, z: {} },
484
+ c: [1, 2, 3],
485
+ d: 1,
486
+ e: { x: 1, y: 2, w: 9000 },
487
+ }
488
+ const result = coerce(T, value)
489
+ expect(result).toEqual({
490
+ a: { x: 1, y: 2, z: 3 },
491
+ b: { x: 4, y: 5, z: 0 },
492
+ c: { x: 0, y: 0, z: 0 },
493
+ d: { x: 0, y: 0, z: 0 },
494
+ e: { x: 1, y: 2, z: 0 },
495
+ })
496
+ })
497
+ })
498
+
499
+ describe('string', () => {
500
+ const T = string()
501
+ const E = ''
502
+ it('Should upcast from string', () => {
503
+ const value = 'hello'
504
+ const result = coerce(T, value)
505
+ expect(result).toBe('hello')
506
+ })
507
+ it('Should upcast from object', () => {
508
+ const value = {}
509
+ const result = coerce(T, value)
510
+ expect(result).toBe(E)
511
+ })
512
+ it('Should upcast from array', () => {
513
+ const value = [1]
514
+ const result = coerce(T, value)
515
+ expect(result).toBe(E)
516
+ })
517
+ it('Should upcast from undefined', () => {
518
+ const value = undefined
519
+ const result = coerce(T, value)
520
+ expect(result).toBe(E)
521
+ })
522
+ it('Should upcast from null', () => {
523
+ const value = null
524
+ const result = coerce(T, value)
525
+ expect(result).toBe(E)
526
+ })
527
+ it('Should upcast from date', () => {
528
+ const value = new Date(100)
529
+ const result = coerce(T, value)
530
+ expect(result).toBe(E)
531
+ })
532
+ it('Should preserve', () => {
533
+ const value = 'foo'
534
+ const result = coerce(T, value)
535
+ expect(result).toBe(value)
536
+ })
537
+ })
538
+
539
+ describe('union', () => {
540
+ const A = object({
541
+ type: literal('A'),
542
+ x: number(),
543
+ y: number(),
544
+ z: number(),
545
+ })
546
+ const B = object({
547
+ type: literal('B'),
548
+ a: string(),
549
+ b: string(),
550
+ c: string(),
551
+ })
552
+ const T = union([A, B])
553
+ const E = {
554
+ type: 'A',
555
+ x: 0,
556
+ y: 0,
557
+ z: 0,
558
+ }
559
+ it('Should upcast from string', () => {
560
+ const value = 'hello'
561
+ const result = coerce(T, value)
562
+ expect(result).toEqual(E)
563
+ })
564
+ it('Should upcast from number', () => {
565
+ const value = 1
566
+ const result = coerce(T, value)
567
+ expect(result).toEqual(E)
568
+ })
569
+ it('Should upcast from boolean', () => {
570
+ const value = true
571
+ const result = coerce(T, value)
572
+ expect(result).toEqual(E)
573
+ })
574
+ it('Should upcast from object', () => {
575
+ const value = {}
576
+ const result = coerce(T, value)
577
+ expect(result).toEqual(E)
578
+ })
579
+ it('Should upcast from array', () => {
580
+ const value = [1]
581
+ const result = coerce(T, value)
582
+ expect(result).toEqual(E)
583
+ })
584
+ it('Should upcast from undefined', () => {
585
+ const value = undefined
586
+ const result = coerce(T, value)
587
+ expect(result).toEqual(E)
588
+ })
589
+ it('Should upcast from null', () => {
590
+ const value = null
591
+ const result = coerce(T, value)
592
+ expect(result).toEqual(E)
593
+ })
594
+ it('Should upcast from date', () => {
595
+ const value = new Date(100)
596
+ const result = coerce(T, value)
597
+ expect(result).toEqual(E)
598
+ })
599
+ it('Should preserve A', () => {
600
+ const value = { type: 'A', x: 1, y: 2, z: 3 }
601
+ const result = coerce(T, value)
602
+ expect(result).toEqual(value)
603
+ })
604
+ it('Should preserve B', () => {
605
+ const value = { type: 'B', a: 'a', b: 'b', c: 'c' }
606
+ const result = coerce(T, value)
607
+ expect(result).toEqual(value)
608
+ })
609
+ it('Should infer through heuristics #1', () => {
610
+ const value = { type: 'A', a: 'a', b: 'b', c: 'c' }
611
+ const result = coerce(T, value)
612
+ expect(result).toEqual({ type: 'A', x: 0, y: 0, z: 0 })
613
+ })
614
+ it('Should infer through heuristics #2', () => {
615
+ const value = { type: 'B', x: 1, y: 2, z: 3 }
616
+ const result = coerce(T, value)
617
+ expect(result).toEqual({ type: 'B', a: '', b: '', c: '' })
618
+ })
619
+ it('Should infer through heuristics #3', () => {
620
+ const value = { type: 'A', a: 'a', b: 'b', c: null }
621
+ const result = coerce(T, value)
622
+ expect(result).toEqual({ type: 'A', x: 0, y: 0, z: 0 })
623
+ })
624
+ it('Should infer through heuristics #4', () => {
625
+ const value = { type: 'B', x: 1, y: 2, z: {} }
626
+ const result = coerce(T, value)
627
+ expect(result).toEqual({ type: 'B', a: '', b: '', c: '' })
628
+ })
629
+ it('Should infer through heuristics #5', () => {
630
+ const value = { type: 'B', x: 1, y: 2, z: null }
631
+ const result = coerce(T, value)
632
+ expect(result).toEqual({ type: 'B', a: '', b: '', c: '' })
633
+ })
634
+ it('Should infer through heuristics #6', () => {
635
+ const value = { x: 1 }
636
+ const result = coerce(T, value)
637
+ expect(result).toEqual({ type: 'A', x: 1, y: 0, z: 0 })
638
+ })
639
+ it('Should infer through heuristics #7', () => {
640
+ const value = { a: null } // property existing should contribute
641
+ const result = coerce(T, value)
642
+ expect(result).toEqual({ type: 'B', a: '', b: '', c: '' })
643
+ })
644
+ it('should correctly score nested union types #1', () => {
645
+ const A = union([
646
+ union([
647
+ object({
648
+ type: literal('a'),
649
+ name: string(),
650
+ in: string(),
651
+ }),
652
+ object({
653
+ type: literal('b'),
654
+ description: optional(string()),
655
+ nested: object({
656
+ a: string(),
657
+ b: optional(string()),
658
+ }),
659
+ }),
660
+ ]),
661
+ object({
662
+ $ref: string(),
663
+ description: optional(string()),
664
+ }),
665
+ ])
666
+
667
+ expect(
668
+ coerce(A, {
669
+ type: 'b',
670
+ description: 'Hello World',
671
+ nested: {
672
+ b: 'hello',
673
+ },
674
+ }),
675
+ ).toEqual({
676
+ type: 'b',
677
+ description: 'Hello World',
678
+ nested: { a: '', b: 'hello' },
679
+ })
680
+ })
681
+
682
+ it('should correctly score nested union types #2', () => {
683
+ const A = union([
684
+ union([
685
+ object({
686
+ prop1: string(),
687
+ prop2: string(),
688
+ prop3: string(),
689
+ }),
690
+ object({
691
+ prop1: string(),
692
+ prop4: string(),
693
+ prop5: string(),
694
+ }),
695
+ ]),
696
+ union([
697
+ object({
698
+ prop6: string(),
699
+ prop7: string(),
700
+ prop8: string(),
701
+ }),
702
+ object({
703
+ prop1: string(),
704
+ prop9: string(),
705
+ prop10: string(),
706
+ }),
707
+ ]),
708
+ ])
709
+
710
+ // Picks the first union variant when the score is equal
711
+ expect(
712
+ coerce(A, {
713
+ prop1: '',
714
+ }),
715
+ ).toEqual({
716
+ prop1: '',
717
+ prop2: '',
718
+ prop3: '',
719
+ })
720
+
721
+ expect(
722
+ coerce(A, {
723
+ prop1: '',
724
+ prop4: '',
725
+ }),
726
+ ).toEqual({
727
+ prop1: '',
728
+ prop4: '',
729
+ prop5: '',
730
+ })
731
+
732
+ expect(
733
+ coerce(A, {
734
+ prop6: '',
735
+ }),
736
+ ).toEqual({
737
+ prop6: '',
738
+ prop7: '',
739
+ prop8: '',
740
+ })
741
+ })
742
+
743
+ it('should correctly score nested union types #3', () => {
744
+ const A = union([
745
+ object({
746
+ prop1: string(),
747
+ prop2: string(),
748
+ prop3: string(),
749
+ }),
750
+ object({
751
+ prop4: string(),
752
+ prop5: string(),
753
+ prop6: string(),
754
+ }),
755
+ union([
756
+ object({
757
+ prop4: string(),
758
+ prop5: string(),
759
+ prop6: string(),
760
+ }),
761
+ object({
762
+ prop1: string(),
763
+ prop2: string(),
764
+ prop7: string(),
765
+ prop8: string(),
766
+ }),
767
+ ]),
768
+ ])
769
+
770
+ expect(
771
+ coerce(A, {
772
+ prop1: '',
773
+ prop2: '',
774
+ prop7: '',
775
+ }),
776
+ ).toEqual({
777
+ prop1: '',
778
+ prop2: '',
779
+ prop7: '',
780
+ prop8: '',
781
+ })
782
+ })
783
+
784
+ it('should correctly score nested union types #4', () => {
785
+ const A = union([
786
+ object({
787
+ prop1: string(),
788
+ prop2: string(),
789
+ prop3: string(),
790
+ }),
791
+ union([
792
+ object({
793
+ prop4: string(),
794
+ prop5: string(),
795
+ prop6: string(),
796
+ }),
797
+ union([
798
+ object({
799
+ prop1: string(),
800
+ prop2: string(),
801
+ prop7: string(),
802
+ prop8: string(),
803
+ }),
804
+ union([
805
+ object({
806
+ prop1: string(),
807
+ prop2: string(),
808
+ prop9: string(),
809
+ prop10: string(),
810
+ }),
811
+ object({
812
+ prop1: string(),
813
+ prop2: string(),
814
+ prop11: string(),
815
+ prop12: string(),
816
+ }),
817
+ ]),
818
+ ]),
819
+ ]),
820
+ ])
821
+
822
+ expect(
823
+ coerce(A, {
824
+ prop1: '',
825
+ prop2: '',
826
+ prop9: '',
827
+ }),
828
+ ).toEqual({
829
+ prop1: '',
830
+ prop2: '',
831
+ prop9: '',
832
+ prop10: '',
833
+ })
834
+ })
835
+
836
+ it('should correctly score object unions with shared properties #1', () => {
837
+ const schema = union([
838
+ object({
839
+ summary: optional(string()),
840
+ description: optional(string()),
841
+ parameters: optional(array(any())),
842
+ responses: optional(record(string(), any())),
843
+ requestBody: optional(any()),
844
+ }),
845
+ object({
846
+ $ref: string(),
847
+ summary: optional(string()),
848
+ }),
849
+ ])
850
+
851
+ expect(
852
+ coerce(schema, {
853
+ summary: 'Test Summary',
854
+ parameters: {},
855
+ }),
856
+ ).toEqual({
857
+ summary: 'Test Summary',
858
+ parameters: [],
859
+ })
860
+ })
861
+
862
+ it('should correctly score object unions with shared properties #2', () => {
863
+ const A = union([
864
+ object({
865
+ prop1: string(),
866
+ prop2: string(),
867
+ prop3: string(),
868
+ }),
869
+ object({
870
+ prop1: string(),
871
+ prop2: string(),
872
+ prop4: string(),
873
+ prop5: string(),
874
+ prop6: string(),
875
+ prop7: string(),
876
+ prop8: string(),
877
+ prop9: string(),
878
+ prop10: string(),
879
+ }),
880
+ ])
881
+
882
+ expect(
883
+ coerce(A, {
884
+ prop1: '',
885
+ prop2: '',
886
+ prop7: '',
887
+ }),
888
+ ).toEqual({
889
+ prop1: '',
890
+ prop2: '',
891
+ prop4: '',
892
+ prop5: '',
893
+ prop6: '',
894
+ prop7: '',
895
+ prop8: '',
896
+ prop9: '',
897
+ prop10: '',
898
+ })
899
+ })
900
+
901
+ it('should correctly score object union for objects with all optional properties', () => {
902
+ const A = union([
903
+ object({
904
+ prop1: optional(string()),
905
+ prop2: optional(string()),
906
+ prop3: optional(string()),
907
+ }),
908
+ object({
909
+ $ref: string(),
910
+ }),
911
+ ])
912
+
913
+ expect(
914
+ coerce(A, {
915
+ $ref: 'https://example.com/schema',
916
+ }),
917
+ ).toEqual({
918
+ $ref: 'https://example.com/schema',
919
+ })
920
+ })
921
+ })
922
+
923
+ describe('notDefined', () => {
924
+ const T = notDefined()
925
+ const E = undefined
926
+ it('Should upcast from string', () => {
927
+ const value = 'hello'
928
+ const result = coerce(T, value)
929
+ expect(result).toBe(E)
930
+ })
931
+ it('Should upcast from number', () => {
932
+ const value = 1
933
+ const result = coerce(T, value)
934
+ expect(result).toBe(E)
935
+ })
936
+ it('Should upcast from boolean', () => {
937
+ const value = true
938
+ const result = coerce(T, value)
939
+ expect(result).toBe(E)
940
+ })
941
+ it('Should upcast from object', () => {
942
+ const value = {}
943
+ const result = coerce(T, value)
944
+ expect(result).toBe(E)
945
+ })
946
+ it('Should upcast from array', () => {
947
+ const value = [1]
948
+ const result = coerce(T, value)
949
+ expect(result).toBe(E)
950
+ })
951
+ it('Should upcast from undefined', () => {
952
+ const value = undefined
953
+ const result = coerce(T, value)
954
+ expect(result).toBe(E)
955
+ })
956
+ it('Should upcast from null', () => {
957
+ const value = null
958
+ const result = coerce(T, value)
959
+ expect(result).toBe(E)
960
+ })
961
+ it('Should upcast from date', () => {
962
+ const value = new Date(100)
963
+ const result = coerce(T, value)
964
+ expect(result).toBe(E)
965
+ })
966
+ it('Should preserve', () => {
967
+ const value = undefined
968
+ const result = coerce(T, value)
969
+ expect(result).toBe(undefined)
970
+ })
971
+ })
972
+
973
+ describe('lazy', () => {
974
+ const T = lazy(() => object({ x: number() }))
975
+ const E = { x: 0 }
976
+ it('Should upcast from string', () => {
977
+ const value = 'hello'
978
+ const result = coerce(T, value)
979
+ expect(result).toEqual(E)
980
+ })
981
+ it('Should upcast from number', () => {
982
+ const value = 1
983
+ const result = coerce(T, value)
984
+ expect(result).toEqual(E)
985
+ })
986
+ it('Should upcast from boolean', () => {
987
+ const value = true
988
+ const result = coerce(T, value)
989
+ expect(result).toEqual(E)
990
+ })
991
+ it('Should upcast from object', () => {
992
+ const value = {}
993
+ const result = coerce(T, value)
994
+ expect(result).toEqual(E)
995
+ })
996
+ it('Should upcast from array', () => {
997
+ const value = [1]
998
+ const result = coerce(T, value)
999
+ expect(result).toEqual(E)
1000
+ })
1001
+ it('Should upcast from undefined', () => {
1002
+ const value = undefined
1003
+ const result = coerce(T, value)
1004
+ expect(result).toEqual(E)
1005
+ })
1006
+ it('Should upcast from null', () => {
1007
+ const value = null
1008
+ const result = coerce(T, value)
1009
+ expect(result).toEqual(E)
1010
+ })
1011
+ it('Should upcast from date', () => {
1012
+ const value = new Date(100)
1013
+ const result = coerce(T, value)
1014
+ expect(result).toEqual(E)
1015
+ })
1016
+ it('Should preserve', () => {
1017
+ const value = { x: 1 }
1018
+ const result = coerce(T, value)
1019
+ expect(result).toEqual(value)
1020
+ })
1021
+ })
1022
+
1023
+ describe('evaluate', () => {
1024
+ const T = evaluate((value) => value, object({ x: number() }))
1025
+ const E = { x: 0 }
1026
+ it('Should upcast from string', () => {
1027
+ const value = 'hello'
1028
+ const result = coerce(T, value)
1029
+ expect(result).toEqual(E)
1030
+ })
1031
+ it('Should upcast from number', () => {
1032
+ const value = 1
1033
+ const result = coerce(T, value)
1034
+ expect(result).toEqual(E)
1035
+ })
1036
+ it('Should upcast from boolean', () => {
1037
+ const value = true
1038
+ const result = coerce(T, value)
1039
+ expect(result).toEqual(E)
1040
+ })
1041
+ it('Should upcast from object', () => {
1042
+ const value = {}
1043
+ const result = coerce(T, value)
1044
+ expect(result).toEqual(E)
1045
+ })
1046
+ it('Should upcast from array', () => {
1047
+ const value = [1]
1048
+ const result = coerce(T, value)
1049
+ expect(result).toEqual(E)
1050
+ })
1051
+ it('Should upcast from undefined', () => {
1052
+ const value = undefined
1053
+ const result = coerce(T, value)
1054
+ expect(result).toEqual(E)
1055
+ })
1056
+ it('Should upcast from null', () => {
1057
+ const value = null
1058
+ const result = coerce(T, value)
1059
+ expect(result).toEqual(E)
1060
+ })
1061
+ it('Should upcast from date', () => {
1062
+ const value = new Date(100)
1063
+ const result = coerce(T, value)
1064
+ expect(result).toEqual(E)
1065
+ })
1066
+ it('Should preserve', () => {
1067
+ const value = { x: 1 }
1068
+ const result = coerce(T, value)
1069
+ expect(result).toEqual(value)
1070
+ })
1071
+ })