@hookform/resolvers 5.4.2 → 5.4.3
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.
- package/arktype/src/__tests__/__snapshots__/arktype.ts.snap +11 -11
- package/arktype/src/__tests__/arktype.ts +15 -6
- package/computed-types/src/__tests__/computed-types.ts +15 -6
- package/effect-ts/src/__tests__/effect-ts.ts +15 -6
- package/io-ts/src/__tests__/io-ts.ts +15 -6
- package/package.json +1 -1
- package/standard-schema/src/__tests__/__snapshots__/standard-schema.ts.snap +31 -0
- package/standard-schema/src/__tests__/standard-schema.ts +21 -13
- package/superstruct/dist/superstruct.d.ts +5 -0
- package/superstruct/dist/superstruct.js.map +1 -1
- package/superstruct/dist/superstruct.modern.mjs.map +1 -1
- package/superstruct/dist/superstruct.module.js.map +1 -1
- package/superstruct/dist/superstruct.umd.js.map +1 -1
- package/superstruct/src/__tests__/superstruct.ts +22 -8
- package/superstruct/src/superstruct.ts +13 -0
- package/typanion/src/__tests__/typanion.ts +8 -3
- package/typebox/src/__tests__/typebox.ts +31 -18
- package/typeschema/dist/typeschema.js +1 -1
- package/typeschema/dist/typeschema.js.map +1 -1
- package/typeschema/dist/typeschema.mjs +1 -1
- package/typeschema/dist/typeschema.modern.mjs +1 -1
- package/typeschema/dist/typeschema.modern.mjs.map +1 -1
- package/typeschema/dist/typeschema.module.js +1 -1
- package/typeschema/dist/typeschema.module.js.map +1 -1
- package/typeschema/dist/typeschema.umd.js +1 -1
- package/typeschema/dist/typeschema.umd.js.map +1 -1
- package/typeschema/src/__tests__/typeschema.ts +23 -15
- package/typeschema/src/typeschema.ts +6 -6
- package/valibot/src/__tests__/valibot.ts +15 -6
- package/vine/src/__tests__/vine.ts +15 -6
- package/yup/dist/yup.js.map +1 -1
- package/yup/dist/yup.modern.mjs.map +1 -1
- package/yup/dist/yup.module.js.map +1 -1
- package/yup/dist/yup.umd.js.map +1 -1
- package/yup/src/__tests__/yup.ts +15 -6
- package/yup/src/yup.ts +10 -2
- package/zod/dist/zod.js +1 -1
- package/zod/dist/zod.js.map +1 -1
- package/zod/dist/zod.mjs +1 -1
- package/zod/dist/zod.modern.mjs +1 -1
- package/zod/dist/zod.modern.mjs.map +1 -1
- package/zod/dist/zod.module.js +1 -1
- package/zod/dist/zod.module.js.map +1 -1
- package/zod/dist/zod.umd.js +1 -1
- package/zod/dist/zod.umd.js.map +1 -1
- package/zod/src/__tests__/__snapshots__/zod-v3.ts.snap +430 -0
- package/zod/src/__tests__/__snapshots__/zod-v4-mini.ts.snap +472 -0
- package/zod/src/__tests__/__snapshots__/zod-v4.ts.snap +434 -0
- package/zod/src/__tests__/zod-v3.ts +45 -6
- package/zod/src/__tests__/zod-v4-mini.ts +21 -11
- package/zod/src/__tests__/zod-v4.ts +47 -11
- package/zod/src/zod.ts +15 -2
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`zodResolver > should return a single error from zodResolver when validation fails 1`] = `
|
|
4
|
+
{
|
|
5
|
+
"errors": {
|
|
6
|
+
"accessToken": {
|
|
7
|
+
"message": "Invalid input: expected string, received undefined",
|
|
8
|
+
"ref": undefined,
|
|
9
|
+
"type": "invalid_type",
|
|
10
|
+
},
|
|
11
|
+
"birthYear": {
|
|
12
|
+
"message": "Invalid input: expected number, received string",
|
|
13
|
+
"ref": undefined,
|
|
14
|
+
"type": "invalid_type",
|
|
15
|
+
},
|
|
16
|
+
"dateStr": {
|
|
17
|
+
"message": "Invalid input: expected string, received undefined",
|
|
18
|
+
"ref": undefined,
|
|
19
|
+
"type": "invalid_type",
|
|
20
|
+
},
|
|
21
|
+
"email": {
|
|
22
|
+
"message": "Invalid email address",
|
|
23
|
+
"ref": {
|
|
24
|
+
"name": "email",
|
|
25
|
+
},
|
|
26
|
+
"type": "invalid_format",
|
|
27
|
+
},
|
|
28
|
+
"enabled": {
|
|
29
|
+
"message": "Invalid input: expected boolean, received undefined",
|
|
30
|
+
"ref": undefined,
|
|
31
|
+
"type": "invalid_type",
|
|
32
|
+
},
|
|
33
|
+
"like": [
|
|
34
|
+
{
|
|
35
|
+
"id": {
|
|
36
|
+
"message": "Invalid input: expected number, received string",
|
|
37
|
+
"ref": undefined,
|
|
38
|
+
"type": "invalid_type",
|
|
39
|
+
},
|
|
40
|
+
"name": {
|
|
41
|
+
"message": "Invalid input: expected string, received undefined",
|
|
42
|
+
"ref": undefined,
|
|
43
|
+
"type": "invalid_type",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
"password": {
|
|
48
|
+
"message": "One uppercase character",
|
|
49
|
+
"ref": {
|
|
50
|
+
"name": "password",
|
|
51
|
+
},
|
|
52
|
+
"type": "invalid_format",
|
|
53
|
+
},
|
|
54
|
+
"repeatPassword": {
|
|
55
|
+
"message": "Invalid input: expected string, received undefined",
|
|
56
|
+
"ref": undefined,
|
|
57
|
+
"type": "invalid_type",
|
|
58
|
+
},
|
|
59
|
+
"tags": {
|
|
60
|
+
"message": "Invalid input: expected array, received undefined",
|
|
61
|
+
"ref": undefined,
|
|
62
|
+
"type": "invalid_type",
|
|
63
|
+
},
|
|
64
|
+
"url": {
|
|
65
|
+
"message": "Custom error url",
|
|
66
|
+
"ref": undefined,
|
|
67
|
+
"type": "invalid_format",
|
|
68
|
+
},
|
|
69
|
+
"username": {
|
|
70
|
+
"message": "Invalid input: expected string, received undefined",
|
|
71
|
+
"ref": {
|
|
72
|
+
"name": "username",
|
|
73
|
+
},
|
|
74
|
+
"type": "invalid_type",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
"values": {},
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
|
|
81
|
+
exports[`zodResolver > should return a single error from zodResolver with \`mode: sync\` when validation fails 1`] = `
|
|
82
|
+
{
|
|
83
|
+
"errors": {
|
|
84
|
+
"accessToken": {
|
|
85
|
+
"message": "Invalid input: expected string, received undefined",
|
|
86
|
+
"ref": undefined,
|
|
87
|
+
"type": "invalid_type",
|
|
88
|
+
},
|
|
89
|
+
"birthYear": {
|
|
90
|
+
"message": "Invalid input: expected number, received string",
|
|
91
|
+
"ref": undefined,
|
|
92
|
+
"type": "invalid_type",
|
|
93
|
+
},
|
|
94
|
+
"dateStr": {
|
|
95
|
+
"message": "Invalid input: expected string, received undefined",
|
|
96
|
+
"ref": undefined,
|
|
97
|
+
"type": "invalid_type",
|
|
98
|
+
},
|
|
99
|
+
"email": {
|
|
100
|
+
"message": "Invalid email address",
|
|
101
|
+
"ref": {
|
|
102
|
+
"name": "email",
|
|
103
|
+
},
|
|
104
|
+
"type": "invalid_format",
|
|
105
|
+
},
|
|
106
|
+
"enabled": {
|
|
107
|
+
"message": "Invalid input: expected boolean, received undefined",
|
|
108
|
+
"ref": undefined,
|
|
109
|
+
"type": "invalid_type",
|
|
110
|
+
},
|
|
111
|
+
"like": [
|
|
112
|
+
{
|
|
113
|
+
"id": {
|
|
114
|
+
"message": "Invalid input: expected number, received string",
|
|
115
|
+
"ref": undefined,
|
|
116
|
+
"type": "invalid_type",
|
|
117
|
+
},
|
|
118
|
+
"name": {
|
|
119
|
+
"message": "Invalid input: expected string, received undefined",
|
|
120
|
+
"ref": undefined,
|
|
121
|
+
"type": "invalid_type",
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
"password": {
|
|
126
|
+
"message": "One uppercase character",
|
|
127
|
+
"ref": {
|
|
128
|
+
"name": "password",
|
|
129
|
+
},
|
|
130
|
+
"type": "invalid_format",
|
|
131
|
+
},
|
|
132
|
+
"repeatPassword": {
|
|
133
|
+
"message": "Invalid input: expected string, received undefined",
|
|
134
|
+
"ref": undefined,
|
|
135
|
+
"type": "invalid_type",
|
|
136
|
+
},
|
|
137
|
+
"tags": {
|
|
138
|
+
"message": "Invalid input: expected array, received undefined",
|
|
139
|
+
"ref": undefined,
|
|
140
|
+
"type": "invalid_type",
|
|
141
|
+
},
|
|
142
|
+
"url": {
|
|
143
|
+
"message": "Custom error url",
|
|
144
|
+
"ref": undefined,
|
|
145
|
+
"type": "invalid_format",
|
|
146
|
+
},
|
|
147
|
+
"username": {
|
|
148
|
+
"message": "Invalid input: expected string, received undefined",
|
|
149
|
+
"ref": {
|
|
150
|
+
"name": "username",
|
|
151
|
+
},
|
|
152
|
+
"type": "invalid_type",
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
"values": {},
|
|
156
|
+
}
|
|
157
|
+
`;
|
|
158
|
+
|
|
159
|
+
exports[`zodResolver > should return all the errors from zodResolver when validation fails with \`validateAllFieldCriteria\` set to true 1`] = `
|
|
160
|
+
{
|
|
161
|
+
"errors": {
|
|
162
|
+
"accessToken": {
|
|
163
|
+
"message": "Invalid input: expected string, received undefined",
|
|
164
|
+
"ref": undefined,
|
|
165
|
+
"type": "invalid_type",
|
|
166
|
+
"types": {
|
|
167
|
+
"invalid_type": [
|
|
168
|
+
"Invalid input: expected string, received undefined",
|
|
169
|
+
"Invalid input: expected number, received undefined",
|
|
170
|
+
],
|
|
171
|
+
"invalid_union": "Invalid input",
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
"birthYear": {
|
|
175
|
+
"message": "Invalid input: expected number, received string",
|
|
176
|
+
"ref": undefined,
|
|
177
|
+
"type": "invalid_type",
|
|
178
|
+
"types": {
|
|
179
|
+
"invalid_type": "Invalid input: expected number, received string",
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
"dateStr": {
|
|
183
|
+
"message": "Invalid input: expected string, received undefined",
|
|
184
|
+
"ref": undefined,
|
|
185
|
+
"type": "invalid_type",
|
|
186
|
+
"types": {
|
|
187
|
+
"invalid_type": "Invalid input: expected string, received undefined",
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
"email": {
|
|
191
|
+
"message": "Invalid email address",
|
|
192
|
+
"ref": {
|
|
193
|
+
"name": "email",
|
|
194
|
+
},
|
|
195
|
+
"type": "invalid_format",
|
|
196
|
+
"types": {
|
|
197
|
+
"invalid_format": "Invalid email address",
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
"enabled": {
|
|
201
|
+
"message": "Invalid input: expected boolean, received undefined",
|
|
202
|
+
"ref": undefined,
|
|
203
|
+
"type": "invalid_type",
|
|
204
|
+
"types": {
|
|
205
|
+
"invalid_type": "Invalid input: expected boolean, received undefined",
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
"like": [
|
|
209
|
+
{
|
|
210
|
+
"id": {
|
|
211
|
+
"message": "Invalid input: expected number, received string",
|
|
212
|
+
"ref": undefined,
|
|
213
|
+
"type": "invalid_type",
|
|
214
|
+
"types": {
|
|
215
|
+
"invalid_type": "Invalid input: expected number, received string",
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
"name": {
|
|
219
|
+
"message": "Invalid input: expected string, received undefined",
|
|
220
|
+
"ref": undefined,
|
|
221
|
+
"type": "invalid_type",
|
|
222
|
+
"types": {
|
|
223
|
+
"invalid_type": "Invalid input: expected string, received undefined",
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
],
|
|
228
|
+
"password": {
|
|
229
|
+
"message": "One uppercase character",
|
|
230
|
+
"ref": {
|
|
231
|
+
"name": "password",
|
|
232
|
+
},
|
|
233
|
+
"type": "invalid_format",
|
|
234
|
+
"types": {
|
|
235
|
+
"invalid_format": [
|
|
236
|
+
"One uppercase character",
|
|
237
|
+
"One lowercase character",
|
|
238
|
+
"One number",
|
|
239
|
+
],
|
|
240
|
+
"too_small": "Must be at least 8 characters in length",
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
"repeatPassword": {
|
|
244
|
+
"message": "Invalid input: expected string, received undefined",
|
|
245
|
+
"ref": undefined,
|
|
246
|
+
"type": "invalid_type",
|
|
247
|
+
"types": {
|
|
248
|
+
"invalid_type": "Invalid input: expected string, received undefined",
|
|
249
|
+
},
|
|
250
|
+
},
|
|
251
|
+
"tags": {
|
|
252
|
+
"message": "Invalid input: expected array, received undefined",
|
|
253
|
+
"ref": undefined,
|
|
254
|
+
"type": "invalid_type",
|
|
255
|
+
"types": {
|
|
256
|
+
"invalid_type": "Invalid input: expected array, received undefined",
|
|
257
|
+
},
|
|
258
|
+
},
|
|
259
|
+
"url": {
|
|
260
|
+
"message": "Custom error url",
|
|
261
|
+
"ref": undefined,
|
|
262
|
+
"type": "invalid_format",
|
|
263
|
+
"types": {
|
|
264
|
+
"invalid_format": "Custom error url",
|
|
265
|
+
"invalid_union": "Invalid input",
|
|
266
|
+
"invalid_value": "Invalid input: expected """,
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
"username": {
|
|
270
|
+
"message": "Invalid input: expected string, received undefined",
|
|
271
|
+
"ref": {
|
|
272
|
+
"name": "username",
|
|
273
|
+
},
|
|
274
|
+
"type": "invalid_type",
|
|
275
|
+
"types": {
|
|
276
|
+
"invalid_type": "Invalid input: expected string, received undefined",
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
"values": {},
|
|
281
|
+
}
|
|
282
|
+
`;
|
|
283
|
+
|
|
284
|
+
exports[`zodResolver > should return all the errors from zodResolver when validation fails with \`validateAllFieldCriteria\` set to true and \`mode: sync\` 1`] = `
|
|
285
|
+
{
|
|
286
|
+
"errors": {
|
|
287
|
+
"accessToken": {
|
|
288
|
+
"message": "Invalid input: expected string, received undefined",
|
|
289
|
+
"ref": undefined,
|
|
290
|
+
"type": "invalid_type",
|
|
291
|
+
"types": {
|
|
292
|
+
"invalid_type": [
|
|
293
|
+
"Invalid input: expected string, received undefined",
|
|
294
|
+
"Invalid input: expected number, received undefined",
|
|
295
|
+
],
|
|
296
|
+
"invalid_union": "Invalid input",
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
"birthYear": {
|
|
300
|
+
"message": "Invalid input: expected number, received string",
|
|
301
|
+
"ref": undefined,
|
|
302
|
+
"type": "invalid_type",
|
|
303
|
+
"types": {
|
|
304
|
+
"invalid_type": "Invalid input: expected number, received string",
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
"dateStr": {
|
|
308
|
+
"message": "Invalid input: expected string, received undefined",
|
|
309
|
+
"ref": undefined,
|
|
310
|
+
"type": "invalid_type",
|
|
311
|
+
"types": {
|
|
312
|
+
"invalid_type": "Invalid input: expected string, received undefined",
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
"email": {
|
|
316
|
+
"message": "Invalid email address",
|
|
317
|
+
"ref": {
|
|
318
|
+
"name": "email",
|
|
319
|
+
},
|
|
320
|
+
"type": "invalid_format",
|
|
321
|
+
"types": {
|
|
322
|
+
"invalid_format": "Invalid email address",
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
"enabled": {
|
|
326
|
+
"message": "Invalid input: expected boolean, received undefined",
|
|
327
|
+
"ref": undefined,
|
|
328
|
+
"type": "invalid_type",
|
|
329
|
+
"types": {
|
|
330
|
+
"invalid_type": "Invalid input: expected boolean, received undefined",
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
"like": [
|
|
334
|
+
{
|
|
335
|
+
"id": {
|
|
336
|
+
"message": "Invalid input: expected number, received string",
|
|
337
|
+
"ref": undefined,
|
|
338
|
+
"type": "invalid_type",
|
|
339
|
+
"types": {
|
|
340
|
+
"invalid_type": "Invalid input: expected number, received string",
|
|
341
|
+
},
|
|
342
|
+
},
|
|
343
|
+
"name": {
|
|
344
|
+
"message": "Invalid input: expected string, received undefined",
|
|
345
|
+
"ref": undefined,
|
|
346
|
+
"type": "invalid_type",
|
|
347
|
+
"types": {
|
|
348
|
+
"invalid_type": "Invalid input: expected string, received undefined",
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
"password": {
|
|
354
|
+
"message": "One uppercase character",
|
|
355
|
+
"ref": {
|
|
356
|
+
"name": "password",
|
|
357
|
+
},
|
|
358
|
+
"type": "invalid_format",
|
|
359
|
+
"types": {
|
|
360
|
+
"invalid_format": [
|
|
361
|
+
"One uppercase character",
|
|
362
|
+
"One lowercase character",
|
|
363
|
+
"One number",
|
|
364
|
+
],
|
|
365
|
+
"too_small": "Must be at least 8 characters in length",
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
"repeatPassword": {
|
|
369
|
+
"message": "Invalid input: expected string, received undefined",
|
|
370
|
+
"ref": undefined,
|
|
371
|
+
"type": "invalid_type",
|
|
372
|
+
"types": {
|
|
373
|
+
"invalid_type": "Invalid input: expected string, received undefined",
|
|
374
|
+
},
|
|
375
|
+
},
|
|
376
|
+
"tags": {
|
|
377
|
+
"message": "Invalid input: expected array, received undefined",
|
|
378
|
+
"ref": undefined,
|
|
379
|
+
"type": "invalid_type",
|
|
380
|
+
"types": {
|
|
381
|
+
"invalid_type": "Invalid input: expected array, received undefined",
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
"url": {
|
|
385
|
+
"message": "Custom error url",
|
|
386
|
+
"ref": undefined,
|
|
387
|
+
"type": "invalid_format",
|
|
388
|
+
"types": {
|
|
389
|
+
"invalid_format": "Custom error url",
|
|
390
|
+
"invalid_union": "Invalid input",
|
|
391
|
+
"invalid_value": "Invalid input: expected """,
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
"username": {
|
|
395
|
+
"message": "Invalid input: expected string, received undefined",
|
|
396
|
+
"ref": {
|
|
397
|
+
"name": "username",
|
|
398
|
+
},
|
|
399
|
+
"type": "invalid_type",
|
|
400
|
+
"types": {
|
|
401
|
+
"invalid_type": "Invalid input: expected string, received undefined",
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
"values": {},
|
|
406
|
+
}
|
|
407
|
+
`;
|
|
408
|
+
|
|
409
|
+
exports[`zodResolver > should return parsed values from zodResolver with \`mode: sync\` when validation pass 1`] = `
|
|
410
|
+
{
|
|
411
|
+
"errors": {},
|
|
412
|
+
"values": {
|
|
413
|
+
"accessToken": "accessToken",
|
|
414
|
+
"birthYear": 2000,
|
|
415
|
+
"dateStr": 2020-01-01T00:00:00.000Z,
|
|
416
|
+
"email": "john@doe.com",
|
|
417
|
+
"enabled": true,
|
|
418
|
+
"like": [
|
|
419
|
+
{
|
|
420
|
+
"id": 1,
|
|
421
|
+
"name": "name",
|
|
422
|
+
},
|
|
423
|
+
],
|
|
424
|
+
"password": "Password123_",
|
|
425
|
+
"repeatPassword": "Password123_",
|
|
426
|
+
"tags": [
|
|
427
|
+
"tag1",
|
|
428
|
+
"tag2",
|
|
429
|
+
],
|
|
430
|
+
"url": "https://react-hook-form.com/",
|
|
431
|
+
"username": "Doe",
|
|
432
|
+
},
|
|
433
|
+
}
|
|
434
|
+
`;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
1
2
|
import { Resolver, SubmitHandler, useForm } from 'react-hook-form';
|
|
2
3
|
import { z } from 'zod/v3';
|
|
3
4
|
import { zodResolver } from '..';
|
|
@@ -80,6 +81,36 @@ describe('zodResolver', () => {
|
|
|
80
81
|
expect(result).toMatchSnapshot();
|
|
81
82
|
});
|
|
82
83
|
|
|
84
|
+
it('should surface the error from the union member closest to matching, not just the first member', async () => {
|
|
85
|
+
const branchWithMoreIssues = z.object({
|
|
86
|
+
id: z.number({ invalid_type_error: 'id wrong (branch B)' }),
|
|
87
|
+
name: z.number({ invalid_type_error: 'name wrong (branch B)' }),
|
|
88
|
+
});
|
|
89
|
+
const branchWithFewerIssues = z.object({
|
|
90
|
+
id: z.string(),
|
|
91
|
+
name: z.number({
|
|
92
|
+
invalid_type_error: 'name wrong (branch A, closer match)',
|
|
93
|
+
}),
|
|
94
|
+
});
|
|
95
|
+
// branchWithMoreIssues is listed first, but only branchWithFewerIssues
|
|
96
|
+
// actually comes close to matching the input (it only fails on `name`).
|
|
97
|
+
const unionSchema = z.object({
|
|
98
|
+
target: z.union([branchWithMoreIssues, branchWithFewerIssues]),
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const result = await zodResolver(unionSchema)(
|
|
102
|
+
{ target: { id: 'abc', name: 'xyz' } } as unknown as z.input<
|
|
103
|
+
typeof unionSchema
|
|
104
|
+
>,
|
|
105
|
+
undefined,
|
|
106
|
+
{ fields: {}, shouldUseNativeValidation },
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
expect(result.errors).toMatchObject({
|
|
110
|
+
target: { message: 'name wrong (branch A, closer match)' },
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
83
114
|
it('should throw any error unrelated to Zod', async () => {
|
|
84
115
|
const schemaWithCustomError = schema.refine(() => {
|
|
85
116
|
throw Error('custom error');
|
|
@@ -147,9 +178,13 @@ describe('zodResolver', () => {
|
|
|
147
178
|
it('should correctly infer the output type from a Zod schema for the handleSubmit function in useForm', () => {
|
|
148
179
|
const schema = z.object({ id: z.number() });
|
|
149
180
|
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
})
|
|
181
|
+
const {
|
|
182
|
+
result: { current: form },
|
|
183
|
+
} = renderHook(() =>
|
|
184
|
+
useForm({
|
|
185
|
+
resolver: zodResolver(schema),
|
|
186
|
+
}),
|
|
187
|
+
);
|
|
153
188
|
|
|
154
189
|
expectTypeOf(form.watch('id')).toEqualTypeOf<number>();
|
|
155
190
|
|
|
@@ -163,9 +198,13 @@ describe('zodResolver', () => {
|
|
|
163
198
|
it('should correctly infer the output type from a Zod schema with a transform for the handleSubmit function in useForm', () => {
|
|
164
199
|
const schema = z.object({ id: z.number().transform((val) => String(val)) });
|
|
165
200
|
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
})
|
|
201
|
+
const {
|
|
202
|
+
result: { current: form },
|
|
203
|
+
} = renderHook(() =>
|
|
204
|
+
useForm({
|
|
205
|
+
resolver: zodResolver(schema),
|
|
206
|
+
}),
|
|
207
|
+
);
|
|
169
208
|
|
|
170
209
|
expectTypeOf(form.watch('id')).toEqualTypeOf<number>();
|
|
171
210
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
1
2
|
import { Resolver, SubmitHandler, useForm } from 'react-hook-form';
|
|
2
3
|
import { z } from 'zod/v4-mini';
|
|
4
|
+
import * as v4Core from 'zod/v4/core';
|
|
3
5
|
import { zodResolver } from '..';
|
|
4
6
|
import {
|
|
5
7
|
fields,
|
|
@@ -12,7 +14,7 @@ const shouldUseNativeValidation = false;
|
|
|
12
14
|
|
|
13
15
|
describe('zodResolver', () => {
|
|
14
16
|
it('should return values from zodResolver when validation pass & raw=true', async () => {
|
|
15
|
-
const parseAsyncSpy = vi.spyOn(
|
|
17
|
+
const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync');
|
|
16
18
|
|
|
17
19
|
const result = await zodResolver(schema, undefined, {
|
|
18
20
|
raw: true,
|
|
@@ -28,8 +30,8 @@ describe('zodResolver', () => {
|
|
|
28
30
|
});
|
|
29
31
|
|
|
30
32
|
it('should return parsed values from zodResolver with `mode: sync` when validation pass', async () => {
|
|
31
|
-
const parseSpy = vi.spyOn(
|
|
32
|
-
const parseAsyncSpy = vi.spyOn(
|
|
33
|
+
const parseSpy = vi.spyOn(v4Core, 'parse');
|
|
34
|
+
const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync');
|
|
33
35
|
|
|
34
36
|
const result = await zodResolver(schema, undefined, {
|
|
35
37
|
mode: 'sync',
|
|
@@ -50,8 +52,8 @@ describe('zodResolver', () => {
|
|
|
50
52
|
});
|
|
51
53
|
|
|
52
54
|
it('should return a single error from zodResolver with `mode: sync` when validation fails', async () => {
|
|
53
|
-
const parseSpy = vi.spyOn(
|
|
54
|
-
const parseAsyncSpy = vi.spyOn(
|
|
55
|
+
const parseSpy = vi.spyOn(v4Core, 'parse');
|
|
56
|
+
const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync');
|
|
55
57
|
|
|
56
58
|
const result = await zodResolver(schema, undefined, {
|
|
57
59
|
mode: 'sync',
|
|
@@ -146,9 +148,13 @@ describe('zodResolver', () => {
|
|
|
146
148
|
it('should correctly infer the output type from a Zod schema for the handleSubmit function in useForm', () => {
|
|
147
149
|
const schema = z.object({ id: z.number() });
|
|
148
150
|
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
})
|
|
151
|
+
const {
|
|
152
|
+
result: { current: form },
|
|
153
|
+
} = renderHook(() =>
|
|
154
|
+
useForm({
|
|
155
|
+
resolver: zodResolver(schema),
|
|
156
|
+
}),
|
|
157
|
+
);
|
|
152
158
|
|
|
153
159
|
expectTypeOf(form.watch('id')).toEqualTypeOf<number>();
|
|
154
160
|
|
|
@@ -167,9 +173,13 @@ describe('zodResolver', () => {
|
|
|
167
173
|
),
|
|
168
174
|
});
|
|
169
175
|
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
})
|
|
176
|
+
const {
|
|
177
|
+
result: { current: form },
|
|
178
|
+
} = renderHook(() =>
|
|
179
|
+
useForm({
|
|
180
|
+
resolver: zodResolver(schema),
|
|
181
|
+
}),
|
|
182
|
+
);
|
|
173
183
|
|
|
174
184
|
expectTypeOf(form.watch('id')).toEqualTypeOf<number>();
|
|
175
185
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
1
2
|
import { Resolver, SubmitHandler, useForm } from 'react-hook-form';
|
|
2
3
|
import { z } from 'zod/v4';
|
|
4
|
+
import * as v4Core from 'zod/v4/core';
|
|
3
5
|
import { zodResolver } from '..';
|
|
4
6
|
import { fields, invalidData, schema, validData } from './__fixtures__/data-v4';
|
|
5
7
|
|
|
@@ -7,7 +9,7 @@ const shouldUseNativeValidation = false;
|
|
|
7
9
|
|
|
8
10
|
describe('zodResolver', () => {
|
|
9
11
|
it('should return values from zodResolver when validation pass & raw=true', async () => {
|
|
10
|
-
const parseAsyncSpy = vi.spyOn(
|
|
12
|
+
const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync');
|
|
11
13
|
|
|
12
14
|
const result = await zodResolver(schema, undefined, {
|
|
13
15
|
raw: true,
|
|
@@ -21,8 +23,8 @@ describe('zodResolver', () => {
|
|
|
21
23
|
});
|
|
22
24
|
|
|
23
25
|
it('should return parsed values from zodResolver with `mode: sync` when validation pass', async () => {
|
|
24
|
-
const parseSpy = vi.spyOn(
|
|
25
|
-
const parseAsyncSpy = vi.spyOn(
|
|
26
|
+
const parseSpy = vi.spyOn(v4Core, 'parse');
|
|
27
|
+
const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync');
|
|
26
28
|
|
|
27
29
|
const result = await zodResolver(schema, undefined, {
|
|
28
30
|
mode: 'sync',
|
|
@@ -44,8 +46,8 @@ describe('zodResolver', () => {
|
|
|
44
46
|
});
|
|
45
47
|
|
|
46
48
|
it('should return a single error from zodResolver with `mode: sync` when validation fails', async () => {
|
|
47
|
-
const parseSpy = vi.spyOn(
|
|
48
|
-
const parseAsyncSpy = vi.spyOn(
|
|
49
|
+
const parseSpy = vi.spyOn(v4Core, 'parse');
|
|
50
|
+
const parseAsyncSpy = vi.spyOn(v4Core, 'parseAsync');
|
|
49
51
|
|
|
50
52
|
const result = await zodResolver(schema, undefined, {
|
|
51
53
|
mode: 'sync',
|
|
@@ -80,6 +82,32 @@ describe('zodResolver', () => {
|
|
|
80
82
|
expect(result).toMatchSnapshot();
|
|
81
83
|
});
|
|
82
84
|
|
|
85
|
+
it('should surface the error from the union member closest to matching, not just the first member', async () => {
|
|
86
|
+
const branchWithMoreIssues = z.object({
|
|
87
|
+
id: z.string().refine(() => false, { error: 'id wrong (branch B)' }),
|
|
88
|
+
name: z.string().refine(() => false, { error: 'name wrong (branch B)' }),
|
|
89
|
+
});
|
|
90
|
+
const branchWithFewerIssues = z.object({
|
|
91
|
+
id: z.string(),
|
|
92
|
+
name: z
|
|
93
|
+
.string()
|
|
94
|
+
.refine((v) => v.length >= 5, { error: 'name too short' }),
|
|
95
|
+
});
|
|
96
|
+
// branchWithMoreIssues is listed first, but only branchWithFewerIssues
|
|
97
|
+
// actually comes close to matching the input (it only fails on `name`).
|
|
98
|
+
const unionSchema = z.union([branchWithMoreIssues, branchWithFewerIssues]);
|
|
99
|
+
|
|
100
|
+
const result = await zodResolver(unionSchema)(
|
|
101
|
+
{ id: 'abc', name: 'yo' },
|
|
102
|
+
undefined,
|
|
103
|
+
{ fields: {}, shouldUseNativeValidation },
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
expect(result.errors).toMatchObject({
|
|
107
|
+
'': { message: 'name too short' },
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
83
111
|
it('should throw any error unrelated to Zod', async () => {
|
|
84
112
|
const schemaWithCustomError = schema.refine(() => {
|
|
85
113
|
throw Error('custom error');
|
|
@@ -145,9 +173,13 @@ describe('zodResolver', () => {
|
|
|
145
173
|
it('should correctly infer the output type from a Zod schema for the handleSubmit function in useForm', () => {
|
|
146
174
|
const schema = z.object({ id: z.number() });
|
|
147
175
|
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
})
|
|
176
|
+
const {
|
|
177
|
+
result: { current: form },
|
|
178
|
+
} = renderHook(() =>
|
|
179
|
+
useForm({
|
|
180
|
+
resolver: zodResolver(schema),
|
|
181
|
+
}),
|
|
182
|
+
);
|
|
151
183
|
|
|
152
184
|
expectTypeOf(form.watch('id')).toEqualTypeOf<number>();
|
|
153
185
|
|
|
@@ -161,9 +193,13 @@ describe('zodResolver', () => {
|
|
|
161
193
|
it('should correctly infer the output type from a Zod schema with a transform for the handleSubmit function in useForm', () => {
|
|
162
194
|
const schema = z.object({ id: z.number().transform((val) => String(val)) });
|
|
163
195
|
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
})
|
|
196
|
+
const {
|
|
197
|
+
result: { current: form },
|
|
198
|
+
} = renderHook(() =>
|
|
199
|
+
useForm({
|
|
200
|
+
resolver: zodResolver(schema),
|
|
201
|
+
}),
|
|
202
|
+
);
|
|
167
203
|
|
|
168
204
|
expectTypeOf(form.watch('id')).toEqualTypeOf<number>();
|
|
169
205
|
|