@tanstack/form-core 0.23.2 → 0.24.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.
- package/dist/cjs/FieldApi.cjs +6 -4
- package/dist/cjs/FieldApi.cjs.map +1 -1
- package/dist/cjs/FieldApi.d.cts +220 -2
- package/dist/cjs/FormApi.cjs +6 -0
- package/dist/cjs/FormApi.cjs.map +1 -1
- package/dist/cjs/FormApi.d.cts +228 -0
- package/dist/cjs/mergeForm.cjs.map +1 -1
- package/dist/cjs/mergeForm.d.cts +3 -0
- package/dist/cjs/types.d.cts +14 -0
- package/dist/cjs/util-types.d.cts +18 -3
- package/dist/cjs/utils.cjs.map +1 -1
- package/dist/cjs/utils.d.cts +24 -0
- package/dist/esm/FieldApi.d.ts +220 -2
- package/dist/esm/FieldApi.js +6 -4
- package/dist/esm/FieldApi.js.map +1 -1
- package/dist/esm/FormApi.d.ts +228 -0
- package/dist/esm/FormApi.js +6 -0
- package/dist/esm/FormApi.js.map +1 -1
- package/dist/esm/mergeForm.d.ts +3 -0
- package/dist/esm/mergeForm.js.map +1 -1
- package/dist/esm/types.d.ts +14 -0
- package/dist/esm/util-types.d.ts +18 -3
- package/dist/esm/utils.d.ts +24 -0
- package/dist/esm/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/FieldApi.ts +222 -9
- package/src/FormApi.ts +228 -12
- package/src/mergeForm.ts +3 -0
- package/src/types.ts +14 -2
- package/src/util-types.ts +18 -4
- package/src/utils.ts +24 -0
- package/src/tests/FieldApi.spec.ts +0 -1184
- package/src/tests/FieldApi.test-d.ts +0 -149
- package/src/tests/FormApi.spec.ts +0 -1523
- package/src/tests/formOptions.test.ts +0 -25
- package/src/tests/mutateMergeDeep.spec.ts +0 -32
- package/src/tests/util-types.test-d.ts +0 -171
- package/src/tests/utils.spec.ts +0 -131
- package/src/tests/utils.ts +0 -5
|
@@ -1,1184 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from 'vitest'
|
|
2
|
-
|
|
3
|
-
import { FormApi } from '../FormApi'
|
|
4
|
-
import { FieldApi } from '../FieldApi'
|
|
5
|
-
import { sleep } from './utils'
|
|
6
|
-
|
|
7
|
-
describe('field api', () => {
|
|
8
|
-
it('should have an initial value', () => {
|
|
9
|
-
const form = new FormApi({
|
|
10
|
-
defaultValues: {
|
|
11
|
-
name: 'test',
|
|
12
|
-
},
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
const field = new FieldApi({
|
|
16
|
-
form,
|
|
17
|
-
name: 'name',
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
expect(field.getValue()).toBe('test')
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
it('should use field default value first', () => {
|
|
24
|
-
const form = new FormApi({
|
|
25
|
-
defaultValues: {
|
|
26
|
-
name: 'test',
|
|
27
|
-
},
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
const field = new FieldApi({
|
|
31
|
-
form,
|
|
32
|
-
defaultValue: 'other',
|
|
33
|
-
name: 'name',
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
expect(field.getValue()).toBe('other')
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('should get default meta', () => {
|
|
40
|
-
const form = new FormApi()
|
|
41
|
-
const field = new FieldApi({
|
|
42
|
-
form,
|
|
43
|
-
name: 'name',
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
expect(field.getMeta()).toEqual({
|
|
47
|
-
isTouched: false,
|
|
48
|
-
isValidating: false,
|
|
49
|
-
isPristine: true,
|
|
50
|
-
isDirty: false,
|
|
51
|
-
touchedErrors: [],
|
|
52
|
-
errors: [],
|
|
53
|
-
errorMap: {},
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('should allow to set default meta', () => {
|
|
58
|
-
const form = new FormApi()
|
|
59
|
-
const field = new FieldApi({
|
|
60
|
-
form,
|
|
61
|
-
name: 'name',
|
|
62
|
-
defaultMeta: { isTouched: true, isDirty: true, isPristine: false },
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
expect(field.getMeta()).toEqual({
|
|
66
|
-
isTouched: true,
|
|
67
|
-
isValidating: false,
|
|
68
|
-
isDirty: true,
|
|
69
|
-
isPristine: false,
|
|
70
|
-
touchedErrors: [],
|
|
71
|
-
errors: [],
|
|
72
|
-
errorMap: {},
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
it('should set a value correctly', () => {
|
|
77
|
-
const form = new FormApi({
|
|
78
|
-
defaultValues: {
|
|
79
|
-
name: 'test',
|
|
80
|
-
},
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
const field = new FieldApi({
|
|
84
|
-
form,
|
|
85
|
-
name: 'name',
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
field.setValue('other')
|
|
89
|
-
|
|
90
|
-
expect(field.getValue()).toBe('other')
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('should push an array value correctly', () => {
|
|
94
|
-
const form = new FormApi({
|
|
95
|
-
defaultValues: {
|
|
96
|
-
names: ['one'],
|
|
97
|
-
},
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
const field = new FieldApi({
|
|
101
|
-
form,
|
|
102
|
-
name: 'names',
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
field.pushValue('other')
|
|
106
|
-
|
|
107
|
-
expect(field.getValue()).toStrictEqual(['one', 'other'])
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
it('should run onChange validation when pushing an array fields value', async () => {
|
|
111
|
-
const form = new FormApi({
|
|
112
|
-
defaultValues: {
|
|
113
|
-
names: ['test'],
|
|
114
|
-
},
|
|
115
|
-
})
|
|
116
|
-
form.mount()
|
|
117
|
-
|
|
118
|
-
const field = new FieldApi({
|
|
119
|
-
form,
|
|
120
|
-
name: 'names',
|
|
121
|
-
validators: {
|
|
122
|
-
onChange: ({ value }) => {
|
|
123
|
-
if (value.length < 3) {
|
|
124
|
-
return 'At least 3 names are required'
|
|
125
|
-
}
|
|
126
|
-
return
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
})
|
|
130
|
-
field.mount()
|
|
131
|
-
|
|
132
|
-
field.pushValue('other')
|
|
133
|
-
|
|
134
|
-
expect(field.getMeta().errors).toStrictEqual([
|
|
135
|
-
'At least 3 names are required',
|
|
136
|
-
])
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
it('should insert a value into an array value correctly', () => {
|
|
140
|
-
const form = new FormApi({
|
|
141
|
-
defaultValues: {
|
|
142
|
-
names: ['one', 'two'],
|
|
143
|
-
},
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
const field = new FieldApi({
|
|
147
|
-
form,
|
|
148
|
-
name: 'names',
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
field.insertValue(1, 'other')
|
|
152
|
-
|
|
153
|
-
expect(field.getValue()).toStrictEqual(['one', 'other', 'two'])
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
it('should replace a value into an array correctly', () => {
|
|
157
|
-
const form = new FormApi({
|
|
158
|
-
defaultValues: {
|
|
159
|
-
names: ['one', 'two', 'three'],
|
|
160
|
-
},
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
const field = new FieldApi({
|
|
164
|
-
form,
|
|
165
|
-
name: 'names',
|
|
166
|
-
})
|
|
167
|
-
|
|
168
|
-
field.replaceValue(1, 'other')
|
|
169
|
-
|
|
170
|
-
expect(field.getValue()).toStrictEqual(['one', 'other', 'three'])
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
it('should do nothing when replacing a value into an array at an index that does not exist', () => {
|
|
174
|
-
const form = new FormApi({
|
|
175
|
-
defaultValues: {
|
|
176
|
-
names: ['one', 'two', 'three'],
|
|
177
|
-
},
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
const field = new FieldApi({
|
|
181
|
-
form,
|
|
182
|
-
name: 'names',
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
field.replaceValue(10, 'other')
|
|
186
|
-
|
|
187
|
-
expect(field.getValue()).toStrictEqual(['one', 'two', 'three'])
|
|
188
|
-
})
|
|
189
|
-
|
|
190
|
-
it('should run onChange validation when inserting an array fields value', () => {
|
|
191
|
-
const form = new FormApi({
|
|
192
|
-
defaultValues: {
|
|
193
|
-
names: ['test'],
|
|
194
|
-
},
|
|
195
|
-
})
|
|
196
|
-
form.mount()
|
|
197
|
-
|
|
198
|
-
const field = new FieldApi({
|
|
199
|
-
form,
|
|
200
|
-
name: 'names',
|
|
201
|
-
validators: {
|
|
202
|
-
onChange: ({ value }) => {
|
|
203
|
-
if (value.length < 3) {
|
|
204
|
-
return 'At least 3 names are required'
|
|
205
|
-
}
|
|
206
|
-
return
|
|
207
|
-
},
|
|
208
|
-
},
|
|
209
|
-
defaultMeta: {
|
|
210
|
-
isTouched: true,
|
|
211
|
-
},
|
|
212
|
-
})
|
|
213
|
-
field.mount()
|
|
214
|
-
|
|
215
|
-
field.insertValue(1, 'other')
|
|
216
|
-
|
|
217
|
-
expect(field.getMeta().errors).toStrictEqual([
|
|
218
|
-
'At least 3 names are required',
|
|
219
|
-
])
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
it('should remove a value from an array value correctly', () => {
|
|
223
|
-
const form = new FormApi({
|
|
224
|
-
defaultValues: {
|
|
225
|
-
names: ['one', 'two'],
|
|
226
|
-
},
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
const field = new FieldApi({
|
|
230
|
-
form,
|
|
231
|
-
name: 'names',
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
field.removeValue(1)
|
|
235
|
-
|
|
236
|
-
expect(field.getValue()).toStrictEqual(['one'])
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
it('should run onChange validation when removing an array fields value', async () => {
|
|
240
|
-
const form = new FormApi({
|
|
241
|
-
defaultValues: {
|
|
242
|
-
names: ['test'],
|
|
243
|
-
},
|
|
244
|
-
})
|
|
245
|
-
form.mount()
|
|
246
|
-
|
|
247
|
-
const field = new FieldApi({
|
|
248
|
-
form,
|
|
249
|
-
name: 'names',
|
|
250
|
-
validators: {
|
|
251
|
-
onChange: ({ value }) => {
|
|
252
|
-
if (value.length < 3) {
|
|
253
|
-
return 'At least 3 names are required'
|
|
254
|
-
}
|
|
255
|
-
return
|
|
256
|
-
},
|
|
257
|
-
},
|
|
258
|
-
defaultMeta: {
|
|
259
|
-
isTouched: true,
|
|
260
|
-
},
|
|
261
|
-
})
|
|
262
|
-
field.mount()
|
|
263
|
-
|
|
264
|
-
await field.removeValue(0)
|
|
265
|
-
|
|
266
|
-
expect(field.getMeta().errors).toStrictEqual([
|
|
267
|
-
'At least 3 names are required',
|
|
268
|
-
])
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
it('should remove a subfield from an array field correctly', async () => {
|
|
272
|
-
const form = new FormApi({
|
|
273
|
-
defaultValues: {
|
|
274
|
-
people: [] as Array<{ name: string }>,
|
|
275
|
-
},
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
const field = new FieldApi({
|
|
279
|
-
form,
|
|
280
|
-
name: 'people',
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
const subFieldValidators = {
|
|
284
|
-
onChange: ({ value }: { value: string }) =>
|
|
285
|
-
value.length === 0 ? 'Required' : null,
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const subField1 = new FieldApi({
|
|
289
|
-
form: field.form,
|
|
290
|
-
name: 'people[0].name',
|
|
291
|
-
defaultValue: '',
|
|
292
|
-
validators: subFieldValidators,
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
const subField2 = new FieldApi({
|
|
296
|
-
form: field.form,
|
|
297
|
-
name: 'people[1].name',
|
|
298
|
-
defaultValue: 'hello',
|
|
299
|
-
validators: subFieldValidators,
|
|
300
|
-
})
|
|
301
|
-
|
|
302
|
-
const subField3 = new FieldApi({
|
|
303
|
-
form: field.form,
|
|
304
|
-
name: 'people[2].name',
|
|
305
|
-
defaultValue: '',
|
|
306
|
-
validators: subFieldValidators,
|
|
307
|
-
})
|
|
308
|
-
|
|
309
|
-
const subField4 = new FieldApi({
|
|
310
|
-
form: field.form,
|
|
311
|
-
name: 'people[3].name',
|
|
312
|
-
defaultValue: 'world',
|
|
313
|
-
validators: subFieldValidators,
|
|
314
|
-
})
|
|
315
|
-
|
|
316
|
-
;[form, field, subField1, subField2, subField3, subField4].forEach((f) =>
|
|
317
|
-
f.mount(),
|
|
318
|
-
)
|
|
319
|
-
|
|
320
|
-
await form.handleSubmit()
|
|
321
|
-
|
|
322
|
-
expect(subField1.state.meta.errorMap.onChange).toStrictEqual('Required')
|
|
323
|
-
expect(subField2.state.meta.errorMap.onChange).toStrictEqual(undefined)
|
|
324
|
-
expect(subField3.state.meta.errorMap.onChange).toStrictEqual('Required')
|
|
325
|
-
expect(subField4.state.meta.errorMap.onChange).toStrictEqual(undefined)
|
|
326
|
-
|
|
327
|
-
await field.removeValue(0 /* subField1 */, { touch: true })
|
|
328
|
-
|
|
329
|
-
expect(subField1.state.value).toBe('hello')
|
|
330
|
-
expect(subField1.state.meta.errorMap.onChange).toStrictEqual(undefined)
|
|
331
|
-
expect(subField2.state.value).toBe('')
|
|
332
|
-
expect(subField2.state.meta.errorMap.onChange).toStrictEqual('Required')
|
|
333
|
-
expect(subField3.state.value).toBe('world')
|
|
334
|
-
expect(subField3.state.meta.errorMap.onChange).toStrictEqual(undefined)
|
|
335
|
-
expect(form.getFieldInfo('people[0].name').instance?.state.value).toBe(
|
|
336
|
-
'hello',
|
|
337
|
-
)
|
|
338
|
-
expect(form.getFieldInfo('people[1].name').instance?.state.value).toBe('')
|
|
339
|
-
expect(form.getFieldInfo('people[2].name').instance?.state.value).toBe(
|
|
340
|
-
'world',
|
|
341
|
-
)
|
|
342
|
-
})
|
|
343
|
-
|
|
344
|
-
it('should remove remove the last subfield from an array field correctly', async () => {
|
|
345
|
-
const form = new FormApi({
|
|
346
|
-
defaultValues: {
|
|
347
|
-
people: [] as Array<{ name: string }>,
|
|
348
|
-
},
|
|
349
|
-
})
|
|
350
|
-
|
|
351
|
-
const field = new FieldApi({
|
|
352
|
-
form,
|
|
353
|
-
name: 'people',
|
|
354
|
-
})
|
|
355
|
-
|
|
356
|
-
const subFieldValidators = {
|
|
357
|
-
onChange: ({ value }: { value: string }) =>
|
|
358
|
-
value.length === 0 ? 'Required' : null,
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
const subField1 = new FieldApi({
|
|
362
|
-
form: field.form,
|
|
363
|
-
name: 'people[0].name',
|
|
364
|
-
defaultValue: '',
|
|
365
|
-
validators: subFieldValidators,
|
|
366
|
-
})
|
|
367
|
-
|
|
368
|
-
;[form, field, subField1].forEach((f) => f.mount())
|
|
369
|
-
|
|
370
|
-
await form.handleSubmit()
|
|
371
|
-
|
|
372
|
-
expect(subField1.state.meta.errorMap.onChange).toStrictEqual('Required')
|
|
373
|
-
|
|
374
|
-
await field.removeValue(0 /* subField1 */, { touch: true })
|
|
375
|
-
|
|
376
|
-
expect(subField1.state.value).toBe(undefined)
|
|
377
|
-
expect(subField1.state.meta.errorMap.onChange).toStrictEqual(undefined)
|
|
378
|
-
|
|
379
|
-
expect(form.state.canSubmit).toBe(true)
|
|
380
|
-
})
|
|
381
|
-
|
|
382
|
-
it('should swap a value from an array value correctly', () => {
|
|
383
|
-
const form = new FormApi({
|
|
384
|
-
defaultValues: {
|
|
385
|
-
names: ['one', 'two'],
|
|
386
|
-
},
|
|
387
|
-
})
|
|
388
|
-
|
|
389
|
-
const field = new FieldApi({
|
|
390
|
-
form,
|
|
391
|
-
name: 'names',
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
field.swapValues(0, 1)
|
|
395
|
-
|
|
396
|
-
expect(field.getValue()).toStrictEqual(['two', 'one'])
|
|
397
|
-
})
|
|
398
|
-
|
|
399
|
-
it('should run onChange validation when swapping an array fields value', () => {
|
|
400
|
-
const form = new FormApi({
|
|
401
|
-
defaultValues: {
|
|
402
|
-
names: ['test', 'test2'],
|
|
403
|
-
},
|
|
404
|
-
})
|
|
405
|
-
form.mount()
|
|
406
|
-
|
|
407
|
-
const field = new FieldApi({
|
|
408
|
-
form,
|
|
409
|
-
name: 'names',
|
|
410
|
-
validators: {
|
|
411
|
-
onChange: ({ value }) => {
|
|
412
|
-
if (value.length < 3) {
|
|
413
|
-
return 'At least 3 names are required'
|
|
414
|
-
}
|
|
415
|
-
return
|
|
416
|
-
},
|
|
417
|
-
},
|
|
418
|
-
defaultMeta: {
|
|
419
|
-
isTouched: true,
|
|
420
|
-
},
|
|
421
|
-
})
|
|
422
|
-
field.mount()
|
|
423
|
-
|
|
424
|
-
field.swapValues(0, 1)
|
|
425
|
-
|
|
426
|
-
expect(field.getMeta().errors).toStrictEqual([
|
|
427
|
-
'At least 3 names are required',
|
|
428
|
-
])
|
|
429
|
-
})
|
|
430
|
-
|
|
431
|
-
it('should move a value from an array value correctly', () => {
|
|
432
|
-
const form = new FormApi({
|
|
433
|
-
defaultValues: {
|
|
434
|
-
names: ['one', 'two', 'three', 'four'],
|
|
435
|
-
},
|
|
436
|
-
})
|
|
437
|
-
|
|
438
|
-
const field = new FieldApi({
|
|
439
|
-
form,
|
|
440
|
-
name: 'names',
|
|
441
|
-
})
|
|
442
|
-
|
|
443
|
-
field.moveValue(2, 0)
|
|
444
|
-
|
|
445
|
-
expect(field.getValue()).toStrictEqual(['three', 'one', 'two', 'four'])
|
|
446
|
-
})
|
|
447
|
-
|
|
448
|
-
it('should run onChange validation when moving an array fields value', () => {
|
|
449
|
-
const form = new FormApi({
|
|
450
|
-
defaultValues: {
|
|
451
|
-
names: ['test', 'test2'],
|
|
452
|
-
},
|
|
453
|
-
})
|
|
454
|
-
form.mount()
|
|
455
|
-
|
|
456
|
-
const field = new FieldApi({
|
|
457
|
-
form,
|
|
458
|
-
name: 'names',
|
|
459
|
-
validators: {
|
|
460
|
-
onChange: ({ value }) => {
|
|
461
|
-
if (value.length < 3) {
|
|
462
|
-
return 'At least 3 names are required'
|
|
463
|
-
}
|
|
464
|
-
return
|
|
465
|
-
},
|
|
466
|
-
},
|
|
467
|
-
defaultMeta: {
|
|
468
|
-
isTouched: true,
|
|
469
|
-
},
|
|
470
|
-
})
|
|
471
|
-
field.mount()
|
|
472
|
-
|
|
473
|
-
field.moveValue(0, 1)
|
|
474
|
-
|
|
475
|
-
expect(field.getMeta().errors).toStrictEqual([
|
|
476
|
-
'At least 3 names are required',
|
|
477
|
-
])
|
|
478
|
-
})
|
|
479
|
-
|
|
480
|
-
it('should not throw errors when no meta info is stored on a field and a form re-renders', async () => {
|
|
481
|
-
const form = new FormApi({
|
|
482
|
-
defaultValues: {
|
|
483
|
-
name: 'test',
|
|
484
|
-
},
|
|
485
|
-
})
|
|
486
|
-
|
|
487
|
-
const field = new FieldApi({
|
|
488
|
-
form,
|
|
489
|
-
name: 'name',
|
|
490
|
-
})
|
|
491
|
-
|
|
492
|
-
field.mount()
|
|
493
|
-
|
|
494
|
-
expect(() =>
|
|
495
|
-
form.update({
|
|
496
|
-
defaultValues: {
|
|
497
|
-
name: 'other',
|
|
498
|
-
},
|
|
499
|
-
}),
|
|
500
|
-
).not.toThrow()
|
|
501
|
-
})
|
|
502
|
-
|
|
503
|
-
it('should run validation onChange', () => {
|
|
504
|
-
const form = new FormApi({
|
|
505
|
-
defaultValues: {
|
|
506
|
-
name: 'test',
|
|
507
|
-
},
|
|
508
|
-
})
|
|
509
|
-
|
|
510
|
-
const field = new FieldApi({
|
|
511
|
-
form,
|
|
512
|
-
name: 'name',
|
|
513
|
-
validators: {
|
|
514
|
-
onChange: ({ value }) => {
|
|
515
|
-
if (value === 'other') return 'Please enter a different value'
|
|
516
|
-
return
|
|
517
|
-
},
|
|
518
|
-
},
|
|
519
|
-
})
|
|
520
|
-
|
|
521
|
-
field.mount()
|
|
522
|
-
|
|
523
|
-
expect(field.getMeta().errors.length).toBe(0)
|
|
524
|
-
field.setValue('other', { touch: true })
|
|
525
|
-
expect(field.getMeta().errors).toContain('Please enter a different value')
|
|
526
|
-
expect(field.getMeta().errorMap).toMatchObject({
|
|
527
|
-
onChange: 'Please enter a different value',
|
|
528
|
-
})
|
|
529
|
-
})
|
|
530
|
-
|
|
531
|
-
it('should run async validation onChange', async () => {
|
|
532
|
-
vi.useFakeTimers()
|
|
533
|
-
|
|
534
|
-
const form = new FormApi({
|
|
535
|
-
defaultValues: {
|
|
536
|
-
name: 'test',
|
|
537
|
-
},
|
|
538
|
-
})
|
|
539
|
-
|
|
540
|
-
const field = new FieldApi({
|
|
541
|
-
form,
|
|
542
|
-
name: 'name',
|
|
543
|
-
validators: {
|
|
544
|
-
onChangeAsync: async ({ value }) => {
|
|
545
|
-
await sleep(1000)
|
|
546
|
-
if (value === 'other') return 'Please enter a different value'
|
|
547
|
-
return
|
|
548
|
-
},
|
|
549
|
-
},
|
|
550
|
-
})
|
|
551
|
-
|
|
552
|
-
field.mount()
|
|
553
|
-
|
|
554
|
-
expect(field.getMeta().errors.length).toBe(0)
|
|
555
|
-
field.setValue('other', { touch: true })
|
|
556
|
-
await vi.runAllTimersAsync()
|
|
557
|
-
expect(field.getMeta().errors).toContain('Please enter a different value')
|
|
558
|
-
expect(field.getMeta().errorMap).toMatchObject({
|
|
559
|
-
onChange: 'Please enter a different value',
|
|
560
|
-
})
|
|
561
|
-
})
|
|
562
|
-
|
|
563
|
-
it('should run async validation onChange with debounce', async () => {
|
|
564
|
-
vi.useFakeTimers()
|
|
565
|
-
const sleepMock = vi.fn().mockImplementation(sleep)
|
|
566
|
-
|
|
567
|
-
const form = new FormApi({
|
|
568
|
-
defaultValues: {
|
|
569
|
-
name: 'test',
|
|
570
|
-
},
|
|
571
|
-
})
|
|
572
|
-
|
|
573
|
-
const field = new FieldApi({
|
|
574
|
-
form,
|
|
575
|
-
name: 'name',
|
|
576
|
-
validators: {
|
|
577
|
-
onChangeAsyncDebounceMs: 1000,
|
|
578
|
-
onChangeAsync: async ({ value }) => {
|
|
579
|
-
await sleepMock(1000)
|
|
580
|
-
if (value === 'other') return 'Please enter a different value'
|
|
581
|
-
return
|
|
582
|
-
},
|
|
583
|
-
},
|
|
584
|
-
})
|
|
585
|
-
|
|
586
|
-
field.mount()
|
|
587
|
-
|
|
588
|
-
expect(field.getMeta().errors.length).toBe(0)
|
|
589
|
-
field.setValue('other', { touch: true })
|
|
590
|
-
field.setValue('other')
|
|
591
|
-
await vi.runAllTimersAsync()
|
|
592
|
-
// sleepMock will have been called 2 times without onChangeAsyncDebounceMs
|
|
593
|
-
expect(sleepMock).toHaveBeenCalledTimes(1)
|
|
594
|
-
expect(field.getMeta().errors).toContain('Please enter a different value')
|
|
595
|
-
expect(field.getMeta().errorMap).toMatchObject({
|
|
596
|
-
onChange: 'Please enter a different value',
|
|
597
|
-
})
|
|
598
|
-
})
|
|
599
|
-
|
|
600
|
-
it('should run async validation onChange with asyncDebounceMs', async () => {
|
|
601
|
-
vi.useFakeTimers()
|
|
602
|
-
const sleepMock = vi.fn().mockImplementation(sleep)
|
|
603
|
-
|
|
604
|
-
const form = new FormApi({
|
|
605
|
-
defaultValues: {
|
|
606
|
-
name: 'test',
|
|
607
|
-
},
|
|
608
|
-
})
|
|
609
|
-
|
|
610
|
-
const field = new FieldApi({
|
|
611
|
-
form,
|
|
612
|
-
name: 'name',
|
|
613
|
-
asyncDebounceMs: 1000,
|
|
614
|
-
validators: {
|
|
615
|
-
onChangeAsync: async ({ value }) => {
|
|
616
|
-
await sleepMock(1000)
|
|
617
|
-
if (value === 'other') return 'Please enter a different value'
|
|
618
|
-
return
|
|
619
|
-
},
|
|
620
|
-
},
|
|
621
|
-
})
|
|
622
|
-
|
|
623
|
-
field.mount()
|
|
624
|
-
|
|
625
|
-
expect(field.getMeta().errors.length).toBe(0)
|
|
626
|
-
field.setValue('other', { touch: true })
|
|
627
|
-
field.setValue('other')
|
|
628
|
-
await vi.runAllTimersAsync()
|
|
629
|
-
// sleepMock will have been called 2 times without asyncDebounceMs
|
|
630
|
-
expect(sleepMock).toHaveBeenCalledTimes(1)
|
|
631
|
-
expect(field.getMeta().errors).toContain('Please enter a different value')
|
|
632
|
-
expect(field.getMeta().errorMap).toMatchObject({
|
|
633
|
-
onChange: 'Please enter a different value',
|
|
634
|
-
})
|
|
635
|
-
})
|
|
636
|
-
|
|
637
|
-
it('should run validation onBlur', () => {
|
|
638
|
-
const form = new FormApi({
|
|
639
|
-
defaultValues: {
|
|
640
|
-
name: 'other',
|
|
641
|
-
},
|
|
642
|
-
})
|
|
643
|
-
|
|
644
|
-
const field = new FieldApi({
|
|
645
|
-
form,
|
|
646
|
-
name: 'name',
|
|
647
|
-
validators: {
|
|
648
|
-
onBlur: ({ value }) => {
|
|
649
|
-
if (value === 'other') return 'Please enter a different value'
|
|
650
|
-
return
|
|
651
|
-
},
|
|
652
|
-
},
|
|
653
|
-
})
|
|
654
|
-
|
|
655
|
-
field.mount()
|
|
656
|
-
|
|
657
|
-
field.setValue('other', { touch: true })
|
|
658
|
-
field.validate('blur')
|
|
659
|
-
expect(field.getMeta().errors).toContain('Please enter a different value')
|
|
660
|
-
expect(field.getMeta().errorMap).toMatchObject({
|
|
661
|
-
onBlur: 'Please enter a different value',
|
|
662
|
-
})
|
|
663
|
-
})
|
|
664
|
-
|
|
665
|
-
it('should run async validation onBlur', async () => {
|
|
666
|
-
vi.useFakeTimers()
|
|
667
|
-
|
|
668
|
-
const form = new FormApi({
|
|
669
|
-
defaultValues: {
|
|
670
|
-
name: 'test',
|
|
671
|
-
},
|
|
672
|
-
})
|
|
673
|
-
|
|
674
|
-
const field = new FieldApi({
|
|
675
|
-
form,
|
|
676
|
-
name: 'name',
|
|
677
|
-
validators: {
|
|
678
|
-
onBlurAsync: async ({ value }) => {
|
|
679
|
-
await sleep(1000)
|
|
680
|
-
if (value === 'other') return 'Please enter a different value'
|
|
681
|
-
return
|
|
682
|
-
},
|
|
683
|
-
},
|
|
684
|
-
})
|
|
685
|
-
|
|
686
|
-
field.mount()
|
|
687
|
-
|
|
688
|
-
expect(field.getMeta().errors.length).toBe(0)
|
|
689
|
-
field.setValue('other', { touch: true })
|
|
690
|
-
field.validate('blur')
|
|
691
|
-
await vi.runAllTimersAsync()
|
|
692
|
-
expect(field.getMeta().errors).toContain('Please enter a different value')
|
|
693
|
-
expect(field.getMeta().errorMap).toMatchObject({
|
|
694
|
-
onBlur: 'Please enter a different value',
|
|
695
|
-
})
|
|
696
|
-
})
|
|
697
|
-
|
|
698
|
-
it('should run async validation onBlur with debounce', async () => {
|
|
699
|
-
vi.useFakeTimers()
|
|
700
|
-
const sleepMock = vi.fn().mockImplementation(sleep)
|
|
701
|
-
|
|
702
|
-
const form = new FormApi({
|
|
703
|
-
defaultValues: {
|
|
704
|
-
name: 'test',
|
|
705
|
-
},
|
|
706
|
-
})
|
|
707
|
-
|
|
708
|
-
const field = new FieldApi({
|
|
709
|
-
form,
|
|
710
|
-
name: 'name',
|
|
711
|
-
validators: {
|
|
712
|
-
onBlurAsyncDebounceMs: 1000,
|
|
713
|
-
onBlurAsync: async ({ value }) => {
|
|
714
|
-
await sleepMock(10)
|
|
715
|
-
if (value === 'other') return 'Please enter a different value'
|
|
716
|
-
return
|
|
717
|
-
},
|
|
718
|
-
},
|
|
719
|
-
})
|
|
720
|
-
|
|
721
|
-
field.mount()
|
|
722
|
-
|
|
723
|
-
expect(field.getMeta().errors.length).toBe(0)
|
|
724
|
-
field.setValue('other', { touch: true })
|
|
725
|
-
field.validate('blur')
|
|
726
|
-
field.validate('blur')
|
|
727
|
-
await vi.runAllTimersAsync()
|
|
728
|
-
// sleepMock will have been called 2 times without onBlurAsyncDebounceMs
|
|
729
|
-
expect(sleepMock).toHaveBeenCalledTimes(1)
|
|
730
|
-
expect(field.getMeta().errors).toContain('Please enter a different value')
|
|
731
|
-
expect(field.getMeta().errorMap).toMatchObject({
|
|
732
|
-
onBlur: 'Please enter a different value',
|
|
733
|
-
})
|
|
734
|
-
})
|
|
735
|
-
|
|
736
|
-
it('should run async validation onBlur with asyncDebounceMs', async () => {
|
|
737
|
-
vi.useFakeTimers()
|
|
738
|
-
const sleepMock = vi.fn().mockImplementation(sleep)
|
|
739
|
-
|
|
740
|
-
const form = new FormApi({
|
|
741
|
-
defaultValues: {
|
|
742
|
-
name: 'test',
|
|
743
|
-
},
|
|
744
|
-
})
|
|
745
|
-
|
|
746
|
-
const field = new FieldApi({
|
|
747
|
-
form,
|
|
748
|
-
name: 'name',
|
|
749
|
-
asyncDebounceMs: 1000,
|
|
750
|
-
validators: {
|
|
751
|
-
onBlurAsync: async ({ value }) => {
|
|
752
|
-
await sleepMock(10)
|
|
753
|
-
if (value === 'other') return 'Please enter a different value'
|
|
754
|
-
return
|
|
755
|
-
},
|
|
756
|
-
},
|
|
757
|
-
})
|
|
758
|
-
|
|
759
|
-
field.mount()
|
|
760
|
-
|
|
761
|
-
expect(field.getMeta().errors.length).toBe(0)
|
|
762
|
-
field.setValue('other', { touch: true })
|
|
763
|
-
field.validate('blur')
|
|
764
|
-
field.validate('blur')
|
|
765
|
-
await vi.runAllTimersAsync()
|
|
766
|
-
// sleepMock will have been called 2 times without asyncDebounceMs
|
|
767
|
-
expect(sleepMock).toHaveBeenCalledTimes(1)
|
|
768
|
-
expect(field.getMeta().errors).toContain('Please enter a different value')
|
|
769
|
-
expect(field.getMeta().errorMap).toMatchObject({
|
|
770
|
-
onBlur: 'Please enter a different value',
|
|
771
|
-
})
|
|
772
|
-
})
|
|
773
|
-
|
|
774
|
-
it('should run async validation onSubmit', async () => {
|
|
775
|
-
vi.useFakeTimers()
|
|
776
|
-
|
|
777
|
-
const form = new FormApi({
|
|
778
|
-
defaultValues: {
|
|
779
|
-
name: 'test',
|
|
780
|
-
},
|
|
781
|
-
})
|
|
782
|
-
|
|
783
|
-
const field = new FieldApi({
|
|
784
|
-
form,
|
|
785
|
-
name: 'name',
|
|
786
|
-
validators: {
|
|
787
|
-
onSubmitAsync: async ({ value }) => {
|
|
788
|
-
await sleep(1000)
|
|
789
|
-
if (value === 'other') return 'Please enter a different value'
|
|
790
|
-
return
|
|
791
|
-
},
|
|
792
|
-
},
|
|
793
|
-
})
|
|
794
|
-
|
|
795
|
-
field.mount()
|
|
796
|
-
|
|
797
|
-
expect(field.getMeta().errors.length).toBe(0)
|
|
798
|
-
field.setValue('other', { touch: true })
|
|
799
|
-
field.validate('submit')
|
|
800
|
-
await vi.runAllTimersAsync()
|
|
801
|
-
expect(field.getMeta().errors).toContain('Please enter a different value')
|
|
802
|
-
expect(field.getMeta().errorMap).toMatchObject({
|
|
803
|
-
onSubmit: 'Please enter a different value',
|
|
804
|
-
})
|
|
805
|
-
})
|
|
806
|
-
|
|
807
|
-
it('should contain multiple errors when running validation onBlur and onChange', () => {
|
|
808
|
-
const form = new FormApi({
|
|
809
|
-
defaultValues: {
|
|
810
|
-
name: 'other',
|
|
811
|
-
},
|
|
812
|
-
})
|
|
813
|
-
|
|
814
|
-
const field = new FieldApi({
|
|
815
|
-
form,
|
|
816
|
-
name: 'name',
|
|
817
|
-
validators: {
|
|
818
|
-
onBlur: ({ value }) => {
|
|
819
|
-
if (value === 'other') return 'Please enter a different value'
|
|
820
|
-
return
|
|
821
|
-
},
|
|
822
|
-
onChange: ({ value }) => {
|
|
823
|
-
if (value === 'other') return 'Please enter a different value'
|
|
824
|
-
return
|
|
825
|
-
},
|
|
826
|
-
},
|
|
827
|
-
})
|
|
828
|
-
|
|
829
|
-
field.mount()
|
|
830
|
-
|
|
831
|
-
field.setValue('other', { touch: true })
|
|
832
|
-
field.validate('blur')
|
|
833
|
-
expect(field.getMeta().errors).toStrictEqual([
|
|
834
|
-
'Please enter a different value',
|
|
835
|
-
'Please enter a different value',
|
|
836
|
-
])
|
|
837
|
-
expect(field.getMeta().errorMap).toEqual({
|
|
838
|
-
onBlur: 'Please enter a different value',
|
|
839
|
-
onChange: 'Please enter a different value',
|
|
840
|
-
})
|
|
841
|
-
})
|
|
842
|
-
|
|
843
|
-
it('should reset onChange errors when the issue is resolved', () => {
|
|
844
|
-
const form = new FormApi({
|
|
845
|
-
defaultValues: {
|
|
846
|
-
name: 'other',
|
|
847
|
-
},
|
|
848
|
-
})
|
|
849
|
-
|
|
850
|
-
const field = new FieldApi({
|
|
851
|
-
form,
|
|
852
|
-
name: 'name',
|
|
853
|
-
validators: {
|
|
854
|
-
onChange: ({ value }) => {
|
|
855
|
-
if (value === 'other') return 'Please enter a different value'
|
|
856
|
-
return
|
|
857
|
-
},
|
|
858
|
-
},
|
|
859
|
-
})
|
|
860
|
-
|
|
861
|
-
field.mount()
|
|
862
|
-
|
|
863
|
-
field.setValue('other', { touch: true })
|
|
864
|
-
expect(field.getMeta().errors).toStrictEqual([
|
|
865
|
-
'Please enter a different value',
|
|
866
|
-
])
|
|
867
|
-
expect(field.getMeta().errorMap).toEqual({
|
|
868
|
-
onChange: 'Please enter a different value',
|
|
869
|
-
})
|
|
870
|
-
field.setValue('test', { touch: true })
|
|
871
|
-
expect(field.getMeta().errors).toStrictEqual([])
|
|
872
|
-
expect(field.getMeta().errorMap).toEqual({})
|
|
873
|
-
})
|
|
874
|
-
|
|
875
|
-
it('should handle default value on field using state.value', async () => {
|
|
876
|
-
interface Form {
|
|
877
|
-
name: string
|
|
878
|
-
}
|
|
879
|
-
const form = new FormApi<Form>()
|
|
880
|
-
|
|
881
|
-
const field = new FieldApi({
|
|
882
|
-
form,
|
|
883
|
-
name: 'name',
|
|
884
|
-
defaultValue: 'test',
|
|
885
|
-
})
|
|
886
|
-
|
|
887
|
-
field.mount()
|
|
888
|
-
|
|
889
|
-
expect(field.state.value).toBe('test')
|
|
890
|
-
})
|
|
891
|
-
|
|
892
|
-
// test the unmounting of the fieldAPI
|
|
893
|
-
it('should preserve value on unmount', () => {
|
|
894
|
-
const form = new FormApi({
|
|
895
|
-
defaultValues: {
|
|
896
|
-
name: 'test',
|
|
897
|
-
},
|
|
898
|
-
})
|
|
899
|
-
|
|
900
|
-
const field = new FieldApi({
|
|
901
|
-
form,
|
|
902
|
-
name: 'name',
|
|
903
|
-
preserveValue: true,
|
|
904
|
-
})
|
|
905
|
-
|
|
906
|
-
const unmount = field.mount()
|
|
907
|
-
unmount()
|
|
908
|
-
expect(form.getFieldInfo(field.name).instance).toBeDefined()
|
|
909
|
-
expect(form.getFieldInfo(field.name)).toBeDefined()
|
|
910
|
-
})
|
|
911
|
-
|
|
912
|
-
it('should not preserve field value on ummount', () => {
|
|
913
|
-
const form = new FormApi({
|
|
914
|
-
defaultValues: {
|
|
915
|
-
name: 'test',
|
|
916
|
-
},
|
|
917
|
-
})
|
|
918
|
-
|
|
919
|
-
const field = new FieldApi({
|
|
920
|
-
form,
|
|
921
|
-
name: 'name',
|
|
922
|
-
})
|
|
923
|
-
|
|
924
|
-
const unmount = field.mount()
|
|
925
|
-
const callback = vi.fn()
|
|
926
|
-
const subscription = form.store.subscribe(callback)
|
|
927
|
-
unmount()
|
|
928
|
-
const info = form.getFieldInfo(field.name)
|
|
929
|
-
subscription()
|
|
930
|
-
expect(info.instance).toBeNull()
|
|
931
|
-
expect(Object.keys(info.instance ?? {}).length).toBe(0)
|
|
932
|
-
|
|
933
|
-
// Check that form store has been updated
|
|
934
|
-
expect(callback).toHaveBeenCalledOnce()
|
|
935
|
-
|
|
936
|
-
// Field should have been removed from the form as well
|
|
937
|
-
expect(form.state.values.name).toBeUndefined()
|
|
938
|
-
expect(form.state.fieldMeta.name).toBeUndefined()
|
|
939
|
-
expect(form.store.state.values.name).toBeUndefined()
|
|
940
|
-
expect(form.store.state.fieldMeta.name).toBeUndefined()
|
|
941
|
-
})
|
|
942
|
-
|
|
943
|
-
it('should show onSubmit errors', async () => {
|
|
944
|
-
const form = new FormApi({
|
|
945
|
-
defaultValues: {
|
|
946
|
-
firstName: '',
|
|
947
|
-
},
|
|
948
|
-
})
|
|
949
|
-
|
|
950
|
-
const field = new FieldApi({
|
|
951
|
-
form,
|
|
952
|
-
name: 'firstName',
|
|
953
|
-
validators: {
|
|
954
|
-
onSubmit: ({ value }) =>
|
|
955
|
-
value.length > 0 ? undefined : 'first name is required',
|
|
956
|
-
},
|
|
957
|
-
})
|
|
958
|
-
|
|
959
|
-
field.mount()
|
|
960
|
-
|
|
961
|
-
await form.handleSubmit()
|
|
962
|
-
expect(field.getMeta().errors).toStrictEqual(['first name is required'])
|
|
963
|
-
})
|
|
964
|
-
|
|
965
|
-
it('should show onMount errors', async () => {
|
|
966
|
-
const form = new FormApi({
|
|
967
|
-
defaultValues: {
|
|
968
|
-
firstName: '',
|
|
969
|
-
},
|
|
970
|
-
})
|
|
971
|
-
|
|
972
|
-
const field = new FieldApi({
|
|
973
|
-
form,
|
|
974
|
-
name: 'firstName',
|
|
975
|
-
validators: {
|
|
976
|
-
onMount: ({ value }) =>
|
|
977
|
-
value.length > 0 ? undefined : 'first name is required',
|
|
978
|
-
},
|
|
979
|
-
})
|
|
980
|
-
|
|
981
|
-
form.mount()
|
|
982
|
-
field.mount()
|
|
983
|
-
|
|
984
|
-
expect(field.getMeta().errors).toStrictEqual(['first name is required'])
|
|
985
|
-
})
|
|
986
|
-
|
|
987
|
-
it('should cancel previous functions from an async validator with an abort signal', async () => {
|
|
988
|
-
vi.useRealTimers()
|
|
989
|
-
const form = new FormApi({
|
|
990
|
-
defaultValues: {
|
|
991
|
-
firstName: '',
|
|
992
|
-
},
|
|
993
|
-
})
|
|
994
|
-
|
|
995
|
-
let resolve!: () => void
|
|
996
|
-
const promise = new Promise((r) => {
|
|
997
|
-
resolve = r as never
|
|
998
|
-
})
|
|
999
|
-
|
|
1000
|
-
const fn = vi.fn()
|
|
1001
|
-
|
|
1002
|
-
const field = new FieldApi({
|
|
1003
|
-
form,
|
|
1004
|
-
name: 'firstName',
|
|
1005
|
-
validators: {
|
|
1006
|
-
onChangeAsyncDebounceMs: 0,
|
|
1007
|
-
onChangeAsync: async ({ signal }) => {
|
|
1008
|
-
await promise
|
|
1009
|
-
if (signal.aborted) return
|
|
1010
|
-
fn()
|
|
1011
|
-
return undefined
|
|
1012
|
-
},
|
|
1013
|
-
},
|
|
1014
|
-
})
|
|
1015
|
-
|
|
1016
|
-
field.mount()
|
|
1017
|
-
|
|
1018
|
-
field.setValue('one', { touch: true })
|
|
1019
|
-
// Allow for a micro-tick to allow the promise to resolve
|
|
1020
|
-
await sleep(1)
|
|
1021
|
-
field.setValue('two', { touch: true })
|
|
1022
|
-
resolve()
|
|
1023
|
-
await sleep(1)
|
|
1024
|
-
expect(fn).toHaveBeenCalledTimes(1)
|
|
1025
|
-
})
|
|
1026
|
-
|
|
1027
|
-
it('should run onChange on a linked field', () => {
|
|
1028
|
-
const form = new FormApi({
|
|
1029
|
-
defaultValues: {
|
|
1030
|
-
password: '',
|
|
1031
|
-
confirm_password: '',
|
|
1032
|
-
},
|
|
1033
|
-
})
|
|
1034
|
-
|
|
1035
|
-
const passField = new FieldApi({
|
|
1036
|
-
form,
|
|
1037
|
-
name: 'password',
|
|
1038
|
-
})
|
|
1039
|
-
|
|
1040
|
-
const passconfirmField = new FieldApi({
|
|
1041
|
-
form,
|
|
1042
|
-
name: 'confirm_password',
|
|
1043
|
-
validators: {
|
|
1044
|
-
onChangeListenTo: ['password'],
|
|
1045
|
-
onChange: ({ value, fieldApi }) => {
|
|
1046
|
-
if (value !== fieldApi.form.getFieldValue('password')) {
|
|
1047
|
-
return 'Passwords do not match'
|
|
1048
|
-
}
|
|
1049
|
-
return undefined
|
|
1050
|
-
},
|
|
1051
|
-
},
|
|
1052
|
-
})
|
|
1053
|
-
|
|
1054
|
-
passField.mount()
|
|
1055
|
-
passconfirmField.mount()
|
|
1056
|
-
|
|
1057
|
-
passField.setValue('one', { touch: true })
|
|
1058
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([
|
|
1059
|
-
'Passwords do not match',
|
|
1060
|
-
])
|
|
1061
|
-
passconfirmField.setValue('one', { touch: true })
|
|
1062
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([])
|
|
1063
|
-
passField.setValue('two', { touch: true })
|
|
1064
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([
|
|
1065
|
-
'Passwords do not match',
|
|
1066
|
-
])
|
|
1067
|
-
})
|
|
1068
|
-
|
|
1069
|
-
it('should run onBlur on a linked field', () => {
|
|
1070
|
-
const form = new FormApi({
|
|
1071
|
-
defaultValues: {
|
|
1072
|
-
password: '',
|
|
1073
|
-
confirm_password: '',
|
|
1074
|
-
},
|
|
1075
|
-
})
|
|
1076
|
-
|
|
1077
|
-
const passField = new FieldApi({
|
|
1078
|
-
form,
|
|
1079
|
-
name: 'password',
|
|
1080
|
-
})
|
|
1081
|
-
|
|
1082
|
-
const passconfirmField = new FieldApi({
|
|
1083
|
-
form,
|
|
1084
|
-
name: 'confirm_password',
|
|
1085
|
-
validators: {
|
|
1086
|
-
onBlurListenTo: ['password'],
|
|
1087
|
-
onBlur: ({ value, fieldApi }) => {
|
|
1088
|
-
if (value !== fieldApi.form.getFieldValue('password')) {
|
|
1089
|
-
return 'Passwords do not match'
|
|
1090
|
-
}
|
|
1091
|
-
return undefined
|
|
1092
|
-
},
|
|
1093
|
-
},
|
|
1094
|
-
})
|
|
1095
|
-
|
|
1096
|
-
passField.mount()
|
|
1097
|
-
passconfirmField.mount()
|
|
1098
|
-
|
|
1099
|
-
passField.setValue('one', { touch: true })
|
|
1100
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([])
|
|
1101
|
-
passField.handleBlur()
|
|
1102
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([
|
|
1103
|
-
'Passwords do not match',
|
|
1104
|
-
])
|
|
1105
|
-
passconfirmField.setValue('one', { touch: true })
|
|
1106
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([
|
|
1107
|
-
'Passwords do not match',
|
|
1108
|
-
])
|
|
1109
|
-
passField.handleBlur()
|
|
1110
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([])
|
|
1111
|
-
passField.setValue('two', { touch: true })
|
|
1112
|
-
passField.handleBlur()
|
|
1113
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([
|
|
1114
|
-
'Passwords do not match',
|
|
1115
|
-
])
|
|
1116
|
-
})
|
|
1117
|
-
|
|
1118
|
-
it('should run onChangeAsync on a linked field', async () => {
|
|
1119
|
-
vi.useRealTimers()
|
|
1120
|
-
let resolve!: () => void
|
|
1121
|
-
let promise = new Promise((r) => {
|
|
1122
|
-
resolve = r as never
|
|
1123
|
-
})
|
|
1124
|
-
|
|
1125
|
-
const fn = vi.fn()
|
|
1126
|
-
|
|
1127
|
-
const form = new FormApi({
|
|
1128
|
-
defaultValues: {
|
|
1129
|
-
password: '',
|
|
1130
|
-
confirm_password: '',
|
|
1131
|
-
},
|
|
1132
|
-
})
|
|
1133
|
-
|
|
1134
|
-
const passField = new FieldApi({
|
|
1135
|
-
form,
|
|
1136
|
-
name: 'password',
|
|
1137
|
-
})
|
|
1138
|
-
|
|
1139
|
-
const passconfirmField = new FieldApi({
|
|
1140
|
-
form,
|
|
1141
|
-
name: 'confirm_password',
|
|
1142
|
-
validators: {
|
|
1143
|
-
onChangeListenTo: ['password'],
|
|
1144
|
-
onChangeAsync: async ({ value, fieldApi }) => {
|
|
1145
|
-
await promise
|
|
1146
|
-
fn()
|
|
1147
|
-
if (value !== fieldApi.form.getFieldValue('password')) {
|
|
1148
|
-
return 'Passwords do not match'
|
|
1149
|
-
}
|
|
1150
|
-
return undefined
|
|
1151
|
-
},
|
|
1152
|
-
},
|
|
1153
|
-
})
|
|
1154
|
-
|
|
1155
|
-
passField.mount()
|
|
1156
|
-
passconfirmField.mount()
|
|
1157
|
-
|
|
1158
|
-
passField.setValue('one', { touch: true })
|
|
1159
|
-
resolve()
|
|
1160
|
-
// Allow for a micro-tick to allow the promise to resolve
|
|
1161
|
-
await sleep(1)
|
|
1162
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([
|
|
1163
|
-
'Passwords do not match',
|
|
1164
|
-
])
|
|
1165
|
-
promise = new Promise((r) => {
|
|
1166
|
-
resolve = r as never
|
|
1167
|
-
})
|
|
1168
|
-
passconfirmField.setValue('one', { touch: true })
|
|
1169
|
-
resolve()
|
|
1170
|
-
// Allow for a micro-tick to allow the promise to resolve
|
|
1171
|
-
await sleep(1)
|
|
1172
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([])
|
|
1173
|
-
promise = new Promise((r) => {
|
|
1174
|
-
resolve = r as never
|
|
1175
|
-
})
|
|
1176
|
-
passField.setValue('two', { touch: true })
|
|
1177
|
-
resolve()
|
|
1178
|
-
// Allow for a micro-tick to allow the promise to resolve
|
|
1179
|
-
await sleep(1)
|
|
1180
|
-
expect(passconfirmField.state.meta.errors).toStrictEqual([
|
|
1181
|
-
'Passwords do not match',
|
|
1182
|
-
])
|
|
1183
|
-
})
|
|
1184
|
-
})
|