@fogpipe/forma-react 0.12.0 → 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.
@@ -38,14 +38,143 @@ describe("useForma", () => {
38
38
  });
39
39
 
40
40
  const initialData = { name: "John", age: 25 };
41
- const { result } = renderHook(() =>
42
- useForma({ spec, initialData })
43
- );
41
+ const { result } = renderHook(() => useForma({ spec, initialData }));
44
42
 
45
43
  expect(result.current.data).toEqual(initialData);
46
44
  expect(result.current.isDirty).toBe(false);
47
45
  });
48
46
 
47
+ it("should initialize with defaultValue from field definitions", () => {
48
+ const spec = createTestSpec({
49
+ fields: {
50
+ country: {
51
+ type: "select",
52
+ defaultValue: "us",
53
+ options: [
54
+ { value: "us", label: "US" },
55
+ { value: "ca", label: "CA" },
56
+ ],
57
+ },
58
+ age: { type: "number", defaultValue: 25 },
59
+ name: { type: "text" },
60
+ },
61
+ });
62
+
63
+ const { result } = renderHook(() => useForma({ spec }));
64
+
65
+ expect(result.current.data.country).toBe("us");
66
+ expect(result.current.data.age).toBe(25);
67
+ expect(result.current.data.name).toBeUndefined();
68
+ });
69
+
70
+ it("should let initialData override defaultValue", () => {
71
+ const spec = createTestSpec({
72
+ fields: {
73
+ country: {
74
+ type: "select",
75
+ defaultValue: "us",
76
+ options: [
77
+ { value: "us", label: "US" },
78
+ { value: "ca", label: "CA" },
79
+ ],
80
+ },
81
+ },
82
+ });
83
+
84
+ const { result } = renderHook(() =>
85
+ useForma({ spec, initialData: { country: "ca" } }),
86
+ );
87
+
88
+ expect(result.current.data.country).toBe("ca");
89
+ });
90
+
91
+ it("should let defaultValue=true override implicit boolean false", () => {
92
+ const spec = createTestSpec({
93
+ fields: {
94
+ agree: { type: "boolean", defaultValue: true },
95
+ optIn: { type: "boolean" },
96
+ },
97
+ });
98
+
99
+ const { result } = renderHook(() => useForma({ spec }));
100
+
101
+ expect(result.current.data.agree).toBe(true);
102
+ expect(result.current.data.optIn).toBe(false);
103
+ });
104
+
105
+ it("should apply defaultValue for number and string fields", () => {
106
+ const spec = createTestSpec({
107
+ fields: {
108
+ quantity: { type: "integer", defaultValue: 5 },
109
+ price: { type: "number", defaultValue: 9.99 },
110
+ notes: { type: "textarea", defaultValue: "N/A" },
111
+ },
112
+ });
113
+
114
+ const { result } = renderHook(() => useForma({ spec }));
115
+
116
+ expect(result.current.data.quantity).toBe(5);
117
+ expect(result.current.data.price).toBe(9.99);
118
+ expect(result.current.data.notes).toBe("N/A");
119
+ });
120
+
121
+ it("should not apply defaultValue for display fields in data", () => {
122
+ const spec = createTestSpec({
123
+ fields: {
124
+ name: { type: "text", defaultValue: "John" },
125
+ header: { type: "display", content: "Header" },
126
+ },
127
+ });
128
+
129
+ const { result } = renderHook(() => useForma({ spec }));
130
+
131
+ expect(result.current.data.name).toBe("John");
132
+ // display fields don't produce data entries
133
+ expect(result.current.data.header).toBeUndefined();
134
+ });
135
+
136
+ it("should preserve defaultValue after resetForm", () => {
137
+ const spec = createTestSpec({
138
+ fields: {
139
+ name: { type: "text", defaultValue: "Default" },
140
+ },
141
+ });
142
+
143
+ const { result } = renderHook(() => useForma({ spec }));
144
+
145
+ expect(result.current.data.name).toBe("Default");
146
+
147
+ act(() => {
148
+ result.current.setFieldValue("name", "Changed");
149
+ });
150
+ expect(result.current.data.name).toBe("Changed");
151
+
152
+ act(() => {
153
+ result.current.resetForm();
154
+ });
155
+ expect(result.current.data.name).toBe("Default");
156
+ });
157
+
158
+ it("should apply defaultValue for multiselect as array", () => {
159
+ const spec = createTestSpec({
160
+ fields: {
161
+ tags: {
162
+ type: "multiselect",
163
+ defaultValue: ["a", "b"],
164
+ options: [
165
+ { value: "a", label: "A" },
166
+ { value: "b", label: "B" },
167
+ { value: "c", label: "C" },
168
+ ],
169
+ },
170
+ },
171
+ });
172
+
173
+ const { result } = renderHook(() => useForma({ spec }));
174
+
175
+ expect(result.current.data.tags).toEqual(["a", "b"]);
176
+ });
177
+
49
178
  it("should merge referenceData from options with spec", () => {
50
179
  const spec = createTestSpec({
51
180
  fields: { value: { type: "number" } },
@@ -56,7 +185,7 @@ describe("useForma", () => {
56
185
  useForma({
57
186
  spec,
58
187
  referenceData: { added: { b: 2 } },
59
- })
188
+ }),
60
189
  );
61
190
 
62
191
  expect(result.current.spec.referenceData).toEqual({
@@ -127,7 +256,7 @@ describe("useForma", () => {
127
256
  });
128
257
 
129
258
  const { result } = renderHook(() =>
130
- useForma({ spec, initialData: { items: [{ name: "A" }] } })
259
+ useForma({ spec, initialData: { items: [{ name: "A" }] } }),
131
260
  );
132
261
 
133
262
  act(() => {
@@ -172,7 +301,7 @@ describe("useForma", () => {
172
301
  });
173
302
 
174
303
  const { result } = renderHook(() =>
175
- useForma({ spec, initialData: { name: "Test" } })
304
+ useForma({ spec, initialData: { name: "Test" } }),
176
305
  );
177
306
 
178
307
  const props = result.current.getFieldProps("name");
@@ -295,7 +424,7 @@ describe("useForma", () => {
295
424
  });
296
425
 
297
426
  const { result } = renderHook(() =>
298
- useForma({ spec, initialData: { tags: ["a", "b"] } })
427
+ useForma({ spec, initialData: { tags: ["a", "b"] } }),
299
428
  );
300
429
 
301
430
  const props = result.current.getSelectFieldProps("tags");
@@ -322,7 +451,7 @@ describe("useForma", () => {
322
451
  });
323
452
 
324
453
  const { result } = renderHook(() =>
325
- useForma({ spec, initialData: { hasLicense: false } })
454
+ useForma({ spec, initialData: { hasLicense: false } }),
326
455
  );
327
456
 
328
457
  // Initially hidden
@@ -348,7 +477,7 @@ describe("useForma", () => {
348
477
  });
349
478
 
350
479
  const { result } = renderHook(() =>
351
- useForma({ spec, initialData: { age: 14 } })
480
+ useForma({ spec, initialData: { age: 14 } }),
352
481
  );
353
482
 
354
483
  expect(result.current.visibility.canDrive).toBe(false);
@@ -378,7 +507,7 @@ describe("useForma", () => {
378
507
  });
379
508
 
380
509
  const { result } = renderHook(() =>
381
- useForma({ spec, initialData: { employmentStatus: "unemployed" } })
510
+ useForma({ spec, initialData: { employmentStatus: "unemployed" } }),
382
511
  );
383
512
 
384
513
  expect(result.current.getFieldProps("employerName").required).toBe(false);
@@ -408,7 +537,7 @@ describe("useForma", () => {
408
537
  });
409
538
 
410
539
  const { result } = renderHook(() =>
411
- useForma({ spec, initialData: { isEditable: false } })
540
+ useForma({ spec, initialData: { isEditable: false } }),
412
541
  );
413
542
 
414
543
  expect(result.current.getFieldProps("notes").enabled).toBe(false);
@@ -438,7 +567,7 @@ describe("useForma", () => {
438
567
  });
439
568
 
440
569
  const { result } = renderHook(() =>
441
- useForma({ spec, initialData: { quantity: 5, price: 10 } })
570
+ useForma({ spec, initialData: { quantity: 5, price: 10 } }),
442
571
  );
443
572
 
444
573
  expect(result.current.computed.total).toBe(50);
@@ -456,7 +585,7 @@ describe("useForma", () => {
456
585
  });
457
586
 
458
587
  const { result } = renderHook(() =>
459
- useForma({ spec, initialData: { a: 1, b: 2 } })
588
+ useForma({ spec, initialData: { a: 1, b: 2 } }),
460
589
  );
461
590
 
462
591
  expect(result.current.computed.sum).toBe(3);
@@ -504,7 +633,7 @@ describe("useForma", () => {
504
633
  });
505
634
 
506
635
  const { result } = renderHook(() =>
507
- useForma({ spec, validateOn: "blur" })
636
+ useForma({ spec, validateOn: "blur" }),
508
637
  );
509
638
 
510
639
  // Errors exist but not shown
@@ -520,11 +649,13 @@ describe("useForma", () => {
520
649
  });
521
650
 
522
651
  const { result } = renderHook(() =>
523
- useForma({ spec, validateOn: "change" })
652
+ useForma({ spec, validateOn: "change" }),
524
653
  );
525
654
 
526
655
  // Errors shown immediately
527
- expect(result.current.getFieldProps("name").errors.length).toBeGreaterThan(0);
656
+ expect(
657
+ result.current.getFieldProps("name").errors.length,
658
+ ).toBeGreaterThan(0);
528
659
  });
529
660
 
530
661
  it("should validate custom validation rules", () => {
@@ -540,7 +671,7 @@ describe("useForma", () => {
540
671
  });
541
672
 
542
673
  const { result } = renderHook(() =>
543
- useForma({ spec, initialData: { age: 16 } })
674
+ useForma({ spec, initialData: { age: 16 } }),
544
675
  );
545
676
 
546
677
  // Touch the field to show errors
@@ -549,7 +680,9 @@ describe("useForma", () => {
549
680
  });
550
681
 
551
682
  const errors = result.current.getFieldProps("age").errors;
552
- expect(errors.some((e) => e.message === "Must be 18 or older")).toBe(true);
683
+ expect(errors.some((e) => e.message === "Must be 18 or older")).toBe(
684
+ true,
685
+ );
553
686
  });
554
687
 
555
688
  it("should clear isSubmitted when data changes", () => {
@@ -583,7 +716,7 @@ describe("useForma", () => {
583
716
  });
584
717
 
585
718
  const { result } = renderHook(() =>
586
- useForma({ spec, validationDebounceMs: 100 })
719
+ useForma({ spec, validationDebounceMs: 100 }),
587
720
  );
588
721
 
589
722
  // Initially invalid (required field empty)
@@ -619,7 +752,7 @@ describe("useForma", () => {
619
752
  });
620
753
 
621
754
  const { result } = renderHook(() =>
622
- useForma({ spec, validationDebounceMs: 500, onSubmit })
755
+ useForma({ spec, validationDebounceMs: 500, onSubmit }),
623
756
  );
624
757
 
625
758
  // Fill the field
@@ -647,7 +780,7 @@ describe("useForma", () => {
647
780
  });
648
781
 
649
782
  const { result } = renderHook(() =>
650
- useForma({ spec, validationDebounceMs: 100, onSubmit })
783
+ useForma({ spec, validationDebounceMs: 100, onSubmit }),
651
784
  );
652
785
 
653
786
  // Submit without filling required field
@@ -667,7 +800,7 @@ describe("useForma", () => {
667
800
  });
668
801
 
669
802
  const { result } = renderHook(() =>
670
- useForma({ spec, validationDebounceMs: 0 })
803
+ useForma({ spec, validationDebounceMs: 0 }),
671
804
  );
672
805
 
673
806
  expect(result.current.isValid).toBe(false);
@@ -698,7 +831,7 @@ describe("useForma", () => {
698
831
  });
699
832
 
700
833
  const { result } = renderHook(() =>
701
- useForma({ spec, initialData: { items: [] } })
834
+ useForma({ spec, initialData: { items: [] } }),
702
835
  );
703
836
 
704
837
  const helpers = result.current.getArrayHelpers("items");
@@ -718,7 +851,7 @@ describe("useForma", () => {
718
851
  });
719
852
 
720
853
  const { result } = renderHook(() =>
721
- useForma({ spec, initialData: { items: [] } })
854
+ useForma({ spec, initialData: { items: [] } }),
722
855
  );
723
856
 
724
857
  act(() => {
@@ -737,7 +870,7 @@ describe("useForma", () => {
737
870
  useForma({
738
871
  spec,
739
872
  initialData: { items: [{ name: "A" }, { name: "B" }, { name: "C" }] },
740
- })
873
+ }),
741
874
  );
742
875
 
743
876
  act(() => {
@@ -756,7 +889,7 @@ describe("useForma", () => {
756
889
  useForma({
757
890
  spec,
758
891
  initialData: { items: [{ name: "A" }, { name: "B" }, { name: "C" }] },
759
- })
892
+ }),
760
893
  );
761
894
 
762
895
  act(() => {
@@ -779,7 +912,7 @@ describe("useForma", () => {
779
912
  useForma({
780
913
  spec,
781
914
  initialData: { items: [{ name: "A" }, { name: "B" }] },
782
- })
915
+ }),
783
916
  );
784
917
 
785
918
  act(() => {
@@ -798,7 +931,7 @@ describe("useForma", () => {
798
931
  useForma({
799
932
  spec,
800
933
  initialData: { items: [{ name: "A" }, { name: "C" }] },
801
- })
934
+ }),
802
935
  );
803
936
 
804
937
  act(() => {
@@ -823,7 +956,7 @@ describe("useForma", () => {
823
956
  useForma({
824
957
  spec,
825
958
  initialData: { items: [{ name: "Only" }] },
826
- })
959
+ }),
827
960
  );
828
961
 
829
962
  const helpers = result.current.getArrayHelpers("items");
@@ -849,7 +982,7 @@ describe("useForma", () => {
849
982
  useForma({
850
983
  spec,
851
984
  initialData: { items: [{ name: "A" }, { name: "B" }] },
852
- })
985
+ }),
853
986
  );
854
987
 
855
988
  const helpers = result.current.getArrayHelpers("items");
@@ -880,10 +1013,12 @@ describe("useForma", () => {
880
1013
  useForma({
881
1014
  spec,
882
1015
  initialData: { items: [{ name: "Test Item" }] },
883
- })
1016
+ }),
884
1017
  );
885
1018
 
886
- const itemProps = result.current.getArrayHelpers("items").getItemFieldProps(0, "name");
1019
+ const itemProps = result.current
1020
+ .getArrayHelpers("items")
1021
+ .getItemFieldProps(0, "name");
887
1022
 
888
1023
  expect(itemProps.name).toBe("items[0].name");
889
1024
  expect(itemProps.value).toBe("Test Item");
@@ -1022,12 +1157,17 @@ describe("useForma", () => {
1022
1157
  },
1023
1158
  pages: [
1024
1159
  { id: "page1", title: "Step 1", fields: ["showPage2", "field1"] },
1025
- { id: "page2", title: "Step 2", fields: ["field2"], visibleWhen: "showPage2 = true" },
1160
+ {
1161
+ id: "page2",
1162
+ title: "Step 2",
1163
+ fields: ["field2"],
1164
+ visibleWhen: "showPage2 = true",
1165
+ },
1026
1166
  ],
1027
1167
  });
1028
1168
 
1029
1169
  const { result } = renderHook(() =>
1030
- useForma({ spec, initialData: { showPage2: false } })
1170
+ useForma({ spec, initialData: { showPage2: false } }),
1031
1171
  );
1032
1172
 
1033
1173
  // Page 2 should be hidden
@@ -1039,7 +1179,9 @@ describe("useForma", () => {
1039
1179
  result.current.setFieldValue("showPage2", true);
1040
1180
  });
1041
1181
 
1042
- const page2After = result.current.wizard?.pages.find((p) => p.id === "page2");
1182
+ const page2After = result.current.wizard?.pages.find(
1183
+ (p) => p.id === "page2",
1184
+ );
1043
1185
  expect(page2After?.visible).toBe(true);
1044
1186
  });
1045
1187
 
@@ -1058,7 +1200,7 @@ describe("useForma", () => {
1058
1200
  });
1059
1201
 
1060
1202
  const { result } = renderHook(() =>
1061
- useForma({ spec, initialData: { name: "Test" }, onSubmit })
1203
+ useForma({ spec, initialData: { name: "Test" }, onSubmit }),
1062
1204
  );
1063
1205
 
1064
1206
  await act(async () => {
@@ -1074,9 +1216,7 @@ describe("useForma", () => {
1074
1216
  fields: { name: { type: "text", required: true } },
1075
1217
  });
1076
1218
 
1077
- const { result } = renderHook(() =>
1078
- useForma({ spec, onSubmit })
1079
- );
1219
+ const { result } = renderHook(() => useForma({ spec, onSubmit }));
1080
1220
 
1081
1221
  await act(async () => {
1082
1222
  await result.current.submitForm();
@@ -1088,14 +1228,14 @@ describe("useForma", () => {
1088
1228
 
1089
1229
  it("should track isSubmitting state during async submit", async () => {
1090
1230
  const onSubmit = vi.fn(
1091
- (): Promise<void> => new Promise((resolve) => setTimeout(resolve, 100))
1231
+ (): Promise<void> => new Promise((resolve) => setTimeout(resolve, 100)),
1092
1232
  );
1093
1233
  const spec = createTestSpec({
1094
1234
  fields: { name: { type: "text" } },
1095
1235
  });
1096
1236
 
1097
1237
  const { result } = renderHook(() =>
1098
- useForma({ spec, initialData: { name: "Test" }, onSubmit })
1238
+ useForma({ spec, initialData: { name: "Test" }, onSubmit }),
1099
1239
  );
1100
1240
 
1101
1241
  let submitPromise: Promise<void>;
@@ -1118,7 +1258,7 @@ describe("useForma", () => {
1118
1258
  });
1119
1259
 
1120
1260
  const { result } = renderHook(() =>
1121
- useForma({ spec, initialData: { name: "Original" } })
1261
+ useForma({ spec, initialData: { name: "Original" } }),
1122
1262
  );
1123
1263
 
1124
1264
  act(() => {
@@ -1144,9 +1284,7 @@ describe("useForma", () => {
1144
1284
  fields: { name: { type: "text" } },
1145
1285
  });
1146
1286
 
1147
- const { result } = renderHook(() =>
1148
- useForma({ spec, onChange })
1149
- );
1287
+ const { result } = renderHook(() => useForma({ spec, onChange }));
1150
1288
 
1151
1289
  act(() => {
1152
1290
  result.current.setFieldValue("name", "New Value");
@@ -1154,7 +1292,7 @@ describe("useForma", () => {
1154
1292
 
1155
1293
  expect(onChange).toHaveBeenCalledWith(
1156
1294
  { name: "New Value" },
1157
- expect.any(Object) // computed values
1295
+ expect.any(Object), // computed values
1158
1296
  );
1159
1297
  });
1160
1298
 
@@ -1165,7 +1303,7 @@ describe("useForma", () => {
1165
1303
  });
1166
1304
 
1167
1305
  renderHook(() =>
1168
- useForma({ spec, initialData: { name: "Initial" }, onChange })
1306
+ useForma({ spec, initialData: { name: "Initial" }, onChange }),
1169
1307
  );
1170
1308
 
1171
1309
  expect(onChange).not.toHaveBeenCalled();
@@ -1197,7 +1335,7 @@ describe("useForma", () => {
1197
1335
  });
1198
1336
 
1199
1337
  const { result } = renderHook(() =>
1200
- useForma({ spec, initialData: { acceptTerms: true } })
1338
+ useForma({ spec, initialData: { acceptTerms: true } }),
1201
1339
  );
1202
1340
 
1203
1341
  expect(result.current.data.acceptTerms).toBe(true);
@@ -1226,7 +1364,9 @@ describe("useForma", () => {
1226
1364
  type: "boolean",
1227
1365
  label: "I accept the terms",
1228
1366
  required: true,
1229
- validations: [{ rule: "value = true", message: "You must accept the terms" }],
1367
+ validations: [
1368
+ { rule: "value = true", message: "You must accept the terms" },
1369
+ ],
1230
1370
  },
1231
1371
  },
1232
1372
  });
@@ -1332,12 +1472,14 @@ describe("useForma", () => {
1332
1472
  });
1333
1473
 
1334
1474
  const { result } = renderHook(() =>
1335
- useForma({ spec, initialData: { age: -5 } })
1475
+ useForma({ spec, initialData: { age: -5 } }),
1336
1476
  );
1337
1477
 
1338
1478
  const fieldErrors = result.current.validateField("age");
1339
1479
 
1340
- expect(fieldErrors.some((e) => e.message === "Must be positive")).toBe(true);
1480
+ expect(fieldErrors.some((e) => e.message === "Must be positive")).toBe(
1481
+ true,
1482
+ );
1341
1483
  });
1342
1484
  });
1343
1485
 
@@ -1360,7 +1502,7 @@ describe("useForma", () => {
1360
1502
  });
1361
1503
 
1362
1504
  const { result } = renderHook(() =>
1363
- useForma({ spec, initialData: { name: "", items: [{ title: "" }] } })
1505
+ useForma({ spec, initialData: { name: "", items: [{ title: "" }] } }),
1364
1506
  );
1365
1507
 
1366
1508
  // Edit root field
@@ -1378,7 +1520,9 @@ describe("useForma", () => {
1378
1520
 
1379
1521
  // Both values should be preserved
1380
1522
  expect(result.current.data.name).toBe("John");
1381
- expect((result.current.data.items as Array<{ title: string }>)[0].title).toBe("First Item");
1523
+ expect(
1524
+ (result.current.data.items as Array<{ title: string }>)[0].title,
1525
+ ).toBe("First Item");
1382
1526
  });
1383
1527
 
1384
1528
  it("should preserve array item changes when editing root fields", () => {
@@ -1393,7 +1537,7 @@ describe("useForma", () => {
1393
1537
  });
1394
1538
 
1395
1539
  const { result } = renderHook(() =>
1396
- useForma({ spec, initialData: { name: "", items: [{ title: "" }] } })
1540
+ useForma({ spec, initialData: { name: "", items: [{ title: "" }] } }),
1397
1541
  );
1398
1542
 
1399
1543
  // Edit array item field first
@@ -1402,7 +1546,9 @@ describe("useForma", () => {
1402
1546
  const itemProps = helpers.getItemFieldProps(0, "title");
1403
1547
  itemProps.onChange("First Item");
1404
1548
  });
1405
- expect((result.current.data.items as Array<{ title: string }>)[0].title).toBe("First Item");
1549
+ expect(
1550
+ (result.current.data.items as Array<{ title: string }>)[0].title,
1551
+ ).toBe("First Item");
1406
1552
 
1407
1553
  // Now edit root field
1408
1554
  act(() => {
@@ -1411,7 +1557,9 @@ describe("useForma", () => {
1411
1557
 
1412
1558
  // Both values should be preserved
1413
1559
  expect(result.current.data.name).toBe("John");
1414
- expect((result.current.data.items as Array<{ title: string }>)[0].title).toBe("First Item");
1560
+ expect(
1561
+ (result.current.data.items as Array<{ title: string }>)[0].title,
1562
+ ).toBe("First Item");
1415
1563
  });
1416
1564
 
1417
1565
  it("should preserve data when alternating between root and array item edits", () => {
@@ -1435,9 +1583,12 @@ describe("useForma", () => {
1435
1583
  initialData: {
1436
1584
  name: "",
1437
1585
  email: "",
1438
- items: [{ title: "", value: null }, { title: "", value: null }],
1586
+ items: [
1587
+ { title: "", value: null },
1588
+ { title: "", value: null },
1589
+ ],
1439
1590
  },
1440
- })
1591
+ }),
1441
1592
  );
1442
1593
 
1443
1594
  // Sequence of edits alternating between root and array fields
@@ -1468,9 +1619,15 @@ describe("useForma", () => {
1468
1619
  const data = result.current.data;
1469
1620
  expect(data.name).toBe("Alice");
1470
1621
  expect(data.email).toBe("alice@example.com");
1471
- expect((data.items as Array<{ title: string; value: number }>)[0].title).toBe("Item 1");
1472
- expect((data.items as Array<{ title: string; value: number }>)[0].value).toBe(100);
1473
- expect((data.items as Array<{ title: string; value: number }>)[1].title).toBe("Item 2");
1622
+ expect(
1623
+ (data.items as Array<{ title: string; value: number }>)[0].title,
1624
+ ).toBe("Item 1");
1625
+ expect(
1626
+ (data.items as Array<{ title: string; value: number }>)[0].value,
1627
+ ).toBe(100);
1628
+ expect(
1629
+ (data.items as Array<{ title: string; value: number }>)[1].title,
1630
+ ).toBe("Item 2");
1474
1631
  });
1475
1632
 
1476
1633
  it("should preserve item data when adding new items", () => {
@@ -1484,7 +1641,7 @@ describe("useForma", () => {
1484
1641
  });
1485
1642
 
1486
1643
  const { result } = renderHook(() =>
1487
- useForma({ spec, initialData: { items: [] } })
1644
+ useForma({ spec, initialData: { items: [] } }),
1488
1645
  );
1489
1646
 
1490
1647
  // Add first item
@@ -1498,7 +1655,9 @@ describe("useForma", () => {
1498
1655
  const helpers = result.current.getArrayHelpers("items");
1499
1656
  helpers.getItemFieldProps(0, "name").onChange("First");
1500
1657
  });
1501
- expect((result.current.data.items as Array<{ name: string }>)[0].name).toBe("First");
1658
+ expect(
1659
+ (result.current.data.items as Array<{ name: string }>)[0].name,
1660
+ ).toBe("First");
1502
1661
 
1503
1662
  // Add second item - first item should keep its value
1504
1663
  act(() => {
@@ -1506,8 +1665,12 @@ describe("useForma", () => {
1506
1665
  helpers.push({ name: "" });
1507
1666
  });
1508
1667
 
1509
- expect((result.current.data.items as Array<{ name: string }>)[0].name).toBe("First");
1510
- expect((result.current.data.items as Array<{ name: string }>).length).toBe(2);
1668
+ expect(
1669
+ (result.current.data.items as Array<{ name: string }>)[0].name,
1670
+ ).toBe("First");
1671
+ expect(
1672
+ (result.current.data.items as Array<{ name: string }>).length,
1673
+ ).toBe(2);
1511
1674
 
1512
1675
  // Edit second item - first item should still keep its value
1513
1676
  act(() => {
@@ -1515,8 +1678,12 @@ describe("useForma", () => {
1515
1678
  helpers.getItemFieldProps(1, "name").onChange("Second");
1516
1679
  });
1517
1680
 
1518
- expect((result.current.data.items as Array<{ name: string }>)[0].name).toBe("First");
1519
- expect((result.current.data.items as Array<{ name: string }>)[1].name).toBe("Second");
1681
+ expect(
1682
+ (result.current.data.items as Array<{ name: string }>)[0].name,
1683
+ ).toBe("First");
1684
+ expect(
1685
+ (result.current.data.items as Array<{ name: string }>)[1].name,
1686
+ ).toBe("Second");
1520
1687
  });
1521
1688
 
1522
1689
  it("should preserve data when editing different array items in sequence", () => {
@@ -1535,7 +1702,7 @@ describe("useForma", () => {
1535
1702
  initialData: {
1536
1703
  items: [{ name: "" }, { name: "" }, { name: "" }],
1537
1704
  },
1538
- })
1705
+ }),
1539
1706
  );
1540
1707
 
1541
1708
  // Edit items in sequence: 0, 2, 1, 0 again
@@ -1581,7 +1748,7 @@ describe("useForma", () => {
1581
1748
  initialData: {
1582
1749
  items: [{ name: "First" }, { name: "Second" }, { name: "Third" }],
1583
1750
  },
1584
- })
1751
+ }),
1585
1752
  );
1586
1753
 
1587
1754
  // Remove middle item
@@ -1618,7 +1785,7 @@ describe("useForma", () => {
1618
1785
  });
1619
1786
 
1620
1787
  const { result } = renderHook(() =>
1621
- useForma({ spec, initialData: { items: [{ name: "" }] } })
1788
+ useForma({ spec, initialData: { items: [{ name: "" }] } }),
1622
1789
  );
1623
1790
 
1624
1791
  // Rapidly edit the same field multiple times
@@ -1642,7 +1809,9 @@ describe("useForma", () => {
1642
1809
  helpers.getItemFieldProps(0, "name").onChange("abcd");
1643
1810
  });
1644
1811
 
1645
- expect((result.current.data.items as Array<{ name: string }>)[0].name).toBe("abcd");
1812
+ expect(
1813
+ (result.current.data.items as Array<{ name: string }>)[0].name,
1814
+ ).toBe("abcd");
1646
1815
  });
1647
1816
 
1648
1817
  it("should preserve multiple root fields when editing array items", () => {
@@ -1667,7 +1836,7 @@ describe("useForma", () => {
1667
1836
  email: "john@example.com",
1668
1837
  items: [{ name: "" }],
1669
1838
  },
1670
- })
1839
+ }),
1671
1840
  );
1672
1841
 
1673
1842
  // Edit array item
@@ -1680,7 +1849,9 @@ describe("useForma", () => {
1680
1849
  expect(result.current.data.firstName).toBe("John");
1681
1850
  expect(result.current.data.lastName).toBe("Doe");
1682
1851
  expect(result.current.data.email).toBe("john@example.com");
1683
- expect((result.current.data.items as Array<{ name: string }>)[0].name).toBe("Item Name");
1852
+ expect(
1853
+ (result.current.data.items as Array<{ name: string }>)[0].name,
1854
+ ).toBe("Item Name");
1684
1855
  });
1685
1856
  });
1686
1857
  });