@akinon/akiform-builder 1.0.0 → 1.0.2

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 (33) hide show
  1. package/dist/cjs/__tests__/akiform-builder.test.js +257 -83
  2. package/dist/cjs/__tests__/field-builder.test.js +48 -3
  3. package/dist/cjs/index.css +10 -0
  4. package/dist/cjs/src/akiform-builder.d.ts.map +1 -1
  5. package/dist/cjs/src/akiform-builder.js +230 -63
  6. package/dist/cjs/src/field-builder.d.ts +22 -5
  7. package/dist/cjs/src/field-builder.d.ts.map +1 -1
  8. package/dist/cjs/src/field-builder.js +81 -22
  9. package/dist/cjs/src/i18n/translations/en.d.ts +7 -0
  10. package/dist/cjs/src/i18n/translations/en.d.ts.map +1 -1
  11. package/dist/cjs/src/i18n/translations/en.js +8 -1
  12. package/dist/cjs/src/i18n/translations/tr.d.ts +7 -0
  13. package/dist/cjs/src/i18n/translations/tr.d.ts.map +1 -1
  14. package/dist/cjs/src/i18n/translations/tr.js +8 -1
  15. package/dist/cjs/src/types.d.ts +27 -5
  16. package/dist/cjs/src/types.d.ts.map +1 -1
  17. package/dist/esm/__tests__/akiform-builder.test.js +257 -83
  18. package/dist/esm/__tests__/field-builder.test.js +48 -3
  19. package/dist/esm/index.css +10 -0
  20. package/dist/esm/src/akiform-builder.d.ts.map +1 -1
  21. package/dist/esm/src/akiform-builder.js +231 -64
  22. package/dist/esm/src/field-builder.d.ts +22 -5
  23. package/dist/esm/src/field-builder.d.ts.map +1 -1
  24. package/dist/esm/src/field-builder.js +81 -22
  25. package/dist/esm/src/i18n/translations/en.d.ts +7 -0
  26. package/dist/esm/src/i18n/translations/en.d.ts.map +1 -1
  27. package/dist/esm/src/i18n/translations/en.js +8 -1
  28. package/dist/esm/src/i18n/translations/tr.d.ts +7 -0
  29. package/dist/esm/src/i18n/translations/tr.d.ts.map +1 -1
  30. package/dist/esm/src/i18n/translations/tr.js +8 -1
  31. package/dist/esm/src/types.d.ts +27 -5
  32. package/dist/esm/src/types.d.ts.map +1 -1
  33. package/package.json +19 -16
@@ -21,6 +21,13 @@ describe('AkiformBuilder', () => {
21
21
  const mockOnSubmit = vi.fn();
22
22
  const mockOnReset = vi.fn();
23
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
+ });
24
31
  const defaultFields = [
25
32
  {
26
33
  key: 'name',
@@ -32,7 +39,8 @@ describe('AkiformBuilder', () => {
32
39
  key: 'age',
33
40
  label: 'Age',
34
41
  type: 'number',
35
- placeholder: 'Enter your age'
42
+ placeholder: 'Enter your age',
43
+ help: 'Description text 2'
36
44
  }
37
45
  ];
38
46
  beforeEach(() => {
@@ -40,13 +48,100 @@ describe('AkiformBuilder', () => {
40
48
  });
41
49
  describe('AkiformBuilder in uncontrolled mode', () => {
42
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}` })));
43
52
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
44
- (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit }));
53
+ (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: newDefaultFields, onSubmit: mockOnSubmit }));
45
54
  }));
46
- expect(utils_1.screen.getByLabelText('Name')).toBeInTheDocument();
47
- expect(utils_1.screen.getByLabelText('Age')).toBeInTheDocument();
48
- expect(utils_1.screen.getByPlaceholderText('Enter your name')).toBeInTheDocument();
49
- expect(utils_1.screen.getByPlaceholderText('Enter your age')).toBeInTheDocument();
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();
50
145
  }));
51
146
  it('handles form with custom field and onChange', () => __awaiter(void 0, void 0, void 0, function* () {
52
147
  const CustomComponent = ({ field, control }) => {
@@ -168,7 +263,14 @@ describe('AkiformBuilder', () => {
168
263
  }));
169
264
  it('renders different field types correctly', () => __awaiter(void 0, void 0, void 0, function* () {
170
265
  const fields = [
171
- { key: 'name', label: 'Name', type: 'text' },
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
+ },
172
274
  { key: 'age', label: 'Age', type: 'number' },
173
275
  {
174
276
  key: 'gender',
@@ -186,7 +288,9 @@ describe('AkiformBuilder', () => {
186
288
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
187
289
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
188
290
  }));
189
- expect(utils_1.screen.getByLabelText('Name')).toHaveAttribute('type', 'text');
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();
190
294
  expect(utils_1.screen.getByLabelText('Age')).toHaveClass('akinon-input-number-input');
191
295
  expect(utils_1.screen.getByLabelText('Gender')).toBeInTheDocument();
192
296
  expect(utils_1.screen.getByLabelText('Subscribe')).toHaveAttribute('type', 'checkbox');
@@ -194,29 +298,38 @@ describe('AkiformBuilder', () => {
194
298
  expect(utils_1.screen.getByLabelText('Biography')).toBeInTheDocument();
195
299
  }));
196
300
  it('renders field array correctly', () => __awaiter(void 0, void 0, void 0, function* () {
301
+ const user = utils_1.userEvent.setup();
197
302
  const fields = [
198
- {
199
- key: 'addresses',
200
- label: 'Addresses',
201
- type: 'fieldArray',
202
- fields: [
203
- { key: 'street', label: 'Street', type: 'text' },
204
- { key: 'city', label: 'City', type: 'text' }
205
- ]
206
- }
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()
207
319
  ];
208
320
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
209
321
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
210
322
  }));
211
- expect(utils_1.screen.getByText('Add')).toBeInTheDocument();
212
- yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
213
- utils_1.fireEvent.click(utils_1.screen.getByText('Add'));
214
- }));
215
- expect(utils_1.screen.getByLabelText('Street')).toBeInTheDocument();
216
- expect(utils_1.screen.getByLabelText('City')).toBeInTheDocument();
217
- expect(utils_1.screen.getByText('Remove')).toBeInTheDocument();
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();
218
330
  }));
219
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();
220
333
  const fields = [
221
334
  {
222
335
  key: 'items',
@@ -243,25 +356,24 @@ describe('AkiformBuilder', () => {
243
356
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
244
357
  }));
245
358
  // Add an item
246
- yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
247
- utils_1.fireEvent.click(utils_1.screen.getByText('Add'));
248
- }));
359
+ yield user.click(utils_1.screen.getByTestId('items-add-button'));
249
360
  // Try to submit without filling required fields
250
361
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
251
362
  utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
252
363
  }));
253
364
  yield (0, utils_1.waitFor)(() => {
254
- expect(utils_1.screen.getByText('Item name is required')).toBeInTheDocument();
365
+ expect(utils_1.screen.getByText('An error occurred in here')).toBeInTheDocument();
255
366
  expect(onSubmitMock).not.toHaveBeenCalled();
256
367
  });
368
+ yield expandCollapsable();
257
369
  // Fill in valid data
258
370
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
259
- utils_1.fireEvent.change(utils_1.screen.getByLabelText('Item Name'), {
260
- target: { value: 'Test Item' }
261
- });
262
- utils_1.fireEvent.change(utils_1.screen.getByLabelText('Quantity'), {
263
- target: { value: '2' }
371
+ const nameInput = utils_1.screen.getByRole('textbox', { name: /item name/i });
372
+ const quantityInput = utils_1.screen.getByRole('spinbutton', {
373
+ name: /quantity/i
264
374
  });
375
+ yield utils_1.userEvent.type(nameInput, 'Test Item');
376
+ yield utils_1.userEvent.type(quantityInput, '2');
265
377
  }));
266
378
  // Submit the form
267
379
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
@@ -274,6 +386,7 @@ describe('AkiformBuilder', () => {
274
386
  });
275
387
  }));
276
388
  it('handles field array operations correctly', () => __awaiter(void 0, void 0, void 0, function* () {
389
+ const user = utils_1.userEvent.setup();
277
390
  const fields = [
278
391
  {
279
392
  key: 'items',
@@ -297,9 +410,8 @@ describe('AkiformBuilder', () => {
297
410
  (0, utils_1.render)(React.createElement(TestComponent, null));
298
411
  }));
299
412
  // Add an item
300
- yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
301
- utils_1.fireEvent.click(utils_1.screen.getByText('Add'));
302
- }));
413
+ yield user.click(utils_1.screen.getByTestId('items-add-button'));
414
+ yield expandCollapsable();
303
415
  // Fill in the fields
304
416
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
305
417
  utils_1.fireEvent.change(utils_1.screen.getByLabelText('Item Name'), {
@@ -381,7 +493,7 @@ describe('AkiformBuilder', () => {
381
493
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
382
494
  }));
383
495
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
384
- utils_1.fireEvent.change(utils_1.screen.getByLabelText('Email'), {
496
+ utils_1.fireEvent.change(utils_1.screen.getByRole('textbox', { name: /email/i }), {
385
497
  target: { value: 'invalid-email' }
386
498
  });
387
499
  utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
@@ -495,6 +607,8 @@ describe('AkiformBuilder', () => {
495
607
  key: 'customField',
496
608
  label: 'Custom Field',
497
609
  type: 'custom',
610
+ help: 'Help text',
611
+ labelDescription: 'Label description text',
498
612
  render: ({ field }) => (React.createElement(CustomComponent, { field: field }))
499
613
  }
500
614
  ];
@@ -502,6 +616,8 @@ describe('AkiformBuilder', () => {
502
616
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
503
617
  }));
504
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();
505
621
  }));
506
622
  it('cleans up throttle timeout on unmount', () => __awaiter(void 0, void 0, void 0, function* () {
507
623
  vi.useFakeTimers();
@@ -536,6 +652,33 @@ describe('AkiformBuilder', () => {
536
652
  // The form should still be rendered
537
653
  expect(utils_1.screen.getByTestId('akiform-builder')).toBeInTheDocument();
538
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
+ }));
539
682
  });
540
683
  describe('AkiformBuilder in controlled mode', () => {
541
684
  it('uses provided values in controlled mode', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -632,11 +775,12 @@ describe('AkiformBuilder', () => {
632
775
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
633
776
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn(), initialValues: initialValues }));
634
777
  }));
778
+ yield expandCollapsable();
635
779
  expect(utils_1.screen.getAllByLabelText('Item Name')).toHaveLength(2);
636
780
  expect(utils_1.screen.getAllByLabelText('Quantity')).toHaveLength(2);
637
- expect(utils_1.screen.getAllByText('Remove')).toHaveLength(2);
638
781
  }));
639
782
  it('adds and removes field array items', () => __awaiter(void 0, void 0, void 0, function* () {
783
+ const user = utils_1.userEvent.setup();
640
784
  const fields = [
641
785
  {
642
786
  key: 'items',
@@ -649,22 +793,20 @@ describe('AkiformBuilder', () => {
649
793
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
650
794
  }));
651
795
  // Add an item
652
- yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
653
- utils_1.fireEvent.click(utils_1.screen.getByText('Add'));
654
- }));
796
+ yield user.click(utils_1.screen.getByTestId('items-add-button'));
797
+ yield expandCollapsable();
655
798
  expect(utils_1.screen.getByLabelText('Item Name')).toBeInTheDocument();
656
799
  // Add another item
657
- yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
658
- utils_1.fireEvent.click(utils_1.screen.getByText('Add'));
659
- }));
800
+ yield user.click(utils_1.screen.getByLabelText('Add Items'));
801
+ yield expandCollapsable();
660
802
  expect(utils_1.screen.getAllByLabelText('Item Name')).toHaveLength(2);
661
803
  // Remove an item
662
- yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
663
- utils_1.fireEvent.click(utils_1.screen.getAllByText('Remove')[0]);
664
- }));
804
+ yield user.click(utils_1.screen.getAllByLabelText('Remove Items')[0]);
805
+ yield expandCollapsable();
665
806
  expect(utils_1.screen.getAllByLabelText('Item Name')).toHaveLength(1);
666
807
  }));
667
808
  it('handles field array with conditional fields', () => __awaiter(void 0, void 0, void 0, function* () {
809
+ const user = utils_1.userEvent.setup();
668
810
  const fields = [
669
811
  {
670
812
  key: 'items',
@@ -684,10 +826,10 @@ describe('AkiformBuilder', () => {
684
826
  }
685
827
  ];
686
828
  const { rerender } = (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
829
+ yield expandCollapsable();
687
830
  // Add an item
688
- yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
689
- utils_1.fireEvent.click(utils_1.screen.getByText('Add'));
690
- }));
831
+ yield user.click(utils_1.screen.getByLabelText('Add Items'));
832
+ yield expandCollapsable();
691
833
  // Description should not be visible initially
692
834
  expect(utils_1.screen.queryByLabelText('Description')).not.toBeInTheDocument();
693
835
  // Enter a name longer than 5 characters
@@ -718,9 +860,10 @@ describe('AkiformBuilder', () => {
718
860
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
719
861
  }));
720
862
  // The field array should be rendered with an "Add" button
721
- expect(utils_1.screen.getByText('Add')).toBeInTheDocument();
863
+ expect(utils_1.screen.getByTestId('emptyFieldArray-add-button')).toBeInTheDocument();
722
864
  }));
723
865
  it('handles form submission with field array', () => __awaiter(void 0, void 0, void 0, function* () {
866
+ const user = utils_1.userEvent.setup();
724
867
  const fields = [
725
868
  {
726
869
  key: 'items',
@@ -737,10 +880,9 @@ describe('AkiformBuilder', () => {
737
880
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
738
881
  }));
739
882
  // Add two items
740
- yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
741
- utils_1.fireEvent.click(utils_1.screen.getByText('Add'));
742
- utils_1.fireEvent.click(utils_1.screen.getByText('Add'));
743
- }));
883
+ yield user.click(utils_1.screen.getByTestId('items-add-button'));
884
+ yield user.click(utils_1.screen.getByLabelText('Add Items'));
885
+ yield expandCollapsable();
744
886
  // Fill in the fields
745
887
  const itemNames = utils_1.screen.getAllByLabelText('Item Name');
746
888
  const quantities = utils_1.screen.getAllByLabelText('Quantity');
@@ -798,7 +940,7 @@ describe('AkiformBuilder', () => {
798
940
  expect(utils_1.screen.getByLabelText('Checkbox')).toBeInTheDocument();
799
941
  expect(utils_1.screen.getByLabelText('Date')).toBeInTheDocument();
800
942
  expect(utils_1.screen.getByLabelText('Textarea')).toBeInTheDocument();
801
- expect(utils_1.screen.getByText('Add')).toBeInTheDocument(); // For field array
943
+ expect(utils_1.screen.getByTestId('fieldArray-add-button')).toBeInTheDocument(); // For field array
802
944
  expect(utils_1.screen.getByTestId('custom-field')).toBeInTheDocument();
803
945
  }));
804
946
  it('handles form with inline layout', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -827,6 +969,8 @@ describe('AkiformBuilder', () => {
827
969
  .label('Name')
828
970
  .type('text')
829
971
  .placeholder('Enter your name')
972
+ .help('Help text')
973
+ .labelDescription('Label description text')
830
974
  .build(),
831
975
  (0, field_builder_1.field)()
832
976
  .key('age')
@@ -854,7 +998,9 @@ describe('AkiformBuilder', () => {
854
998
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
855
999
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
856
1000
  }));
857
- expect(utils_1.screen.getByLabelText('Name')).toBeInTheDocument();
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();
858
1004
  expect(utils_1.screen.getByLabelText('Age')).toBeInTheDocument();
859
1005
  expect(utils_1.screen.getByLabelText('Country')).toBeInTheDocument();
860
1006
  expect(utils_1.screen.getByLabelText('Subscribe to newsletter')).toBeInTheDocument();
@@ -881,10 +1027,10 @@ describe('AkiformBuilder', () => {
881
1027
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
882
1028
  }));
883
1029
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
884
- utils_1.fireEvent.change(utils_1.screen.getByLabelText('Name'), {
1030
+ utils_1.fireEvent.change(utils_1.screen.getByRole('textbox', { name: /name/i }), {
885
1031
  target: { value: 'John Doe' }
886
1032
  });
887
- utils_1.fireEvent.change(utils_1.screen.getByLabelText('Age'), {
1033
+ utils_1.fireEvent.change(utils_1.screen.getByRole('spinbutton', { name: /age/i }), {
888
1034
  target: { value: '25' }
889
1035
  });
890
1036
  utils_1.fireEvent.submit(utils_1.screen.getByTestId('akiform-builder'));
@@ -903,6 +1049,8 @@ describe('AkiformBuilder', () => {
903
1049
  .key('customField')
904
1050
  .label('Custom Field')
905
1051
  .type('custom')
1052
+ .help('Help text')
1053
+ .labelDescription('Label description text')
906
1054
  .render(({ field }) => React.createElement(CustomComponent, { field: field }))
907
1055
  .build()
908
1056
  ];
@@ -910,15 +1058,25 @@ describe('AkiformBuilder', () => {
910
1058
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
911
1059
  }));
912
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();
913
1063
  }));
914
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();
915
1066
  const fields = [
916
1067
  (0, field_builder_1.field)()
917
1068
  .key('addresses')
918
1069
  .label('Addresses')
919
1070
  .type('fieldArray')
920
1071
  .fields([
921
- (0, field_builder_1.field)().key('street').label('Street').type('text').build(),
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(),
922
1080
  (0, field_builder_1.field)().key('city').label('City').type('text').build()
923
1081
  ])
924
1082
  .build()
@@ -928,12 +1086,16 @@ describe('AkiformBuilder', () => {
928
1086
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
929
1087
  }));
930
1088
  // Add an address
931
- yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
932
- utils_1.fireEvent.click(utils_1.screen.getByText('Add'));
933
- }));
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();
934
1096
  // Fill in the fields
935
1097
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
936
- utils_1.fireEvent.change(utils_1.screen.getByLabelText('Street'), {
1098
+ utils_1.fireEvent.change(utils_1.screen.getByPlaceholderText('Enter your street'), {
937
1099
  target: { value: '123 Main St' }
938
1100
  });
939
1101
  utils_1.fireEvent.change(utils_1.screen.getByLabelText('City'), {
@@ -1000,10 +1162,10 @@ describe('AkiformBuilder', () => {
1000
1162
  }));
1001
1163
  const form = utils_1.screen.getByRole('form');
1002
1164
  expect(form).toHaveAttribute('aria-label', 'Form');
1003
- const nameInput = utils_1.screen.getByLabelText('Name');
1165
+ const nameInput = utils_1.screen.getByRole('textbox', { name: /name/i });
1004
1166
  expect(nameInput).toHaveAttribute('aria-required', 'true');
1005
1167
  expect(nameInput).toHaveAttribute('aria-invalid', 'false');
1006
- const ageInput = utils_1.screen.getByLabelText('Age');
1168
+ const ageInput = utils_1.screen.getByRole('spinbutton', { name: /age/i });
1007
1169
  expect(ageInput).toHaveAttribute('aria-required', 'false');
1008
1170
  expect(ageInput).toHaveAttribute('aria-invalid', 'false');
1009
1171
  }));
@@ -1019,7 +1181,7 @@ describe('AkiformBuilder', () => {
1019
1181
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1020
1182
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1021
1183
  }));
1022
- const nameInput = utils_1.screen.getByLabelText('Name');
1184
+ const nameInput = utils_1.screen.getByRole('textbox', { name: /name/i });
1023
1185
  expect(nameInput).toHaveAttribute('aria-invalid', 'false');
1024
1186
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1025
1187
  utils_1.fireEvent.submit(utils_1.screen.getByRole('form'));
@@ -1030,6 +1192,7 @@ describe('AkiformBuilder', () => {
1030
1192
  });
1031
1193
  }));
1032
1194
  it('renders field array with proper ARIA attributes', () => __awaiter(void 0, void 0, void 0, function* () {
1195
+ const user = utils_1.userEvent.setup();
1033
1196
  const fields = [
1034
1197
  {
1035
1198
  key: 'addresses',
@@ -1044,16 +1207,15 @@ describe('AkiformBuilder', () => {
1044
1207
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1045
1208
  (0, utils_1.render)(React.createElement(akiform_builder_1.AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1046
1209
  }));
1210
+ yield user.click(utils_1.screen.getByTestId('addresses-add-button'));
1211
+ yield expandCollapsable();
1047
1212
  const fieldArrayGroup = utils_1.screen.getByRole('group', { name: 'Addresses' });
1048
1213
  expect(fieldArrayGroup).toBeInTheDocument();
1049
- const addButton = utils_1.screen.getByRole('button', { name: 'Add Addresses' });
1214
+ const addButton = utils_1.screen.getByLabelText('Add Addresses');
1050
1215
  expect(addButton).toBeInTheDocument();
1051
- yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
1052
- utils_1.fireEvent.click(addButton);
1053
- }));
1054
- const removeButton = utils_1.screen.getByRole('button', {
1055
- name: 'Remove Addresses 1'
1056
- });
1216
+ yield user.click(addButton);
1217
+ yield expandCollapsable();
1218
+ const removeButton = utils_1.screen.getAllByLabelText('Remove Addresses')[1];
1057
1219
  expect(removeButton).toBeInTheDocument();
1058
1220
  }));
1059
1221
  it('supports keyboard navigation', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -1087,15 +1249,24 @@ describe('AkiformBuilder', () => {
1087
1249
  .label('Personal Information')
1088
1250
  .type('section')
1089
1251
  .fields([
1090
- (0, field_builder_1.field)().key('name').label('Name').type('text').build(),
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(),
1091
1259
  (0, field_builder_1.field)().key('age').label('Age').type('number').build()
1092
1260
  ])
1261
+ .collapsible(true)
1093
1262
  .defaultExpanded(true)
1094
1263
  .build(),
1095
1264
  (0, field_builder_1.field)()
1096
1265
  .key('contactInfo')
1097
1266
  .label('Contact Information')
1098
1267
  .type('section')
1268
+ .collapsible(true)
1269
+ .defaultExpanded(false)
1099
1270
  .fields([
1100
1271
  (0, field_builder_1.field)().key('email').label('Email').type('text').build(),
1101
1272
  (0, field_builder_1.field)().key('phone').label('Phone').type('text').build()
@@ -1107,10 +1278,12 @@ describe('AkiformBuilder', () => {
1107
1278
  }));
1108
1279
  expect(utils_1.screen.getByText('Personal Information')).toBeInTheDocument();
1109
1280
  expect(utils_1.screen.getByText('Contact Information')).toBeInTheDocument();
1110
- expect(utils_1.screen.getByLabelText('Name')).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();
1111
1284
  expect(utils_1.screen.getByLabelText('Age')).toBeInTheDocument();
1112
1285
  // Check if the first section is expanded by default
1113
- expect(utils_1.screen.getByLabelText('Name')).toBeVisible();
1286
+ expect(utils_1.screen.getByText('Name').closest('label')).toBeVisible();
1114
1287
  // Check if the second section is collapsed by default
1115
1288
  expect(utils_1.screen.queryByLabelText('Email')).not.toBeInTheDocument();
1116
1289
  // Expand the second section
@@ -1166,18 +1339,19 @@ describe('AkiformBuilder', () => {
1166
1339
  delay: 1
1167
1340
  });
1168
1341
  // Wait for submit button to become interactable
1342
+ const submitButton = utils_1.screen.getByRole('button', { name: /submit/i });
1169
1343
  yield (0, utils_1.waitFor)(() => {
1170
- expect(utils_1.screen.getByRole('button', { name: 'Submit' })).toBeEnabled();
1344
+ expect(submitButton).toBeEnabled();
1171
1345
  });
1172
1346
  // Submit the form
1173
- yield utils_1.userEvent.click(utils_1.screen.getByRole('button', { name: 'SUBMIT' }));
1347
+ yield utils_1.userEvent.click(submitButton);
1174
1348
  // Validate submission
1175
1349
  expect(onSubmitMock).toHaveBeenCalledWith({
1176
1350
  name: 'John Doe',
1177
1351
  age: 30,
1178
1352
  email: 'john@example.com'
1179
1353
  }, expect.anything());
1180
- }), 10000);
1354
+ }));
1181
1355
  it('handles conditional rendering within sections', () => __awaiter(void 0, void 0, void 0, function* () {
1182
1356
  const fields = [
1183
1357
  (0, field_builder_1.field)()
@@ -1214,7 +1388,7 @@ describe('AkiformBuilder', () => {
1214
1388
  .key('name')
1215
1389
  .label('Name')
1216
1390
  .type('text')
1217
- .tooltip({ title: 'Enter your full name' })
1391
+ .tooltip({ title: 'Enter your full name', defaultOpen: true })
1218
1392
  .build()
1219
1393
  ];
1220
1394
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
@@ -1237,7 +1411,7 @@ describe('AkiformBuilder', () => {
1237
1411
  .key('email')
1238
1412
  .label('Email')
1239
1413
  .type('text')
1240
- .tooltip('Enter your email address')
1414
+ .tooltip({ title: 'Enter your full name', defaultOpen: true })
1241
1415
  .build()
1242
1416
  ];
1243
1417
  yield (0, react_1.act)(() => __awaiter(void 0, void 0, void 0, function* () {
@@ -1251,7 +1425,7 @@ describe('AkiformBuilder', () => {
1251
1425
  }));
1252
1426
  // Wait for the tooltip to appear
1253
1427
  yield (0, utils_1.waitFor)(() => {
1254
- expect(utils_1.screen.getByText('Enter your email address')).toBeInTheDocument();
1428
+ expect(utils_1.screen.getByText('Enter your full name')).toBeInTheDocument();
1255
1429
  });
1256
1430
  }));
1257
1431
  });