@fogpipe/forma-react 0.12.0-alpha.2 → 0.13.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/README.md +75 -61
- package/dist/index.js +36 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/ErrorBoundary.tsx +14 -7
- package/src/FieldRenderer.tsx +3 -1
- package/src/FormRenderer.tsx +3 -1
- package/src/__tests__/FieldRenderer.test.tsx +128 -1
- package/src/__tests__/FormRenderer.test.tsx +54 -0
- package/src/__tests__/canProceed.test.ts +141 -100
- package/src/__tests__/diabetes-trial-flow.test.ts +235 -66
- package/src/__tests__/null-handling.test.ts +27 -8
- package/src/__tests__/optionVisibility.test.tsx +199 -58
- package/src/__tests__/test-utils.tsx +26 -7
- package/src/__tests__/useForma.test.ts +244 -73
- package/src/context.ts +3 -1
- package/src/index.ts +6 -1
- package/src/types.ts +58 -14
- package/src/useForma.ts +31 -3
|
@@ -26,7 +26,10 @@ describe("canProceed", () => {
|
|
|
26
26
|
});
|
|
27
27
|
|
|
28
28
|
const { result } = renderHook(() =>
|
|
29
|
-
useForma({
|
|
29
|
+
useForma({
|
|
30
|
+
spec,
|
|
31
|
+
initialData: { name: "John", email: "john@example.com" },
|
|
32
|
+
}),
|
|
30
33
|
);
|
|
31
34
|
|
|
32
35
|
expect(result.current.wizard?.canProceed).toBe(true);
|
|
@@ -38,13 +41,11 @@ describe("canProceed", () => {
|
|
|
38
41
|
name: { type: "text", label: "Name", required: true },
|
|
39
42
|
email: { type: "email", label: "Email", required: true },
|
|
40
43
|
},
|
|
41
|
-
pages: [
|
|
42
|
-
{ id: "page1", title: "Page 1", fields: ["name", "email"] },
|
|
43
|
-
],
|
|
44
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["name", "email"] }],
|
|
44
45
|
});
|
|
45
46
|
|
|
46
|
-
const { result } = renderHook(
|
|
47
|
-
useForma({ spec, initialData: { name: "John" } }) // email is missing
|
|
47
|
+
const { result } = renderHook(
|
|
48
|
+
() => useForma({ spec, initialData: { name: "John" } }), // email is missing
|
|
48
49
|
);
|
|
49
50
|
|
|
50
51
|
expect(result.current.wizard?.canProceed).toBe(false);
|
|
@@ -63,8 +64,8 @@ describe("canProceed", () => {
|
|
|
63
64
|
],
|
|
64
65
|
});
|
|
65
66
|
|
|
66
|
-
const { result } = renderHook(
|
|
67
|
-
useForma({ spec, initialData: { name: "John" } }) // page 2 fields empty
|
|
67
|
+
const { result } = renderHook(
|
|
68
|
+
() => useForma({ spec, initialData: { name: "John" } }), // page 2 fields empty
|
|
68
69
|
);
|
|
69
70
|
|
|
70
71
|
// On page 1, only name is checked (which is filled)
|
|
@@ -84,7 +85,7 @@ describe("canProceed", () => {
|
|
|
84
85
|
});
|
|
85
86
|
|
|
86
87
|
const { result } = renderHook(() =>
|
|
87
|
-
useForma({ spec, initialData: { name: "John" } })
|
|
88
|
+
useForma({ spec, initialData: { name: "John" } }),
|
|
88
89
|
);
|
|
89
90
|
|
|
90
91
|
// Page 1 is valid
|
|
@@ -112,13 +113,11 @@ describe("canProceed", () => {
|
|
|
112
113
|
},
|
|
113
114
|
},
|
|
114
115
|
},
|
|
115
|
-
pages: [
|
|
116
|
-
{ id: "page1", title: "Page 1", fields: ["items"] },
|
|
117
|
-
],
|
|
116
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["items"] }],
|
|
118
117
|
});
|
|
119
118
|
|
|
120
119
|
const { result } = renderHook(() =>
|
|
121
|
-
useForma({ spec, initialData: { items: [] } })
|
|
120
|
+
useForma({ spec, initialData: { items: [] } }),
|
|
122
121
|
);
|
|
123
122
|
|
|
124
123
|
// Array is empty but minItems requires at least 1
|
|
@@ -139,15 +138,24 @@ describe("canProceed", () => {
|
|
|
139
138
|
fields: {
|
|
140
139
|
showEmail: { type: "boolean", label: "Show Email" },
|
|
141
140
|
name: { type: "text", label: "Name", required: true },
|
|
142
|
-
email: {
|
|
141
|
+
email: {
|
|
142
|
+
type: "email",
|
|
143
|
+
label: "Email",
|
|
144
|
+
required: true,
|
|
145
|
+
visibleWhen: "showEmail = true",
|
|
146
|
+
},
|
|
143
147
|
},
|
|
144
148
|
pages: [
|
|
145
|
-
{
|
|
149
|
+
{
|
|
150
|
+
id: "page1",
|
|
151
|
+
title: "Page 1",
|
|
152
|
+
fields: ["showEmail", "name", "email"],
|
|
153
|
+
},
|
|
146
154
|
],
|
|
147
155
|
});
|
|
148
156
|
|
|
149
157
|
const { result } = renderHook(() =>
|
|
150
|
-
useForma({ spec, initialData: { showEmail: false, name: "John" } })
|
|
158
|
+
useForma({ spec, initialData: { showEmail: false, name: "John" } }),
|
|
151
159
|
);
|
|
152
160
|
|
|
153
161
|
// Email is required but hidden, so it shouldn't block progression
|
|
@@ -159,15 +167,24 @@ describe("canProceed", () => {
|
|
|
159
167
|
fields: {
|
|
160
168
|
showEmail: { type: "boolean", label: "Show Email" },
|
|
161
169
|
name: { type: "text", label: "Name", required: true },
|
|
162
|
-
email: {
|
|
170
|
+
email: {
|
|
171
|
+
type: "email",
|
|
172
|
+
label: "Email",
|
|
173
|
+
required: true,
|
|
174
|
+
visibleWhen: "showEmail = true",
|
|
175
|
+
},
|
|
163
176
|
},
|
|
164
177
|
pages: [
|
|
165
|
-
{
|
|
178
|
+
{
|
|
179
|
+
id: "page1",
|
|
180
|
+
title: "Page 1",
|
|
181
|
+
fields: ["showEmail", "name", "email"],
|
|
182
|
+
},
|
|
166
183
|
],
|
|
167
184
|
});
|
|
168
185
|
|
|
169
186
|
const { result } = renderHook(() =>
|
|
170
|
-
useForma({ spec, initialData: { showEmail: false, name: "John" } })
|
|
187
|
+
useForma({ spec, initialData: { showEmail: false, name: "John" } }),
|
|
171
188
|
);
|
|
172
189
|
|
|
173
190
|
// Email is hidden
|
|
@@ -197,13 +214,11 @@ describe("canProceed", () => {
|
|
|
197
214
|
name: { type: "text", label: "Name", required: true },
|
|
198
215
|
age: { type: "number", label: "Age" }, // Not required
|
|
199
216
|
},
|
|
200
|
-
pages: [
|
|
201
|
-
{ id: "page1", title: "Page 1", fields: ["name", "age"] },
|
|
202
|
-
],
|
|
217
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["name", "age"] }],
|
|
203
218
|
});
|
|
204
219
|
|
|
205
|
-
const { result } = renderHook(
|
|
206
|
-
useForma({ spec, initialData: { age: 25 } }) // name missing
|
|
220
|
+
const { result } = renderHook(
|
|
221
|
+
() => useForma({ spec, initialData: { age: 25 } }), // name missing
|
|
207
222
|
);
|
|
208
223
|
|
|
209
224
|
expect(result.current.wizard?.canProceed).toBe(false);
|
|
@@ -219,7 +234,11 @@ describe("canProceed", () => {
|
|
|
219
234
|
const spec = createTestSpec({
|
|
220
235
|
fields: {
|
|
221
236
|
hasSpouse: { type: "boolean", label: "Has Spouse" },
|
|
222
|
-
spouseName: {
|
|
237
|
+
spouseName: {
|
|
238
|
+
type: "text",
|
|
239
|
+
label: "Spouse Name",
|
|
240
|
+
requiredWhen: "hasSpouse = true",
|
|
241
|
+
},
|
|
223
242
|
},
|
|
224
243
|
pages: [
|
|
225
244
|
{ id: "page1", title: "Page 1", fields: ["hasSpouse", "spouseName"] },
|
|
@@ -227,7 +246,7 @@ describe("canProceed", () => {
|
|
|
227
246
|
});
|
|
228
247
|
|
|
229
248
|
const { result } = renderHook(() =>
|
|
230
|
-
useForma({ spec, initialData: { hasSpouse: false } })
|
|
249
|
+
useForma({ spec, initialData: { hasSpouse: false } }),
|
|
231
250
|
);
|
|
232
251
|
|
|
233
252
|
// Spouse name not required when hasSpouse is false
|
|
@@ -258,29 +277,31 @@ describe("canProceed", () => {
|
|
|
258
277
|
// use a validation rule: { rule: "value = true", message: "Must accept terms" }
|
|
259
278
|
const spec = createTestSpec({
|
|
260
279
|
fields: {
|
|
261
|
-
hasPets: {
|
|
280
|
+
hasPets: {
|
|
281
|
+
type: "boolean",
|
|
282
|
+
label: "Do you have pets?",
|
|
283
|
+
required: true,
|
|
284
|
+
},
|
|
262
285
|
},
|
|
263
|
-
pages: [
|
|
264
|
-
{ id: "page1", title: "Page 1", fields: ["hasPets"] },
|
|
265
|
-
],
|
|
286
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["hasPets"] }],
|
|
266
287
|
});
|
|
267
288
|
|
|
268
289
|
// With auto-initialization, boolean defaults to false (a valid value)
|
|
269
290
|
const { result: resultDefault } = renderHook(() =>
|
|
270
|
-
useForma({ spec, initialData: {} })
|
|
291
|
+
useForma({ spec, initialData: {} }),
|
|
271
292
|
);
|
|
272
293
|
expect(resultDefault.current.data.hasPets).toBe(false);
|
|
273
294
|
expect(resultDefault.current.wizard?.canProceed).toBe(true); // false is valid
|
|
274
295
|
|
|
275
296
|
// explicit false should be valid (user answered "no")
|
|
276
297
|
const { result: resultFalse } = renderHook(() =>
|
|
277
|
-
useForma({ spec, initialData: { hasPets: false } })
|
|
298
|
+
useForma({ spec, initialData: { hasPets: false } }),
|
|
278
299
|
);
|
|
279
300
|
expect(resultFalse.current.wizard?.canProceed).toBe(true);
|
|
280
301
|
|
|
281
302
|
// true should be valid (user answered "yes")
|
|
282
303
|
const { result: resultTrue } = renderHook(() =>
|
|
283
|
-
useForma({ spec, initialData: { hasPets: true } })
|
|
304
|
+
useForma({ spec, initialData: { hasPets: true } }),
|
|
284
305
|
);
|
|
285
306
|
expect(resultTrue.current.wizard?.canProceed).toBe(true);
|
|
286
307
|
});
|
|
@@ -298,14 +319,10 @@ describe("canProceed", () => {
|
|
|
298
319
|
],
|
|
299
320
|
},
|
|
300
321
|
},
|
|
301
|
-
pages: [
|
|
302
|
-
{ id: "page1", title: "Page 1", fields: ["country"] },
|
|
303
|
-
],
|
|
322
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["country"] }],
|
|
304
323
|
});
|
|
305
324
|
|
|
306
|
-
const { result } = renderHook(() =>
|
|
307
|
-
useForma({ spec, initialData: {} })
|
|
308
|
-
);
|
|
325
|
+
const { result } = renderHook(() => useForma({ spec, initialData: {} }));
|
|
309
326
|
|
|
310
327
|
expect(result.current.wizard?.canProceed).toBe(false);
|
|
311
328
|
|
|
@@ -323,26 +340,24 @@ describe("canProceed", () => {
|
|
|
323
340
|
fields: {
|
|
324
341
|
name: { type: "text", label: "Name", required: true },
|
|
325
342
|
},
|
|
326
|
-
pages: [
|
|
327
|
-
{ id: "page1", title: "Page 1", fields: ["name"] },
|
|
328
|
-
],
|
|
343
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["name"] }],
|
|
329
344
|
});
|
|
330
345
|
|
|
331
346
|
// Empty string should be invalid
|
|
332
347
|
const { result: resultEmpty } = renderHook(() =>
|
|
333
|
-
useForma({ spec, initialData: { name: "" } })
|
|
348
|
+
useForma({ spec, initialData: { name: "" } }),
|
|
334
349
|
);
|
|
335
350
|
expect(resultEmpty.current.wizard?.canProceed).toBe(false);
|
|
336
351
|
|
|
337
352
|
// Whitespace only should be invalid
|
|
338
353
|
const { result: resultWhitespace } = renderHook(() =>
|
|
339
|
-
useForma({ spec, initialData: { name: " " } })
|
|
354
|
+
useForma({ spec, initialData: { name: " " } }),
|
|
340
355
|
);
|
|
341
356
|
expect(resultWhitespace.current.wizard?.canProceed).toBe(false);
|
|
342
357
|
|
|
343
358
|
// Actual value should be valid
|
|
344
359
|
const { result: resultValid } = renderHook(() =>
|
|
345
|
-
useForma({ spec, initialData: { name: "John" } })
|
|
360
|
+
useForma({ spec, initialData: { name: "John" } }),
|
|
346
361
|
);
|
|
347
362
|
expect(resultValid.current.wizard?.canProceed).toBe(true);
|
|
348
363
|
});
|
|
@@ -352,26 +367,24 @@ describe("canProceed", () => {
|
|
|
352
367
|
fields: {
|
|
353
368
|
age: { type: "number", label: "Age", required: true },
|
|
354
369
|
},
|
|
355
|
-
pages: [
|
|
356
|
-
{ id: "page1", title: "Page 1", fields: ["age"] },
|
|
357
|
-
],
|
|
370
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["age"] }],
|
|
358
371
|
});
|
|
359
372
|
|
|
360
373
|
// null should be invalid
|
|
361
374
|
const { result: resultNull } = renderHook(() =>
|
|
362
|
-
useForma({ spec, initialData: { age: null } })
|
|
375
|
+
useForma({ spec, initialData: { age: null } }),
|
|
363
376
|
);
|
|
364
377
|
expect(resultNull.current.wizard?.canProceed).toBe(false);
|
|
365
378
|
|
|
366
379
|
// undefined should be invalid
|
|
367
380
|
const { result: resultUndefined } = renderHook(() =>
|
|
368
|
-
useForma({ spec, initialData: {} })
|
|
381
|
+
useForma({ spec, initialData: {} }),
|
|
369
382
|
);
|
|
370
383
|
expect(resultUndefined.current.wizard?.canProceed).toBe(false);
|
|
371
384
|
|
|
372
385
|
// 0 should be valid (it's a real number)
|
|
373
386
|
const { result: resultZero } = renderHook(() =>
|
|
374
|
-
useForma({ spec, initialData: { age: 0 } })
|
|
387
|
+
useForma({ spec, initialData: { age: 0 } }),
|
|
375
388
|
);
|
|
376
389
|
expect(resultZero.current.wizard?.canProceed).toBe(true);
|
|
377
390
|
});
|
|
@@ -388,26 +401,27 @@ describe("canProceed", () => {
|
|
|
388
401
|
},
|
|
389
402
|
},
|
|
390
403
|
},
|
|
391
|
-
pages: [
|
|
392
|
-
{ id: "page1", title: "Page 1", fields: ["items"] },
|
|
393
|
-
],
|
|
404
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["items"] }],
|
|
394
405
|
});
|
|
395
406
|
|
|
396
407
|
// Empty array with minItems > 0 should be invalid
|
|
397
408
|
const { result: resultEmpty } = renderHook(() =>
|
|
398
|
-
useForma({ spec, initialData: { items: [] } })
|
|
409
|
+
useForma({ spec, initialData: { items: [] } }),
|
|
399
410
|
);
|
|
400
411
|
expect(resultEmpty.current.wizard?.canProceed).toBe(false);
|
|
401
412
|
|
|
402
413
|
// 1 item but minItems is 2
|
|
403
414
|
const { result: resultOne } = renderHook(() =>
|
|
404
|
-
useForma({ spec, initialData: { items: [{ name: "Item 1" }] } })
|
|
415
|
+
useForma({ spec, initialData: { items: [{ name: "Item 1" }] } }),
|
|
405
416
|
);
|
|
406
417
|
expect(resultOne.current.wizard?.canProceed).toBe(false);
|
|
407
418
|
|
|
408
419
|
// 2 items should be valid
|
|
409
420
|
const { result: resultTwo } = renderHook(() =>
|
|
410
|
-
useForma({
|
|
421
|
+
useForma({
|
|
422
|
+
spec,
|
|
423
|
+
initialData: { items: [{ name: "Item 1" }, { name: "Item 2" }] },
|
|
424
|
+
}),
|
|
411
425
|
);
|
|
412
426
|
expect(resultTwo.current.wizard?.canProceed).toBe(true);
|
|
413
427
|
});
|
|
@@ -425,9 +439,7 @@ describe("canProceed", () => {
|
|
|
425
439
|
],
|
|
426
440
|
});
|
|
427
441
|
|
|
428
|
-
const { result } = renderHook(() =>
|
|
429
|
-
useForma({ spec, initialData: {} })
|
|
430
|
-
);
|
|
442
|
+
const { result } = renderHook(() => useForma({ spec, initialData: {} }));
|
|
431
443
|
|
|
432
444
|
// Empty page should allow progression
|
|
433
445
|
expect(result.current.wizard?.canProceed).toBe(true);
|
|
@@ -437,16 +449,30 @@ describe("canProceed", () => {
|
|
|
437
449
|
const spec = createTestSpec({
|
|
438
450
|
fields: {
|
|
439
451
|
showFields: { type: "boolean", label: "Show Fields" },
|
|
440
|
-
name: {
|
|
441
|
-
|
|
452
|
+
name: {
|
|
453
|
+
type: "text",
|
|
454
|
+
label: "Name",
|
|
455
|
+
required: true,
|
|
456
|
+
visibleWhen: "showFields = true",
|
|
457
|
+
},
|
|
458
|
+
email: {
|
|
459
|
+
type: "email",
|
|
460
|
+
label: "Email",
|
|
461
|
+
required: true,
|
|
462
|
+
visibleWhen: "showFields = true",
|
|
463
|
+
},
|
|
442
464
|
},
|
|
443
465
|
pages: [
|
|
444
|
-
{
|
|
466
|
+
{
|
|
467
|
+
id: "page1",
|
|
468
|
+
title: "Page 1",
|
|
469
|
+
fields: ["showFields", "name", "email"],
|
|
470
|
+
},
|
|
445
471
|
],
|
|
446
472
|
});
|
|
447
473
|
|
|
448
474
|
const { result } = renderHook(() =>
|
|
449
|
-
useForma({ spec, initialData: { showFields: false } })
|
|
475
|
+
useForma({ spec, initialData: { showFields: false } }),
|
|
450
476
|
);
|
|
451
477
|
|
|
452
478
|
// All required fields are hidden, only showFields is visible (not required)
|
|
@@ -467,8 +493,8 @@ describe("canProceed", () => {
|
|
|
467
493
|
],
|
|
468
494
|
});
|
|
469
495
|
|
|
470
|
-
const { result } = renderHook(
|
|
471
|
-
useForma({ spec, initialData: { name: "John" } }) // Only page 1 is valid
|
|
496
|
+
const { result } = renderHook(
|
|
497
|
+
() => useForma({ spec, initialData: { name: "John" } }), // Only page 1 is valid
|
|
472
498
|
);
|
|
473
499
|
|
|
474
500
|
// Page 1 should be valid
|
|
@@ -500,7 +526,7 @@ describe("canProceed", () => {
|
|
|
500
526
|
});
|
|
501
527
|
|
|
502
528
|
const { result } = renderHook(() =>
|
|
503
|
-
useForma({ spec, initialData: { price: 10, quantity: 2 } })
|
|
529
|
+
useForma({ spec, initialData: { price: 10, quantity: 2 } }),
|
|
504
530
|
);
|
|
505
531
|
|
|
506
532
|
// Computed fields don't block - only real fields do
|
|
@@ -515,14 +541,10 @@ describe("canProceed", () => {
|
|
|
515
541
|
fields: {
|
|
516
542
|
name: { type: "text", label: "Name", required: true },
|
|
517
543
|
},
|
|
518
|
-
pages: [
|
|
519
|
-
{ id: "page1", title: "Page 1", fields: ["name"] },
|
|
520
|
-
],
|
|
544
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["name"] }],
|
|
521
545
|
});
|
|
522
546
|
|
|
523
|
-
const { result } = renderHook(() =>
|
|
524
|
-
useForma({ spec, initialData: {} })
|
|
525
|
-
);
|
|
547
|
+
const { result } = renderHook(() => useForma({ spec, initialData: {} }));
|
|
526
548
|
|
|
527
549
|
// Both should return the same result
|
|
528
550
|
expect(result.current.wizard?.canProceed).toBe(false);
|
|
@@ -543,13 +565,11 @@ describe("canProceed", () => {
|
|
|
543
565
|
name: { type: "text", label: "Name", required: true },
|
|
544
566
|
email: { type: "email", label: "Email", required: true },
|
|
545
567
|
},
|
|
546
|
-
pages: [
|
|
547
|
-
{ id: "page1", title: "Page 1", fields: ["name", "email"] },
|
|
548
|
-
],
|
|
568
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["name", "email"] }],
|
|
549
569
|
});
|
|
550
570
|
|
|
551
571
|
const { result } = renderHook(() =>
|
|
552
|
-
useForma({ spec, initialData: {}, validateOn: "blur" })
|
|
572
|
+
useForma({ spec, initialData: {}, validateOn: "blur" }),
|
|
553
573
|
);
|
|
554
574
|
|
|
555
575
|
// Fields not touched yet - errors exist but not visible to user
|
|
@@ -574,14 +594,10 @@ describe("canProceed", () => {
|
|
|
574
594
|
fields: {
|
|
575
595
|
name: { type: "text", label: "Name", required: true },
|
|
576
596
|
},
|
|
577
|
-
pages: [
|
|
578
|
-
{ id: "page1", title: "Page 1", fields: ["name"] },
|
|
579
|
-
],
|
|
597
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["name"] }],
|
|
580
598
|
});
|
|
581
599
|
|
|
582
|
-
const { result } = renderHook(() =>
|
|
583
|
-
useForma({ spec, initialData: {} })
|
|
584
|
-
);
|
|
600
|
+
const { result } = renderHook(() => useForma({ spec, initialData: {} }));
|
|
585
601
|
|
|
586
602
|
expect(result.current.wizard?.canProceed).toBe(false);
|
|
587
603
|
|
|
@@ -606,13 +622,15 @@ describe("canProceed", () => {
|
|
|
606
622
|
email: { type: "email", label: "Email", required: true },
|
|
607
623
|
},
|
|
608
624
|
pages: [
|
|
609
|
-
{
|
|
625
|
+
{
|
|
626
|
+
id: "page1",
|
|
627
|
+
title: "Page 1",
|
|
628
|
+
fields: ["firstName", "lastName", "email"],
|
|
629
|
+
},
|
|
610
630
|
],
|
|
611
631
|
});
|
|
612
632
|
|
|
613
|
-
const { result } = renderHook(() =>
|
|
614
|
-
useForma({ spec, initialData: {} })
|
|
615
|
-
);
|
|
633
|
+
const { result } = renderHook(() => useForma({ spec, initialData: {} }));
|
|
616
634
|
|
|
617
635
|
expect(result.current.wizard?.canProceed).toBe(false);
|
|
618
636
|
|
|
@@ -644,18 +662,18 @@ describe("canProceed", () => {
|
|
|
644
662
|
fields: {
|
|
645
663
|
name: { type: "text", label: "Name", required: true },
|
|
646
664
|
},
|
|
647
|
-
pages: [
|
|
648
|
-
{ id: "page1", title: "Page 1", fields: ["name"] },
|
|
649
|
-
],
|
|
665
|
+
pages: [{ id: "page1", title: "Page 1", fields: ["name"] }],
|
|
650
666
|
});
|
|
651
667
|
|
|
652
668
|
const { result } = renderHook(() =>
|
|
653
|
-
useForma({ spec, initialData: { name: "John" } })
|
|
669
|
+
useForma({ spec, initialData: { name: "John" } }),
|
|
654
670
|
);
|
|
655
671
|
|
|
656
672
|
// No errors - should be able to proceed
|
|
657
673
|
expect(result.current.wizard?.canProceed).toBe(true);
|
|
658
|
-
expect(
|
|
674
|
+
expect(
|
|
675
|
+
result.current.errors.filter((e) => e.severity === "error"),
|
|
676
|
+
).toHaveLength(0);
|
|
659
677
|
});
|
|
660
678
|
});
|
|
661
679
|
|
|
@@ -669,12 +687,17 @@ describe("canProceed", () => {
|
|
|
669
687
|
},
|
|
670
688
|
pages: [
|
|
671
689
|
{ id: "page1", title: "Page 1", fields: ["showPage2", "page1Field"] },
|
|
672
|
-
{
|
|
690
|
+
{
|
|
691
|
+
id: "page2",
|
|
692
|
+
title: "Page 2",
|
|
693
|
+
fields: ["page2Field"],
|
|
694
|
+
visibleWhen: "showPage2 = true",
|
|
695
|
+
},
|
|
673
696
|
],
|
|
674
697
|
});
|
|
675
698
|
|
|
676
699
|
const { result } = renderHook(() =>
|
|
677
|
-
useForma({ spec, initialData: { showPage2: true } })
|
|
700
|
+
useForma({ spec, initialData: { showPage2: true } }),
|
|
678
701
|
);
|
|
679
702
|
|
|
680
703
|
// Navigate to page 2
|
|
@@ -703,14 +726,23 @@ describe("canProceed", () => {
|
|
|
703
726
|
page3Field: { type: "text", label: "Page 3 Field" },
|
|
704
727
|
},
|
|
705
728
|
pages: [
|
|
706
|
-
{
|
|
707
|
-
|
|
729
|
+
{
|
|
730
|
+
id: "page1",
|
|
731
|
+
title: "Page 1",
|
|
732
|
+
fields: ["skipMiddle", "page1Field"],
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
id: "page2",
|
|
736
|
+
title: "Page 2",
|
|
737
|
+
fields: ["page2Field"],
|
|
738
|
+
visibleWhen: "skipMiddle = false",
|
|
739
|
+
},
|
|
708
740
|
{ id: "page3", title: "Page 3", fields: ["page3Field"] },
|
|
709
741
|
],
|
|
710
742
|
});
|
|
711
743
|
|
|
712
744
|
const { result } = renderHook(() =>
|
|
713
|
-
useForma({ spec, initialData: { skipMiddle: true } })
|
|
745
|
+
useForma({ spec, initialData: { skipMiddle: true } }),
|
|
714
746
|
);
|
|
715
747
|
|
|
716
748
|
// With skipMiddle=true, page2 is hidden
|
|
@@ -734,13 +766,22 @@ describe("canProceed", () => {
|
|
|
734
766
|
optionalField: { type: "text", label: "Optional" },
|
|
735
767
|
},
|
|
736
768
|
pages: [
|
|
737
|
-
{
|
|
738
|
-
|
|
769
|
+
{
|
|
770
|
+
id: "main",
|
|
771
|
+
title: "Main",
|
|
772
|
+
fields: ["showOptional", "requiredField"],
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
id: "optional",
|
|
776
|
+
title: "Optional",
|
|
777
|
+
fields: ["optionalField"],
|
|
778
|
+
visibleWhen: "showOptional = true",
|
|
779
|
+
},
|
|
739
780
|
],
|
|
740
781
|
});
|
|
741
782
|
|
|
742
783
|
const { result } = renderHook(() =>
|
|
743
|
-
useForma({ spec, initialData: { showOptional: false } })
|
|
784
|
+
useForma({ spec, initialData: { showOptional: false } }),
|
|
744
785
|
);
|
|
745
786
|
|
|
746
787
|
// All pages are returned
|