@akinon/akiform-builder 0.8.0 → 1.0.1

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.
Files changed (57) hide show
  1. package/dist/cjs/__tests__/akiform-builder.test.d.ts +2 -0
  2. package/dist/cjs/__tests__/akiform-builder.test.d.ts.map +1 -0
  3. package/dist/cjs/__tests__/akiform-builder.test.js +1432 -0
  4. package/dist/cjs/__tests__/field-builder.test.d.ts +2 -0
  5. package/dist/cjs/__tests__/field-builder.test.d.ts.map +1 -0
  6. package/dist/cjs/__tests__/field-builder.test.js +296 -0
  7. package/dist/cjs/index.css +17 -0
  8. package/dist/cjs/src/akiform-builder.d.ts +7 -0
  9. package/dist/cjs/src/akiform-builder.d.ts.map +1 -0
  10. package/dist/cjs/src/akiform-builder.js +458 -0
  11. package/dist/cjs/src/field-builder.d.ts +54 -0
  12. package/dist/cjs/src/field-builder.d.ts.map +1 -0
  13. package/dist/cjs/src/field-builder.js +153 -0
  14. package/dist/cjs/src/i18n/index.d.ts +5 -0
  15. package/dist/cjs/src/i18n/index.d.ts.map +1 -0
  16. package/dist/cjs/src/i18n/index.js +14 -0
  17. package/dist/cjs/src/i18n/translations/en.d.ts +14 -0
  18. package/dist/cjs/src/i18n/translations/en.d.ts.map +1 -0
  19. package/dist/cjs/src/i18n/translations/en.js +15 -0
  20. package/dist/cjs/src/i18n/translations/tr.d.ts +14 -0
  21. package/dist/cjs/src/i18n/translations/tr.d.ts.map +1 -0
  22. package/dist/cjs/src/i18n/translations/tr.js +15 -0
  23. package/dist/cjs/src/index.d.ts +4 -0
  24. package/dist/cjs/src/index.d.ts.map +1 -0
  25. package/dist/cjs/src/index.js +21 -0
  26. package/dist/cjs/src/types.d.ts +106 -0
  27. package/dist/cjs/src/types.d.ts.map +1 -0
  28. package/dist/cjs/src/types.js +2 -0
  29. package/dist/esm/__tests__/akiform-builder.test.d.ts +2 -0
  30. package/dist/esm/__tests__/akiform-builder.test.d.ts.map +1 -0
  31. package/dist/esm/__tests__/akiform-builder.test.js +1430 -0
  32. package/dist/esm/__tests__/field-builder.test.d.ts +2 -0
  33. package/dist/esm/__tests__/field-builder.test.d.ts.map +1 -0
  34. package/dist/esm/__tests__/field-builder.test.js +294 -0
  35. package/dist/esm/index.css +17 -0
  36. package/dist/esm/src/akiform-builder.d.ts +7 -0
  37. package/dist/esm/src/akiform-builder.d.ts.map +1 -0
  38. package/dist/esm/src/akiform-builder.js +455 -0
  39. package/dist/esm/src/field-builder.d.ts +54 -0
  40. package/dist/esm/src/field-builder.d.ts.map +1 -0
  41. package/dist/esm/src/field-builder.js +150 -0
  42. package/dist/esm/src/i18n/index.d.ts +5 -0
  43. package/dist/esm/src/i18n/index.d.ts.map +1 -0
  44. package/dist/esm/src/i18n/index.js +11 -0
  45. package/dist/esm/src/i18n/translations/en.d.ts +14 -0
  46. package/dist/esm/src/i18n/translations/en.d.ts.map +1 -0
  47. package/dist/esm/src/i18n/translations/en.js +13 -0
  48. package/dist/esm/src/i18n/translations/tr.d.ts +14 -0
  49. package/dist/esm/src/i18n/translations/tr.d.ts.map +1 -0
  50. package/dist/esm/src/i18n/translations/tr.js +13 -0
  51. package/dist/esm/src/index.d.ts +4 -0
  52. package/dist/esm/src/index.d.ts.map +1 -0
  53. package/dist/esm/src/index.js +3 -0
  54. package/dist/esm/src/types.d.ts +106 -0
  55. package/dist/esm/src/types.d.ts.map +1 -0
  56. package/dist/esm/src/types.js +1 -0
  57. package/package.json +20 -15
@@ -0,0 +1,1432 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ /* eslint-disable @typescript-eslint/no-explicit-any */
13
+ const akiform_1 = require("@akinon/akiform");
14
+ const akival_1 = require("@akinon/akival");
15
+ const utils_1 = require("@akinon/utils");
16
+ const React = require("react");
17
+ const react_1 = require("react");
18
+ const akiform_builder_1 = require("../src/akiform-builder");
19
+ const field_builder_1 = require("../src/field-builder");
20
+ describe('AkiformBuilder', () => {
21
+ const mockOnSubmit = vi.fn();
22
+ const mockOnReset = vi.fn();
23
+ const mockOnValueChange = vi.fn();
24
+ const expandCollapsable = () => __awaiter(void 0, void 0, void 0, function* () {
25
+ const user = utils_1.userEvent.setup();
26
+ const expandIcons = (yield utils_1.screen.findAllByRole('button')).filter(el => el.className.includes('akinon-collapse-expand-icon'));
27
+ for (const expandIcon of expandIcons) {
28
+ yield user.click(expandIcon);
29
+ }
30
+ });
31
+ const defaultFields = [
32
+ {
33
+ key: 'name',
34
+ label: 'Name',
35
+ type: 'text',
36
+ placeholder: 'Enter your name'
37
+ },
38
+ {
39
+ key: 'age',
40
+ label: 'Age',
41
+ type: 'number',
42
+ placeholder: 'Enter your age',
43
+ help: 'Description text 2'
44
+ }
45
+ ];
46
+ beforeEach(() => {
47
+ vi.clearAllMocks();
48
+ });
49
+ describe('AkiformBuilder in uncontrolled mode', () => {
50
+ it('renders form fields correctly', () => __awaiter(void 0, void 0, void 0, function* () {
51
+ const newDefaultFields = defaultFields.map((field, key) => (Object.assign(Object.assign({}, field), { help: `Description text ${key}`, labelDescription: `Label description text ${key}` })));
52
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
53
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: newDefaultFields, onSubmit: mockOnSubmit }));
54
+ }));
55
+ for (const field of newDefaultFields) {
56
+ if (field.label) {
57
+ expect(utils_1.screen.getByText(field.label)).toBeInTheDocument();
58
+ }
59
+ if (field.placeholder) {
60
+ expect(utils_1.screen.getByPlaceholderText(field.placeholder)).toBeInTheDocument();
61
+ }
62
+ expect(utils_1.screen.getByText(field.help)).toBeInTheDocument();
63
+ expect(utils_1.screen.getByText(field.labelDescription)).toBeInTheDocument();
64
+ }
65
+ }));
66
+ it('renders form fields correctly with row and column fields', () => __awaiter(void 0, void 0, void 0, function* () {
67
+ const newDefaultFields = [
68
+ {
69
+ type: 'row',
70
+ key: 'mainrow',
71
+ rowProps: {
72
+ align: 'middle'
73
+ },
74
+ columnFields: [
75
+ {
76
+ type: 'column',
77
+ key: 'col1',
78
+ columnProps: {
79
+ span: '24'
80
+ },
81
+ fields: [
82
+ {
83
+ type: 'row',
84
+ key: 'row1',
85
+ columnFields: [
86
+ {
87
+ type: 'column',
88
+ key: 'col1_1',
89
+ fields: [
90
+ {
91
+ type: 'text',
92
+ key: 'test1',
93
+ label: 'Test Field 1'
94
+ }
95
+ ]
96
+ }
97
+ ]
98
+ },
99
+ {
100
+ type: 'row',
101
+ key: 'row2',
102
+ columnFields: [
103
+ {
104
+ type: 'column',
105
+ key: 'col2_1',
106
+ fields: [
107
+ {
108
+ type: 'text',
109
+ key: 'test2',
110
+ label: 'Test Field 2'
111
+ }
112
+ ]
113
+ },
114
+ {
115
+ type: 'column',
116
+ key: 'col2_2',
117
+ fields: [
118
+ {
119
+ type: 'text',
120
+ key: 'test3',
121
+ label: 'Test Field 3'
122
+ }
123
+ ]
124
+ }
125
+ ]
126
+ }
127
+ ]
128
+ }
129
+ ]
130
+ }
131
+ ];
132
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
133
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: newDefaultFields, onSubmit: mockOnSubmit }));
134
+ }));
135
+ // Check fields
136
+ expect(utils_1.screen.getByLabelText('Test Field 1')).toBeInTheDocument();
137
+ expect(utils_1.screen.getByLabelText('Test Field 2')).toBeInTheDocument();
138
+ expect(utils_1.screen.getByLabelText('Test Field 3')).toBeInTheDocument();
139
+ // Check row and column count
140
+ expect(document.querySelectorAll('.akinon-col')).toHaveLength(11);
141
+ expect(document.querySelectorAll('.akinon-row')).toHaveLength(7);
142
+ // Check props
143
+ expect(document.querySelector('.akinon-row-middle')).toBeInTheDocument();
144
+ expect(document.querySelector('.akinon-col-24')).toBeInTheDocument();
145
+ }));
146
+ it('handles form with custom field and onChange', () => __awaiter(void 0, void 0, void 0, function* () {
147
+ const CustomComponent = ({ field, control }) => {
148
+ const { field: controllerField } = (0, akiform_1.useController)({
149
+ name: field.key,
150
+ control
151
+ });
152
+ return React.createElement("input", Object.assign({ "data-testid": "custom-input" }, controllerField));
153
+ };
154
+ const fields = [
155
+ {
156
+ key: 'customField',
157
+ label: 'Custom Field',
158
+ type: 'custom',
159
+ render: ({ field, formValues, control }) => (React.createElement(CustomComponent, { field: field, formValues: formValues, control: control }))
160
+ }
161
+ ];
162
+ const onValueChangeMock = vi.fn();
163
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
164
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit, onValueChange: onValueChangeMock }));
165
+ }));
166
+ const customInput = utils_1.screen.getByTestId('custom-input');
167
+ expect(customInput).toBeInTheDocument();
168
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
169
+ yield utils_1.userEvent.type(customInput, 'test value');
170
+ }));
171
+ yield (0, utils_1.waitFor)(() => {
172
+ expect(onValueChangeMock).toHaveBeenCalledWith(expect.objectContaining({
173
+ customField: 'test value'
174
+ }));
175
+ });
176
+ }));
177
+ it('resets form when reset button is clicked', () => __awaiter(void 0, void 0, void 0, function* () {
178
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
179
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit, onReset: mockOnReset, showResetButton: true }));
180
+ }));
181
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
182
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Name'), {
183
+ target: { value: 'John Doe' }
184
+ });
185
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Age'), {
186
+ target: { value: '30' }
187
+ });
188
+ utils_1.fireEvent.click(utils_1.screen.getByText('RESET'));
189
+ }));
190
+ yield (0, utils_1.waitFor)(() => {
191
+ expect(mockOnReset).toHaveBeenCalled();
192
+ expect(utils_1.screen.getByLabelText('Name')).toHaveValue('');
193
+ expect(utils_1.screen.getByLabelText('Age')).toHaveValue('');
194
+ });
195
+ }));
196
+ it('exposes reset method through ref', () => __awaiter(void 0, void 0, void 0, function* () {
197
+ const ref = React.createRef();
198
+ const onResetMock = vi.fn();
199
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
200
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { ref: ref, fields: defaultFields, onSubmit: mockOnSubmit, onReset: onResetMock }));
201
+ }));
202
+ // Fill in some values
203
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
204
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Name'), {
205
+ target: { value: 'John Doe' }
206
+ });
207
+ }));
208
+ // Call reset through ref
209
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
210
+ var _a;
211
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.reset();
212
+ }));
213
+ // Check if form is reset and onReset is called
214
+ expect(utils_1.screen.getByLabelText('Name')).toHaveValue('');
215
+ expect(onResetMock).toHaveBeenCalled();
216
+ // Test partial reset
217
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
218
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Name'), {
219
+ target: { value: 'John Doe' }
220
+ });
221
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Age'), {
222
+ target: { value: '30' }
223
+ });
224
+ }));
225
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
226
+ var _a;
227
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.reset({ name: 'Jane Doe' });
228
+ }));
229
+ expect(utils_1.screen.getByLabelText('Name')).toHaveValue('Jane Doe');
230
+ expect(utils_1.screen.getByLabelText('Age')).toHaveValue('30');
231
+ }));
232
+ it('calls onValueChange when form values change in uncontrolled mode', () => __awaiter(void 0, void 0, void 0, function* () {
233
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
234
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit, onValueChange: mockOnValueChange }));
235
+ }));
236
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
237
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Name'), {
238
+ target: { value: 'John Doe' }
239
+ });
240
+ }));
241
+ yield (0, utils_1.waitFor)(() => {
242
+ expect(mockOnValueChange).toHaveBeenCalledWith(expect.objectContaining({
243
+ name: 'John Doe'
244
+ }));
245
+ });
246
+ }));
247
+ it('applies throttling in uncontrolled mode', () => __awaiter(void 0, void 0, void 0, function* () {
248
+ vi.useFakeTimers();
249
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
250
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit, onValueChange: mockOnValueChange }));
251
+ }));
252
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
253
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Name'), {
254
+ target: { value: 'John Doe' }
255
+ });
256
+ }));
257
+ expect(mockOnValueChange).not.toHaveBeenCalled();
258
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
259
+ vi.advanceTimersByTime(akiform_builder_1.THROTTLE_DELAY);
260
+ }));
261
+ expect(mockOnValueChange).toHaveBeenCalledWith(expect.objectContaining({ name: 'John Doe' }));
262
+ vi.useRealTimers();
263
+ }));
264
+ it('renders different field types correctly', () => __awaiter(void 0, void 0, void 0, function* () {
265
+ const fields = [
266
+ {
267
+ key: 'name',
268
+ label: 'Name',
269
+ type: 'text',
270
+ help: 'Help text',
271
+ labelDescription: 'Label description text',
272
+ placeholder: 'Enter your name'
273
+ },
274
+ { key: 'age', label: 'Age', type: 'number' },
275
+ {
276
+ key: 'gender',
277
+ label: 'Gender',
278
+ type: 'select',
279
+ options: [
280
+ { value: 'male', label: 'Male' },
281
+ { value: 'female', label: 'Female' }
282
+ ]
283
+ },
284
+ { key: 'subscribe', label: 'Subscribe', type: 'checkbox' },
285
+ { key: 'birthdate', label: 'Birth Date', type: 'date' },
286
+ { key: 'bio', label: 'Biography', type: 'textarea' }
287
+ ];
288
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
289
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
290
+ }));
291
+ expect(utils_1.screen.getByPlaceholderText('Enter your name')).toHaveAttribute('type', 'text');
292
+ expect(utils_1.screen.getByText('Help text')).toBeInTheDocument();
293
+ expect(utils_1.screen.getByText('Label description text')).toBeInTheDocument();
294
+ expect(utils_1.screen.getByLabelText('Age')).toHaveClass('akinon-input-number-input');
295
+ expect(utils_1.screen.getByLabelText('Gender')).toBeInTheDocument();
296
+ expect(utils_1.screen.getByLabelText('Subscribe')).toHaveAttribute('type', 'checkbox');
297
+ expect(utils_1.screen.getByLabelText('Birth Date')).toBeInTheDocument();
298
+ expect(utils_1.screen.getByLabelText('Biography')).toBeInTheDocument();
299
+ }));
300
+ it('renders field array correctly', () => __awaiter(void 0, void 0, void 0, function* () {
301
+ const user = utils_1.userEvent.setup();
302
+ const fields = [
303
+ (0, field_builder_1.field)()
304
+ .key('addresses')
305
+ .label('Addresses')
306
+ .type('fieldArray')
307
+ .defaultExpanded(true)
308
+ .fields([
309
+ (0, field_builder_1.field)()
310
+ .key('street')
311
+ .label('Street')
312
+ .type('text')
313
+ .help('Help text')
314
+ .labelDescription('Label description text')
315
+ .build(),
316
+ (0, field_builder_1.field)().key('city').label('City').type('text').build()
317
+ ])
318
+ .build()
319
+ ];
320
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
321
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
322
+ }));
323
+ expect(utils_1.screen.getByText('Add Addresses')).toBeInTheDocument();
324
+ yield user.click(utils_1.screen.getByTestId('addresses-add-button'));
325
+ yield expandCollapsable();
326
+ expect(utils_1.screen.getAllByText('Street')).toHaveLength(1);
327
+ expect(utils_1.screen.getAllByText('City')).toHaveLength(1);
328
+ expect(utils_1.screen.getByText('Help text')).toBeInTheDocument();
329
+ expect(utils_1.screen.getByText('Label description text')).toBeInTheDocument();
330
+ }));
331
+ it('handles form with field array and nested validation', () => __awaiter(void 0, void 0, void 0, function* () {
332
+ const user = utils_1.userEvent.setup();
333
+ const fields = [
334
+ {
335
+ key: 'items',
336
+ label: 'Items',
337
+ type: 'fieldArray',
338
+ fields: [
339
+ {
340
+ key: 'name',
341
+ label: 'Item Name',
342
+ type: 'text',
343
+ validation: akival_1.akival.string().required('Item name is required')
344
+ },
345
+ {
346
+ key: 'quantity',
347
+ label: 'Quantity',
348
+ type: 'number',
349
+ validation: akival_1.akival.number().min(1, 'Quantity must be at least 1')
350
+ }
351
+ ]
352
+ }
353
+ ];
354
+ const onSubmitMock = vi.fn();
355
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
356
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
357
+ }));
358
+ // Add an item
359
+ yield user.click(utils_1.screen.getByTestId('items-add-button'));
360
+ // Try to submit without filling required fields
361
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
362
+ utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
363
+ }));
364
+ yield (0, utils_1.waitFor)(() => {
365
+ expect(utils_1.screen.getByText('An error occurred in here')).toBeInTheDocument();
366
+ expect(onSubmitMock).not.toHaveBeenCalled();
367
+ });
368
+ yield expandCollapsable();
369
+ // Fill in valid data
370
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
371
+ const nameInput = utils_1.screen.getByRole('textbox', { name: /item name/i });
372
+ const quantityInput = utils_1.screen.getByRole('spinbutton', {
373
+ name: /quantity/i
374
+ });
375
+ yield utils_1.userEvent.type(nameInput, 'Test Item');
376
+ yield utils_1.userEvent.type(quantityInput, '2');
377
+ }));
378
+ // Submit the form
379
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
380
+ utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
381
+ }));
382
+ yield (0, utils_1.waitFor)(() => {
383
+ expect(onSubmitMock).toHaveBeenCalledWith(expect.objectContaining({
384
+ items: [{ name: 'Test Item', quantity: 2 }]
385
+ }), expect.anything());
386
+ });
387
+ }));
388
+ it('handles field array operations correctly', () => __awaiter(void 0, void 0, void 0, function* () {
389
+ const user = utils_1.userEvent.setup();
390
+ const fields = [
391
+ {
392
+ key: 'items',
393
+ label: 'Items',
394
+ type: 'fieldArray',
395
+ fields: [
396
+ { key: 'name', label: 'Item Name', type: 'text' },
397
+ { key: 'quantity', label: 'Quantity', type: 'number' }
398
+ ]
399
+ }
400
+ ];
401
+ const TestComponent = () => {
402
+ const [formValues, setFormValues] = React.useState({});
403
+ return (React.createElement(React.Fragment, null,
404
+ React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit, onValueChange: values => {
405
+ setFormValues(values);
406
+ } }),
407
+ React.createElement("div", { "data-testid": "form-values" }, JSON.stringify(formValues))));
408
+ };
409
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
410
+ (0, utils_1.render)(React.createElement(TestComponent, null));
411
+ }));
412
+ // Add an item
413
+ yield user.click(utils_1.screen.getByTestId('items-add-button'));
414
+ yield expandCollapsable();
415
+ // Fill in the fields
416
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
417
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Item Name'), {
418
+ target: { value: 'Test Item' }
419
+ });
420
+ }));
421
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
422
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Quantity'), {
423
+ target: { value: '5' }
424
+ });
425
+ }));
426
+ // Wait for the form values to update
427
+ yield (0, utils_1.waitFor)(() => {
428
+ const formValuesElement = utils_1.screen.getByTestId('form-values');
429
+ const formValues = JSON.parse(formValuesElement.textContent || '{}');
430
+ expect(formValues).toEqual(expect.objectContaining({
431
+ items: [{ name: 'Test Item', quantity: 5 }]
432
+ }));
433
+ });
434
+ // Submit the form
435
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
436
+ utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
437
+ }));
438
+ // Check the submitted values
439
+ yield (0, utils_1.waitFor)(() => {
440
+ expect(mockOnSubmit).toHaveBeenCalledWith(expect.objectContaining({
441
+ items: [{ name: 'Test Item', quantity: 5 }]
442
+ }), expect.anything());
443
+ });
444
+ }));
445
+ it('applies layout options correctly', () => __awaiter(void 0, void 0, void 0, function* () {
446
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
447
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit, layout: "horizontal", layoutOptions: { labelCol: { span: 8 }, wrapperCol: { span: 16 } } }));
448
+ }));
449
+ const form = utils_1.screen.getByTestId('akiform-builder');
450
+ expect(form).toHaveClass('akinon-form-horizontal');
451
+ }));
452
+ it('conditionally renders and disables fields', () => __awaiter(void 0, void 0, void 0, function* () {
453
+ const fields = [
454
+ { key: 'showField', label: 'Show Field', type: 'checkbox' },
455
+ {
456
+ key: 'conditionalField',
457
+ label: 'Conditional Field',
458
+ type: 'text',
459
+ config: { visible: values => values.showField }
460
+ },
461
+ { key: 'enableField', label: 'Enable Field', type: 'checkbox' },
462
+ {
463
+ key: 'disableableField',
464
+ label: 'Disableable Field',
465
+ type: 'text',
466
+ config: { disabled: values => !values.enableField }
467
+ }
468
+ ];
469
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
470
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
471
+ }));
472
+ expect(utils_1.screen.queryByLabelText('Conditional Field')).not.toBeInTheDocument();
473
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
474
+ utils_1.fireEvent.click(utils_1.screen.getByLabelText('Show Field'));
475
+ }));
476
+ expect(utils_1.screen.getByLabelText('Conditional Field')).toBeInTheDocument();
477
+ expect(utils_1.screen.getByLabelText('Disableable Field')).toBeDisabled();
478
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
479
+ utils_1.fireEvent.click(utils_1.screen.getByLabelText('Enable Field'));
480
+ }));
481
+ expect(utils_1.screen.getByLabelText('Disableable Field')).not.toBeDisabled();
482
+ }));
483
+ it('applies custom validation', () => __awaiter(void 0, void 0, void 0, function* () {
484
+ const fields = [
485
+ {
486
+ key: 'email',
487
+ label: 'Email',
488
+ type: 'text',
489
+ validation: akival_1.akival.string().email('Invalid email format')
490
+ }
491
+ ];
492
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
493
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
494
+ }));
495
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
496
+ utils_1.fireEvent.change(utils_1.screen.getByRole('textbox', { name: /email/i }), {
497
+ target: { value: 'invalid-email' }
498
+ });
499
+ utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
500
+ }));
501
+ yield (0, utils_1.waitFor)(() => {
502
+ expect(utils_1.screen.getByText('Invalid email format')).toBeInTheDocument();
503
+ });
504
+ }));
505
+ it('resets form using ref', () => __awaiter(void 0, void 0, void 0, function* () {
506
+ const ref = React.createRef();
507
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
508
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { ref: ref, fields: defaultFields, onSubmit: mockOnSubmit }));
509
+ }));
510
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
511
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Name'), {
512
+ target: { value: 'John Doe' }
513
+ });
514
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Age'), {
515
+ target: { value: '30' }
516
+ });
517
+ }));
518
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
519
+ var _a;
520
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.reset();
521
+ }));
522
+ expect(utils_1.screen.getByLabelText('Name')).toHaveValue('');
523
+ expect(utils_1.screen.getByLabelText('Age')).toHaveValue('');
524
+ }));
525
+ it('displays error states', () => __awaiter(void 0, void 0, void 0, function* () {
526
+ const fields = [
527
+ {
528
+ key: 'name',
529
+ label: 'Name',
530
+ type: 'text',
531
+ validation: akival_1.akival.string().required('Name is required')
532
+ }
533
+ ];
534
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
535
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
536
+ }));
537
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
538
+ utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
539
+ }));
540
+ yield (0, utils_1.waitFor)(() => {
541
+ expect(utils_1.screen.getByText('Name is required')).toBeInTheDocument();
542
+ });
543
+ }));
544
+ it('handles form submission', () => __awaiter(void 0, void 0, void 0, function* () {
545
+ const onSubmit = vi.fn();
546
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
547
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: onSubmit }));
548
+ }));
549
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
550
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Name'), {
551
+ target: { value: 'John Doe' }
552
+ });
553
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Age'), {
554
+ target: { value: '30' }
555
+ });
556
+ utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
557
+ }));
558
+ yield (0, utils_1.waitFor)(() => {
559
+ expect(onSubmit).toHaveBeenCalledWith(expect.objectContaining({
560
+ name: 'John Doe',
561
+ age: 30
562
+ }), expect.anything());
563
+ });
564
+ }));
565
+ it('handles form submission with errors', () => __awaiter(void 0, void 0, void 0, function* () {
566
+ const fields = [
567
+ {
568
+ key: 'name',
569
+ label: 'Name',
570
+ type: 'text',
571
+ validation: akival_1.akival.string().required('Name is required')
572
+ }
573
+ ];
574
+ const onSubmit = vi.fn();
575
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
576
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: onSubmit }));
577
+ }));
578
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
579
+ utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
580
+ }));
581
+ yield (0, utils_1.waitFor)(() => {
582
+ expect(utils_1.screen.getByText('Name is required')).toBeInTheDocument();
583
+ expect(onSubmit).not.toHaveBeenCalled();
584
+ });
585
+ }));
586
+ it('handles form with initial values', () => __awaiter(void 0, void 0, void 0, function* () {
587
+ const initialValues = { name: 'John Doe', age: 30 };
588
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
589
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit, initialValues: initialValues }));
590
+ }));
591
+ yield (0, utils_1.waitFor)(() => {
592
+ expect(utils_1.screen.getByLabelText('Name')).toHaveValue('John Doe');
593
+ expect(utils_1.screen.getByLabelText('Age')).toHaveValue('30');
594
+ });
595
+ }));
596
+ it('handles form with custom layout', () => __awaiter(void 0, void 0, void 0, function* () {
597
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
598
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit, layout: "vertical" }));
599
+ }));
600
+ const form = utils_1.screen.getByTestId('akiform-builder');
601
+ expect(form).toHaveClass('akinon-form-vertical');
602
+ }));
603
+ it('renders custom field correctly', () => __awaiter(void 0, void 0, void 0, function* () {
604
+ const CustomComponent = ({ field }) => (React.createElement("div", { "data-testid": "custom-field" }, field.label));
605
+ const fields = [
606
+ {
607
+ key: 'customField',
608
+ label: 'Custom Field',
609
+ type: 'custom',
610
+ help: 'Help text',
611
+ labelDescription: 'Label description text',
612
+ render: ({ field }) => (React.createElement(CustomComponent, { field: field }))
613
+ }
614
+ ];
615
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
616
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
617
+ }));
618
+ expect(utils_1.screen.getByTestId('custom-field')).toHaveTextContent('Custom Field');
619
+ expect(utils_1.screen.getByText('Help text')).toBeInTheDocument();
620
+ expect(utils_1.screen.getByText('Label description text')).toBeInTheDocument();
621
+ }));
622
+ it('cleans up throttle timeout on unmount', () => __awaiter(void 0, void 0, void 0, function* () {
623
+ vi.useFakeTimers();
624
+ const { unmount } = (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit, onValueChange: mockOnValueChange }));
625
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
626
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Name'), {
627
+ target: { value: 'John Doe' }
628
+ });
629
+ }));
630
+ unmount();
631
+ // Advance timers and ensure onValueChange is not called
632
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
633
+ vi.advanceTimersByTime(akiform_builder_1.THROTTLE_DELAY + 100);
634
+ }));
635
+ expect(mockOnValueChange).not.toHaveBeenCalled();
636
+ vi.useRealTimers();
637
+ }));
638
+ it('handles custom field with undefined render prop', () => __awaiter(void 0, void 0, void 0, function* () {
639
+ const fields = [
640
+ {
641
+ key: 'customField',
642
+ label: 'Custom Field',
643
+ type: 'custom',
644
+ render: undefined
645
+ }
646
+ ];
647
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
648
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
649
+ }));
650
+ // The custom field should not be rendered, but the form should not crash
651
+ expect(utils_1.screen.queryByLabelText('Custom Field')).not.toBeInTheDocument();
652
+ // The form should still be rendered
653
+ expect(utils_1.screen.getByTestId('akiform-builder')).toBeInTheDocument();
654
+ }));
655
+ it('renders custom submit and reset button props', () => __awaiter(void 0, void 0, void 0, function* () {
656
+ const submitButtonProps = {
657
+ className: 'custom-submit-btn',
658
+ children: 'submit button'
659
+ };
660
+ const resetButtonProps = {
661
+ className: 'custom-reset-btn',
662
+ children: 'reset button'
663
+ };
664
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
665
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit, showResetButton: true, onReset: mockOnReset, submitButtonProps: submitButtonProps, resetButtonProps: resetButtonProps }));
666
+ }));
667
+ const submitButton = utils_1.screen
668
+ .getByText(submitButtonProps.children)
669
+ .closest('button');
670
+ const resetButton = utils_1.screen
671
+ .getByText(resetButtonProps.children)
672
+ .closest('button');
673
+ expect(submitButton).toBeInTheDocument();
674
+ expect(resetButton).toBeInTheDocument();
675
+ expect(submitButton).toHaveClass(submitButtonProps.className);
676
+ expect(resetButton).toHaveClass(resetButtonProps.className);
677
+ yield utils_1.userEvent.click(resetButton);
678
+ expect(mockOnReset).toHaveBeenCalled();
679
+ yield utils_1.userEvent.click(submitButton);
680
+ expect(mockOnSubmit).toHaveBeenCalled();
681
+ }));
682
+ });
683
+ describe('AkiformBuilder in controlled mode', () => {
684
+ it('uses provided values in controlled mode', () => __awaiter(void 0, void 0, void 0, function* () {
685
+ const fields = [
686
+ { key: 'name', label: 'Name', type: 'text' },
687
+ { key: 'age', label: 'Age', type: 'number' }
688
+ ];
689
+ const controlledValues = { name: 'John Doe', age: 30 };
690
+ const onChangeMock = vi.fn();
691
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
692
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn(), controlled: true, values: controlledValues, onValueChange: onChangeMock }));
693
+ }));
694
+ expect(utils_1.screen.getByLabelText('Name')).toHaveValue('John Doe');
695
+ expect(utils_1.screen.getByLabelText('Age')).toHaveValue('30');
696
+ }));
697
+ it('calls onValueChange when form values change in controlled mode', () => __awaiter(void 0, void 0, void 0, function* () {
698
+ const fields = [
699
+ { key: 'name', label: 'Name', type: 'text' }
700
+ ];
701
+ const onChangeMock = vi.fn();
702
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
703
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn(), controlled: true, values: { name: '' }, onValueChange: onChangeMock }));
704
+ }));
705
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
706
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Name'), {
707
+ target: { value: 'Jane Doe' }
708
+ });
709
+ }));
710
+ yield (0, utils_1.waitFor)(() => {
711
+ expect(onChangeMock).toHaveBeenCalledWith(expect.objectContaining({ name: 'Jane Doe' }));
712
+ });
713
+ }));
714
+ it('calls onValueChange immediately in controlled mode', () => __awaiter(void 0, void 0, void 0, function* () {
715
+ const onValueChangeMock = vi.fn();
716
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
717
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit, controlled: true, values: { name: 'John Doe', age: 30 }, onValueChange: onValueChangeMock }));
718
+ }));
719
+ expect(onValueChangeMock).toHaveBeenCalledWith(expect.objectContaining({ name: 'John Doe', age: 30 }));
720
+ }));
721
+ it('handles conditional rendering and disabling of fields', () => __awaiter(void 0, void 0, void 0, function* () {
722
+ const fields = [
723
+ { key: 'showField', label: 'Show Field', type: 'checkbox' },
724
+ {
725
+ key: 'conditionalField',
726
+ label: 'Conditional Field',
727
+ type: 'text',
728
+ config: { visible: values => values.showField }
729
+ },
730
+ { key: 'enableField', label: 'Enable Field', type: 'checkbox' },
731
+ {
732
+ key: 'disableableField',
733
+ label: 'Disableable Field',
734
+ type: 'text',
735
+ config: { disabled: values => !values.enableField }
736
+ }
737
+ ];
738
+ const onValueChangeMock = vi.fn();
739
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
740
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn(), controlled: true, values: { showField: false, enableField: false }, onValueChange: onValueChangeMock }));
741
+ }));
742
+ expect(utils_1.screen.queryByLabelText('Conditional Field')).not.toBeInTheDocument();
743
+ expect(utils_1.screen.getByLabelText('Disableable Field')).toBeDisabled();
744
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
745
+ utils_1.fireEvent.click(utils_1.screen.getByLabelText('Show Field'));
746
+ utils_1.fireEvent.click(utils_1.screen.getByLabelText('Enable Field'));
747
+ }));
748
+ expect(utils_1.screen.getByLabelText('Conditional Field')).toBeInTheDocument();
749
+ expect(utils_1.screen.getByLabelText('Disableable Field')).not.toBeDisabled();
750
+ expect(onValueChangeMock).toHaveBeenCalledWith(expect.objectContaining({
751
+ showField: true,
752
+ enableField: true
753
+ }));
754
+ }));
755
+ });
756
+ describe('FieldArrayComponent', () => {
757
+ it('renders field array with initial values', () => __awaiter(void 0, void 0, void 0, function* () {
758
+ const fields = [
759
+ {
760
+ key: 'items',
761
+ label: 'Items',
762
+ type: 'fieldArray',
763
+ fields: [
764
+ { key: 'name', label: 'Item Name', type: 'text' },
765
+ { key: 'quantity', label: 'Quantity', type: 'number' }
766
+ ]
767
+ }
768
+ ];
769
+ const initialValues = {
770
+ items: [
771
+ { name: 'Item 1', quantity: 1 },
772
+ { name: 'Item 2', quantity: 2 }
773
+ ]
774
+ };
775
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
776
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn(), initialValues: initialValues }));
777
+ }));
778
+ yield expandCollapsable();
779
+ expect(utils_1.screen.getAllByLabelText('Item Name')).toHaveLength(2);
780
+ expect(utils_1.screen.getAllByLabelText('Quantity')).toHaveLength(2);
781
+ }));
782
+ it('adds and removes field array items', () => __awaiter(void 0, void 0, void 0, function* () {
783
+ const user = utils_1.userEvent.setup();
784
+ const fields = [
785
+ {
786
+ key: 'items',
787
+ label: 'Items',
788
+ type: 'fieldArray',
789
+ fields: [{ key: 'name', label: 'Item Name', type: 'text' }]
790
+ }
791
+ ];
792
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
793
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
794
+ }));
795
+ // Add an item
796
+ yield user.click(utils_1.screen.getByTestId('items-add-button'));
797
+ yield expandCollapsable();
798
+ expect(utils_1.screen.getByLabelText('Item Name')).toBeInTheDocument();
799
+ // Add another item
800
+ yield user.click(utils_1.screen.getByLabelText('Add Items'));
801
+ yield expandCollapsable();
802
+ expect(utils_1.screen.getAllByLabelText('Item Name')).toHaveLength(2);
803
+ // Remove an item
804
+ yield user.click(utils_1.screen.getAllByLabelText('Remove Items')[0]);
805
+ yield expandCollapsable();
806
+ expect(utils_1.screen.getAllByLabelText('Item Name')).toHaveLength(1);
807
+ }));
808
+ it('handles field array with conditional fields', () => __awaiter(void 0, void 0, void 0, function* () {
809
+ const user = utils_1.userEvent.setup();
810
+ const fields = [
811
+ {
812
+ key: 'items',
813
+ label: 'Items',
814
+ type: 'fieldArray',
815
+ fields: [
816
+ { key: 'name', label: 'Item Name', type: 'text' },
817
+ {
818
+ key: 'description',
819
+ label: 'Description',
820
+ type: 'text',
821
+ config: {
822
+ visible: values => values.name && values.name.length > 5
823
+ }
824
+ }
825
+ ]
826
+ }
827
+ ];
828
+ const { rerender } = (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
829
+ yield expandCollapsable();
830
+ // Add an item
831
+ yield user.click(utils_1.screen.getByLabelText('Add Items'));
832
+ yield expandCollapsable();
833
+ // Description should not be visible initially
834
+ expect(utils_1.screen.queryByLabelText('Description')).not.toBeInTheDocument();
835
+ // Enter a name longer than 5 characters
836
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
837
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('Item Name'), {
838
+ target: { value: 'Long Name' }
839
+ });
840
+ }));
841
+ // Force a re-render to trigger the conditional rendering
842
+ rerender(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
843
+ // Description should now be visible
844
+ yield (0, utils_1.waitFor)(() => {
845
+ expect(utils_1.screen.getByLabelText('Description')).toBeInTheDocument();
846
+ });
847
+ }));
848
+ });
849
+ describe('Edge cases and uncovered scenarios', () => {
850
+ it('handles field array with no fields', () => __awaiter(void 0, void 0, void 0, function* () {
851
+ const fields = [
852
+ {
853
+ key: 'emptyFieldArray',
854
+ label: 'Empty Field Array',
855
+ type: 'fieldArray',
856
+ fields: []
857
+ }
858
+ ];
859
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
860
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
861
+ }));
862
+ // The field array should be rendered with an "Add" button
863
+ expect(utils_1.screen.getByTestId('emptyFieldArray-add-button')).toBeInTheDocument();
864
+ }));
865
+ it('handles form submission with field array', () => __awaiter(void 0, void 0, void 0, function* () {
866
+ const user = utils_1.userEvent.setup();
867
+ const fields = [
868
+ {
869
+ key: 'items',
870
+ label: 'Items',
871
+ type: 'fieldArray',
872
+ fields: [
873
+ { key: 'name', label: 'Item Name', type: 'text' },
874
+ { key: 'quantity', label: 'Quantity', type: 'number' }
875
+ ]
876
+ }
877
+ ];
878
+ const onSubmitMock = vi.fn();
879
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
880
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
881
+ }));
882
+ // Add two items
883
+ yield user.click(utils_1.screen.getByTestId('items-add-button'));
884
+ yield user.click(utils_1.screen.getByLabelText('Add Items'));
885
+ yield expandCollapsable();
886
+ // Fill in the fields
887
+ const itemNames = utils_1.screen.getAllByLabelText('Item Name');
888
+ const quantities = utils_1.screen.getAllByLabelText('Quantity');
889
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
890
+ utils_1.fireEvent.change(itemNames[0], { target: { value: 'Item 1' } });
891
+ utils_1.fireEvent.change(quantities[0], { target: { value: '5' } });
892
+ utils_1.fireEvent.change(itemNames[1], { target: { value: 'Item 2' } });
893
+ utils_1.fireEvent.change(quantities[1], { target: { value: '10' } });
894
+ }));
895
+ // Submit the form
896
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
897
+ utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
898
+ }));
899
+ yield (0, utils_1.waitFor)(() => {
900
+ expect(onSubmitMock).toHaveBeenCalledWith(expect.objectContaining({
901
+ items: [
902
+ { name: 'Item 1', quantity: 5 },
903
+ { name: 'Item 2', quantity: 10 }
904
+ ]
905
+ }), expect.anything());
906
+ });
907
+ }));
908
+ it('handles form with all field types', () => __awaiter(void 0, void 0, void 0, function* () {
909
+ const fields = [
910
+ { key: 'text', label: 'Text', type: 'text' },
911
+ { key: 'number', label: 'Number', type: 'number' },
912
+ {
913
+ key: 'select',
914
+ label: 'Select',
915
+ type: 'select',
916
+ options: [{ value: 'option1', label: 'Option 1' }]
917
+ },
918
+ { key: 'checkbox', label: 'Checkbox', type: 'checkbox' },
919
+ { key: 'date', label: 'Date', type: 'date' },
920
+ { key: 'textarea', label: 'Textarea', type: 'textarea' },
921
+ {
922
+ key: 'fieldArray',
923
+ label: 'Field Array',
924
+ type: 'fieldArray',
925
+ fields: [{ key: 'subfield', label: 'Subfield', type: 'text' }]
926
+ },
927
+ {
928
+ key: 'custom',
929
+ label: 'Custom',
930
+ type: 'custom',
931
+ render: () => React.createElement("div", { "data-testid": "custom-field" }, "Custom Field")
932
+ }
933
+ ];
934
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
935
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
936
+ }));
937
+ expect(utils_1.screen.getByLabelText('Text')).toBeInTheDocument();
938
+ expect(utils_1.screen.getByLabelText('Number')).toBeInTheDocument();
939
+ expect(utils_1.screen.getByLabelText('Select')).toBeInTheDocument();
940
+ expect(utils_1.screen.getByLabelText('Checkbox')).toBeInTheDocument();
941
+ expect(utils_1.screen.getByLabelText('Date')).toBeInTheDocument();
942
+ expect(utils_1.screen.getByLabelText('Textarea')).toBeInTheDocument();
943
+ expect(utils_1.screen.getByTestId('fieldArray-add-button')).toBeInTheDocument(); // For field array
944
+ expect(utils_1.screen.getByTestId('custom-field')).toBeInTheDocument();
945
+ }));
946
+ it('handles form with inline layout', () => __awaiter(void 0, void 0, void 0, function* () {
947
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
948
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: vi.fn(), layout: "inline" }));
949
+ }));
950
+ const form = utils_1.screen.getByTestId('akiform-builder');
951
+ expect(form).toHaveClass('akinon-form-inline');
952
+ }));
953
+ it('handles form reset with custom reset handler', () => __awaiter(void 0, void 0, void 0, function* () {
954
+ const onResetMock = vi.fn();
955
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
956
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: vi.fn(), onReset: onResetMock, showResetButton: true }));
957
+ }));
958
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
959
+ utils_1.fireEvent.click(utils_1.screen.getByText('RESET'));
960
+ }));
961
+ expect(onResetMock).toHaveBeenCalled();
962
+ }));
963
+ });
964
+ describe('AkiformBuilder with FieldBuilder', () => {
965
+ it('renders form fields created with FieldBuilder', () => __awaiter(void 0, void 0, void 0, function* () {
966
+ const fields = [
967
+ (0, field_builder_1.field)()
968
+ .key('name')
969
+ .label('Name')
970
+ .type('text')
971
+ .placeholder('Enter your name')
972
+ .help('Help text')
973
+ .labelDescription('Label description text')
974
+ .build(),
975
+ (0, field_builder_1.field)()
976
+ .key('age')
977
+ .label('Age')
978
+ .type('number')
979
+ .placeholder('Enter your age')
980
+ .build(),
981
+ (0, field_builder_1.field)()
982
+ .key('country')
983
+ .label('Country')
984
+ .type('select')
985
+ .options([
986
+ { value: 'us', label: 'United States' },
987
+ { value: 'ca', label: 'Canada' }
988
+ ])
989
+ .build(),
990
+ (0, field_builder_1.field)()
991
+ .key('subscribe')
992
+ .label('Subscribe to newsletter')
993
+ .type('checkbox')
994
+ .build(),
995
+ (0, field_builder_1.field)().key('birthdate').label('Birth Date').type('date').build(),
996
+ (0, field_builder_1.field)().key('description').label('Description').type('textarea').build()
997
+ ];
998
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
999
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1000
+ }));
1001
+ expect(utils_1.screen.getByText('Name')).toBeInTheDocument();
1002
+ expect(utils_1.screen.getByText('Label description text')).toBeInTheDocument();
1003
+ expect(utils_1.screen.getByText('Help text')).toBeInTheDocument();
1004
+ expect(utils_1.screen.getByLabelText('Age')).toBeInTheDocument();
1005
+ expect(utils_1.screen.getByLabelText('Country')).toBeInTheDocument();
1006
+ expect(utils_1.screen.getByLabelText('Subscribe to newsletter')).toBeInTheDocument();
1007
+ expect(utils_1.screen.getByLabelText('Birth Date')).toBeInTheDocument();
1008
+ expect(utils_1.screen.getByLabelText('Description')).toBeInTheDocument();
1009
+ }));
1010
+ it('handles form submission with fields created by FieldBuilder', () => __awaiter(void 0, void 0, void 0, function* () {
1011
+ const fields = [
1012
+ (0, field_builder_1.field)()
1013
+ .key('name')
1014
+ .label('Name')
1015
+ .type('text')
1016
+ .validation(akival_1.akival.string().required('Name is required'))
1017
+ .build(),
1018
+ (0, field_builder_1.field)()
1019
+ .key('age')
1020
+ .label('Age')
1021
+ .type('number')
1022
+ .validation(akival_1.akival.number().min(18, 'Must be at least 18'))
1023
+ .build()
1024
+ ];
1025
+ const onSubmitMock = vi.fn();
1026
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1027
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
1028
+ }));
1029
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1030
+ utils_1.fireEvent.change(utils_1.screen.getByRole('textbox', { name: /name/i }), {
1031
+ target: { value: 'John Doe' }
1032
+ });
1033
+ utils_1.fireEvent.change(utils_1.screen.getByRole('spinbutton', { name: /age/i }), {
1034
+ target: { value: '25' }
1035
+ });
1036
+ utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
1037
+ }));
1038
+ yield (0, utils_1.waitFor)(() => {
1039
+ expect(onSubmitMock).toHaveBeenCalledWith(expect.objectContaining({
1040
+ name: 'John Doe',
1041
+ age: 25
1042
+ }), expect.anything());
1043
+ });
1044
+ }));
1045
+ it('handles form with custom field created by FieldBuilder', () => __awaiter(void 0, void 0, void 0, function* () {
1046
+ const CustomComponent = ({ field }) => (React.createElement("div", { "data-testid": "custom-field" }, field.label));
1047
+ const fields = [
1048
+ (0, field_builder_1.field)()
1049
+ .key('customField')
1050
+ .label('Custom Field')
1051
+ .type('custom')
1052
+ .help('Help text')
1053
+ .labelDescription('Label description text')
1054
+ .render(({ field }) => React.createElement(CustomComponent, { field: field }))
1055
+ .build()
1056
+ ];
1057
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1058
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1059
+ }));
1060
+ expect(utils_1.screen.getByTestId('custom-field')).toHaveTextContent('Custom Field');
1061
+ expect(utils_1.screen.getByText('Help text')).toBeInTheDocument();
1062
+ expect(utils_1.screen.getByText('Label description text')).toBeInTheDocument();
1063
+ }));
1064
+ it('handles form with field array created by FieldBuilder', () => __awaiter(void 0, void 0, void 0, function* () {
1065
+ const user = utils_1.userEvent.setup();
1066
+ const fields = [
1067
+ (0, field_builder_1.field)()
1068
+ .key('addresses')
1069
+ .label('Addresses')
1070
+ .type('fieldArray')
1071
+ .fields([
1072
+ (0, field_builder_1.field)()
1073
+ .key('street')
1074
+ .label('Street')
1075
+ .type('text')
1076
+ .help('Help text')
1077
+ .labelDescription('Label description text')
1078
+ .placeholder('Enter your street')
1079
+ .build(),
1080
+ (0, field_builder_1.field)().key('city').label('City').type('text').build()
1081
+ ])
1082
+ .build()
1083
+ ];
1084
+ const onSubmitMock = vi.fn();
1085
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1086
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
1087
+ }));
1088
+ // Add an address
1089
+ yield user.click(utils_1.screen.getByTestId('addresses-add-button'));
1090
+ yield expandCollapsable();
1091
+ //Check rendered fields
1092
+ expect(utils_1.screen.getByText('Street')).toBeInTheDocument();
1093
+ expect(utils_1.screen.getByText('Help text')).toBeInTheDocument();
1094
+ expect(utils_1.screen.getByText('Label description text')).toBeInTheDocument();
1095
+ expect(utils_1.screen.getByLabelText('City')).toBeInTheDocument();
1096
+ // Fill in the fields
1097
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1098
+ utils_1.fireEvent.change(utils_1.screen.getByPlaceholderText('Enter your street'), {
1099
+ target: { value: '123 Main St' }
1100
+ });
1101
+ utils_1.fireEvent.change(utils_1.screen.getByLabelText('City'), {
1102
+ target: { value: 'Anytown' }
1103
+ });
1104
+ }));
1105
+ // Submit the form
1106
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1107
+ utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
1108
+ }));
1109
+ yield (0, utils_1.waitFor)(() => {
1110
+ expect(onSubmitMock).toHaveBeenCalledWith(expect.objectContaining({
1111
+ addresses: [{ street: '123 Main St', city: 'Anytown' }]
1112
+ }), expect.anything());
1113
+ });
1114
+ }));
1115
+ it('handles conditional rendering with FieldBuilder', () => __awaiter(void 0, void 0, void 0, function* () {
1116
+ const fields = [
1117
+ (0, field_builder_1.field)().key('showField').label('Show Field').type('checkbox').build(),
1118
+ (0, field_builder_1.field)()
1119
+ .key('conditionalField')
1120
+ .label('Conditional Field')
1121
+ .type('text')
1122
+ .config({ visible: (values) => values.showField })
1123
+ .build()
1124
+ ];
1125
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1126
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1127
+ }));
1128
+ expect(utils_1.screen.queryByLabelText('Conditional Field')).not.toBeInTheDocument();
1129
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1130
+ utils_1.fireEvent.click(utils_1.screen.getByLabelText('Show Field'));
1131
+ }));
1132
+ expect(utils_1.screen.getByLabelText('Conditional Field')).toBeInTheDocument();
1133
+ }));
1134
+ it('handles disabled fields with FieldBuilder', () => __awaiter(void 0, void 0, void 0, function* () {
1135
+ const fields = [
1136
+ (0, field_builder_1.field)()
1137
+ .key('disabledField')
1138
+ .label('Disabled Field')
1139
+ .type('text')
1140
+ .config({ disabled: true })
1141
+ .build()
1142
+ ];
1143
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1144
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1145
+ }));
1146
+ expect(utils_1.screen.getByLabelText('Disabled Field')).toBeDisabled();
1147
+ }));
1148
+ });
1149
+ describe('Accessibility features', () => {
1150
+ it('renders form with proper ARIA attributes', () => __awaiter(void 0, void 0, void 0, function* () {
1151
+ const fields = [
1152
+ {
1153
+ key: 'name',
1154
+ label: 'Name',
1155
+ type: 'text',
1156
+ validation: akival_1.akival.string().required()
1157
+ },
1158
+ { key: 'age', label: 'Age', type: 'number' }
1159
+ ];
1160
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1161
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1162
+ }));
1163
+ const form = utils_1.screen.getByRole('form');
1164
+ expect(form).toHaveAttribute('aria-label', 'Form');
1165
+ const nameInput = utils_1.screen.getByRole('textbox', { name: /name/i });
1166
+ expect(nameInput).toHaveAttribute('aria-required', 'true');
1167
+ expect(nameInput).toHaveAttribute('aria-invalid', 'false');
1168
+ const ageInput = utils_1.screen.getByRole('spinbutton', { name: /age/i });
1169
+ expect(ageInput).toHaveAttribute('aria-required', 'false');
1170
+ expect(ageInput).toHaveAttribute('aria-invalid', 'false');
1171
+ }));
1172
+ it('updates aria-invalid attribute when form is submitted with errors', () => __awaiter(void 0, void 0, void 0, function* () {
1173
+ const fields = [
1174
+ {
1175
+ key: 'name',
1176
+ label: 'Name',
1177
+ type: 'text',
1178
+ validation: akival_1.akival.string().required('Name is required')
1179
+ }
1180
+ ];
1181
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1182
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1183
+ }));
1184
+ const nameInput = utils_1.screen.getByRole('textbox', { name: /name/i });
1185
+ expect(nameInput).toHaveAttribute('aria-invalid', 'false');
1186
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1187
+ utils_1.fireEvent.submit(utils_1.screen.getByRole('form'));
1188
+ }));
1189
+ yield (0, utils_1.waitFor)(() => {
1190
+ expect(nameInput).toHaveAttribute('aria-invalid', 'true');
1191
+ expect(utils_1.screen.getByText('Name is required')).toBeInTheDocument();
1192
+ });
1193
+ }));
1194
+ it('renders field array with proper ARIA attributes', () => __awaiter(void 0, void 0, void 0, function* () {
1195
+ const user = utils_1.userEvent.setup();
1196
+ const fields = [
1197
+ {
1198
+ key: 'addresses',
1199
+ label: 'Addresses',
1200
+ type: 'fieldArray',
1201
+ fields: [
1202
+ { key: 'street', label: 'Street', type: 'text' },
1203
+ { key: 'city', label: 'City', type: 'text' }
1204
+ ]
1205
+ }
1206
+ ];
1207
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1208
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1209
+ }));
1210
+ yield user.click(utils_1.screen.getByTestId('addresses-add-button'));
1211
+ yield expandCollapsable();
1212
+ const fieldArrayGroup = utils_1.screen.getByRole('group', { name: 'Addresses' });
1213
+ expect(fieldArrayGroup).toBeInTheDocument();
1214
+ const addButton = utils_1.screen.getByLabelText('Add Addresses');
1215
+ expect(addButton).toBeInTheDocument();
1216
+ yield user.click(addButton);
1217
+ yield expandCollapsable();
1218
+ const removeButton = utils_1.screen.getAllByLabelText('Remove Addresses')[1];
1219
+ expect(removeButton).toBeInTheDocument();
1220
+ }));
1221
+ it('supports keyboard navigation', () => __awaiter(void 0, void 0, void 0, function* () {
1222
+ const user = utils_1.userEvent.setup();
1223
+ const fields = [
1224
+ { key: 'name', label: 'Name', type: 'text' },
1225
+ { key: 'age', label: 'Age', type: 'number' }
1226
+ ];
1227
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1228
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn(), showResetButton: true }));
1229
+ }));
1230
+ const nameInput = utils_1.screen.getByLabelText('Name');
1231
+ const ageInput = utils_1.screen.getByLabelText('Age');
1232
+ const submitButton = utils_1.screen.getByRole('button', { name: 'SUBMIT' });
1233
+ const resetButton = utils_1.screen.getByRole('button', { name: 'RESET' });
1234
+ yield user.tab();
1235
+ expect(document.activeElement).toBe(nameInput);
1236
+ yield user.tab();
1237
+ expect(document.activeElement).toBe(ageInput);
1238
+ yield user.tab();
1239
+ expect(document.activeElement).toBe(submitButton);
1240
+ yield user.tab();
1241
+ expect(document.activeElement).toBe(resetButton);
1242
+ }));
1243
+ });
1244
+ describe('AkiformBuilder with sections', () => {
1245
+ it('renders form with sections', () => __awaiter(void 0, void 0, void 0, function* () {
1246
+ const fields = [
1247
+ (0, field_builder_1.field)()
1248
+ .key('personalInfo')
1249
+ .label('Personal Information')
1250
+ .type('section')
1251
+ .fields([
1252
+ (0, field_builder_1.field)()
1253
+ .key('name')
1254
+ .label('Name')
1255
+ .type('text')
1256
+ .help('Help text')
1257
+ .labelDescription('Label description text')
1258
+ .build(),
1259
+ (0, field_builder_1.field)().key('age').label('Age').type('number').build()
1260
+ ])
1261
+ .collapsible(true)
1262
+ .defaultExpanded(true)
1263
+ .build(),
1264
+ (0, field_builder_1.field)()
1265
+ .key('contactInfo')
1266
+ .label('Contact Information')
1267
+ .type('section')
1268
+ .collapsible(true)
1269
+ .defaultExpanded(false)
1270
+ .fields([
1271
+ (0, field_builder_1.field)().key('email').label('Email').type('text').build(),
1272
+ (0, field_builder_1.field)().key('phone').label('Phone').type('text').build()
1273
+ ])
1274
+ .build()
1275
+ ];
1276
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1277
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1278
+ }));
1279
+ expect(utils_1.screen.getByText('Personal Information')).toBeInTheDocument();
1280
+ expect(utils_1.screen.getByText('Contact Information')).toBeInTheDocument();
1281
+ expect(utils_1.screen.getByText('Name')).toBeInTheDocument();
1282
+ expect(utils_1.screen.getByText('Help text')).toBeInTheDocument();
1283
+ expect(utils_1.screen.getByText('Label description text')).toBeInTheDocument();
1284
+ expect(utils_1.screen.getByLabelText('Age')).toBeInTheDocument();
1285
+ // Check if the first section is expanded by default
1286
+ expect(utils_1.screen.getByText('Name').closest('label')).toBeVisible();
1287
+ // Check if the second section is collapsed by default
1288
+ expect(utils_1.screen.queryByLabelText('Email')).not.toBeInTheDocument();
1289
+ // Expand the second section
1290
+ const contactInfoSection = utils_1.screen.getByText('Contact Information');
1291
+ yield utils_1.userEvent.click(contactInfoSection);
1292
+ // Wait for the section to expand
1293
+ yield (0, utils_1.waitFor)(() => {
1294
+ expect(utils_1.screen.getByLabelText('Email')).toBeInTheDocument();
1295
+ });
1296
+ // Check if the Email field is now visible
1297
+ // const emailInput = screen.getByLabelText('Email');
1298
+ // expect(emailInput).toBeVisible();
1299
+ // Additional debug information
1300
+ // if (!emailInput.isConnected) {
1301
+ // console.error('Email input is not connected to the DOM');
1302
+ // }
1303
+ // console.log(
1304
+ // 'Email input visibility:',
1305
+ // window.getComputedStyle(emailInput).display
1306
+ // );
1307
+ }));
1308
+ it('handles form submission with sections', () => __awaiter(void 0, void 0, void 0, function* () {
1309
+ const onSubmitMock = vi.fn();
1310
+ const fields = [
1311
+ (0, field_builder_1.field)()
1312
+ .key('personalInfo')
1313
+ .label('Personal Information')
1314
+ .type('section')
1315
+ .fields([
1316
+ (0, field_builder_1.field)().key('name').label('Name').type('text').build(),
1317
+ (0, field_builder_1.field)().key('age').label('Age').type('number').build()
1318
+ ])
1319
+ .build(),
1320
+ (0, field_builder_1.field)()
1321
+ .key('contactInfo')
1322
+ .label('Contact Information')
1323
+ .type('section')
1324
+ .fields([(0, field_builder_1.field)().key('email').label('Email').type('text').build()])
1325
+ .build()
1326
+ ];
1327
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1328
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
1329
+ }));
1330
+ // Expand both sections
1331
+ yield utils_1.userEvent.click(utils_1.screen.getByText('Personal Information'));
1332
+ yield utils_1.userEvent.click(utils_1.screen.getByText('Contact Information'));
1333
+ // Fill in the form
1334
+ yield utils_1.userEvent.type(utils_1.screen.getByLabelText('Name'), 'John Doe', {
1335
+ delay: 1
1336
+ });
1337
+ yield utils_1.userEvent.type(utils_1.screen.getByLabelText('Age'), '30', { delay: 1 });
1338
+ yield utils_1.userEvent.type(utils_1.screen.getByLabelText('Email'), 'john@example.com', {
1339
+ delay: 1
1340
+ });
1341
+ // Wait for submit button to become interactable
1342
+ const submitButton = utils_1.screen.getByRole('button', { name: /submit/i });
1343
+ yield (0, utils_1.waitFor)(() => {
1344
+ expect(submitButton).toBeEnabled();
1345
+ });
1346
+ // Submit the form
1347
+ yield utils_1.userEvent.click(submitButton);
1348
+ // Validate submission
1349
+ expect(onSubmitMock).toHaveBeenCalledWith({
1350
+ name: 'John Doe',
1351
+ age: 30,
1352
+ email: 'john@example.com'
1353
+ }, expect.anything());
1354
+ }));
1355
+ it('handles conditional rendering within sections', () => __awaiter(void 0, void 0, void 0, function* () {
1356
+ const fields = [
1357
+ (0, field_builder_1.field)()
1358
+ .key('personalInfo')
1359
+ .label('Personal Information')
1360
+ .type('section')
1361
+ .fields([
1362
+ (0, field_builder_1.field)().key('name').label('Name').type('text').build(),
1363
+ (0, field_builder_1.field)().key('showAge').label('Show Age').type('checkbox').build(),
1364
+ (0, field_builder_1.field)()
1365
+ .key('age')
1366
+ .label('Age')
1367
+ .type('number')
1368
+ .config({ visible: (values) => values.showAge })
1369
+ .build()
1370
+ ])
1371
+ .defaultExpanded(true)
1372
+ .build()
1373
+ ];
1374
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1375
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1376
+ }));
1377
+ expect(utils_1.screen.getByLabelText('Name')).toBeInTheDocument();
1378
+ expect(utils_1.screen.getByLabelText('Show Age')).toBeInTheDocument();
1379
+ expect(utils_1.screen.queryByLabelText('Age')).not.toBeInTheDocument();
1380
+ yield utils_1.userEvent.click(utils_1.screen.getByLabelText('Show Age'));
1381
+ expect(yield utils_1.screen.findByLabelText('Age')).toBeInTheDocument();
1382
+ }));
1383
+ });
1384
+ describe('AkiformBuilder with tooltip', () => {
1385
+ it('renders form field with tooltip as TooltipProps', () => __awaiter(void 0, void 0, void 0, function* () {
1386
+ const fields = [
1387
+ (0, field_builder_1.field)()
1388
+ .key('name')
1389
+ .label('Name')
1390
+ .type('text')
1391
+ .tooltip({ title: 'Enter your full name', defaultOpen: true })
1392
+ .build()
1393
+ ];
1394
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1395
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1396
+ }));
1397
+ const tooltipTrigger = utils_1.screen.getByLabelText('Name');
1398
+ expect(tooltipTrigger).toBeInTheDocument();
1399
+ // Simulate hovering over the field to show the tooltip
1400
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1401
+ utils_1.fireEvent.mouseEnter(tooltipTrigger);
1402
+ }));
1403
+ // Wait for the tooltip to appear
1404
+ yield (0, utils_1.waitFor)(() => {
1405
+ expect(utils_1.screen.getByText('Enter your full name')).toBeInTheDocument();
1406
+ });
1407
+ }));
1408
+ it('renders form field with tooltip as string', () => __awaiter(void 0, void 0, void 0, function* () {
1409
+ const fields = [
1410
+ (0, field_builder_1.field)()
1411
+ .key('email')
1412
+ .label('Email')
1413
+ .type('text')
1414
+ .tooltip({ title: 'Enter your full name', defaultOpen: true })
1415
+ .build()
1416
+ ];
1417
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1418
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1419
+ }));
1420
+ const tooltipTrigger = utils_1.screen.getByLabelText('Email');
1421
+ expect(tooltipTrigger).toBeInTheDocument();
1422
+ // Simulate hovering over the field to show the tooltip
1423
+ yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1424
+ utils_1.fireEvent.mouseEnter(tooltipTrigger);
1425
+ }));
1426
+ // Wait for the tooltip to appear
1427
+ yield (0, utils_1.waitFor)(() => {
1428
+ expect(utils_1.screen.getByText('Enter your full name')).toBeInTheDocument();
1429
+ });
1430
+ }));
1431
+ });
1432
+ });