@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
@@ -19,6 +19,13 @@ describe('AkiformBuilder', () => {
19
19
  const mockOnSubmit = vi.fn();
20
20
  const mockOnReset = vi.fn();
21
21
  const mockOnValueChange = vi.fn();
22
+ const expandCollapsable = () => __awaiter(void 0, void 0, void 0, function* () {
23
+ const user = userEvent.setup();
24
+ const expandIcons = (yield screen.findAllByRole('button')).filter(el => el.className.includes('akinon-collapse-expand-icon'));
25
+ for (const expandIcon of expandIcons) {
26
+ yield user.click(expandIcon);
27
+ }
28
+ });
22
29
  const defaultFields = [
23
30
  {
24
31
  key: 'name',
@@ -30,7 +37,8 @@ describe('AkiformBuilder', () => {
30
37
  key: 'age',
31
38
  label: 'Age',
32
39
  type: 'number',
33
- placeholder: 'Enter your age'
40
+ placeholder: 'Enter your age',
41
+ help: 'Description text 2'
34
42
  }
35
43
  ];
36
44
  beforeEach(() => {
@@ -38,13 +46,100 @@ describe('AkiformBuilder', () => {
38
46
  });
39
47
  describe('AkiformBuilder in uncontrolled mode', () => {
40
48
  it('renders form fields correctly', () => __awaiter(void 0, void 0, void 0, function* () {
49
+ const newDefaultFields = defaultFields.map((field, key) => (Object.assign(Object.assign({}, field), { help: `Description text ${key}`, labelDescription: `Label description text ${key}` })));
41
50
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
42
- render(React.createElement(AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit }));
51
+ render(React.createElement(AkiformBuilder, { fields: newDefaultFields, onSubmit: mockOnSubmit }));
43
52
  }));
44
- expect(screen.getByLabelText('Name')).toBeInTheDocument();
45
- expect(screen.getByLabelText('Age')).toBeInTheDocument();
46
- expect(screen.getByPlaceholderText('Enter your name')).toBeInTheDocument();
47
- expect(screen.getByPlaceholderText('Enter your age')).toBeInTheDocument();
53
+ for (const field of newDefaultFields) {
54
+ if (field.label) {
55
+ expect(screen.getByText(field.label)).toBeInTheDocument();
56
+ }
57
+ if (field.placeholder) {
58
+ expect(screen.getByPlaceholderText(field.placeholder)).toBeInTheDocument();
59
+ }
60
+ expect(screen.getByText(field.help)).toBeInTheDocument();
61
+ expect(screen.getByText(field.labelDescription)).toBeInTheDocument();
62
+ }
63
+ }));
64
+ it('renders form fields correctly with row and column fields', () => __awaiter(void 0, void 0, void 0, function* () {
65
+ const newDefaultFields = [
66
+ {
67
+ type: 'row',
68
+ key: 'mainrow',
69
+ rowProps: {
70
+ align: 'middle'
71
+ },
72
+ columnFields: [
73
+ {
74
+ type: 'column',
75
+ key: 'col1',
76
+ columnProps: {
77
+ span: '24'
78
+ },
79
+ fields: [
80
+ {
81
+ type: 'row',
82
+ key: 'row1',
83
+ columnFields: [
84
+ {
85
+ type: 'column',
86
+ key: 'col1_1',
87
+ fields: [
88
+ {
89
+ type: 'text',
90
+ key: 'test1',
91
+ label: 'Test Field 1'
92
+ }
93
+ ]
94
+ }
95
+ ]
96
+ },
97
+ {
98
+ type: 'row',
99
+ key: 'row2',
100
+ columnFields: [
101
+ {
102
+ type: 'column',
103
+ key: 'col2_1',
104
+ fields: [
105
+ {
106
+ type: 'text',
107
+ key: 'test2',
108
+ label: 'Test Field 2'
109
+ }
110
+ ]
111
+ },
112
+ {
113
+ type: 'column',
114
+ key: 'col2_2',
115
+ fields: [
116
+ {
117
+ type: 'text',
118
+ key: 'test3',
119
+ label: 'Test Field 3'
120
+ }
121
+ ]
122
+ }
123
+ ]
124
+ }
125
+ ]
126
+ }
127
+ ]
128
+ }
129
+ ];
130
+ yield act(() => __awaiter(void 0, void 0, void 0, function* () {
131
+ render(React.createElement(AkiformBuilder, { fields: newDefaultFields, onSubmit: mockOnSubmit }));
132
+ }));
133
+ // Check fields
134
+ expect(screen.getByLabelText('Test Field 1')).toBeInTheDocument();
135
+ expect(screen.getByLabelText('Test Field 2')).toBeInTheDocument();
136
+ expect(screen.getByLabelText('Test Field 3')).toBeInTheDocument();
137
+ // Check row and column count
138
+ expect(document.querySelectorAll('.akinon-col')).toHaveLength(11);
139
+ expect(document.querySelectorAll('.akinon-row')).toHaveLength(7);
140
+ // Check props
141
+ expect(document.querySelector('.akinon-row-middle')).toBeInTheDocument();
142
+ expect(document.querySelector('.akinon-col-24')).toBeInTheDocument();
48
143
  }));
49
144
  it('handles form with custom field and onChange', () => __awaiter(void 0, void 0, void 0, function* () {
50
145
  const CustomComponent = ({ field, control }) => {
@@ -166,7 +261,14 @@ describe('AkiformBuilder', () => {
166
261
  }));
167
262
  it('renders different field types correctly', () => __awaiter(void 0, void 0, void 0, function* () {
168
263
  const fields = [
169
- { key: 'name', label: 'Name', type: 'text' },
264
+ {
265
+ key: 'name',
266
+ label: 'Name',
267
+ type: 'text',
268
+ help: 'Help text',
269
+ labelDescription: 'Label description text',
270
+ placeholder: 'Enter your name'
271
+ },
170
272
  { key: 'age', label: 'Age', type: 'number' },
171
273
  {
172
274
  key: 'gender',
@@ -184,7 +286,9 @@ describe('AkiformBuilder', () => {
184
286
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
185
287
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
186
288
  }));
187
- expect(screen.getByLabelText('Name')).toHaveAttribute('type', 'text');
289
+ expect(screen.getByPlaceholderText('Enter your name')).toHaveAttribute('type', 'text');
290
+ expect(screen.getByText('Help text')).toBeInTheDocument();
291
+ expect(screen.getByText('Label description text')).toBeInTheDocument();
188
292
  expect(screen.getByLabelText('Age')).toHaveClass('akinon-input-number-input');
189
293
  expect(screen.getByLabelText('Gender')).toBeInTheDocument();
190
294
  expect(screen.getByLabelText('Subscribe')).toHaveAttribute('type', 'checkbox');
@@ -192,29 +296,38 @@ describe('AkiformBuilder', () => {
192
296
  expect(screen.getByLabelText('Biography')).toBeInTheDocument();
193
297
  }));
194
298
  it('renders field array correctly', () => __awaiter(void 0, void 0, void 0, function* () {
299
+ const user = userEvent.setup();
195
300
  const fields = [
196
- {
197
- key: 'addresses',
198
- label: 'Addresses',
199
- type: 'fieldArray',
200
- fields: [
201
- { key: 'street', label: 'Street', type: 'text' },
202
- { key: 'city', label: 'City', type: 'text' }
203
- ]
204
- }
301
+ field()
302
+ .key('addresses')
303
+ .label('Addresses')
304
+ .type('fieldArray')
305
+ .defaultExpanded(true)
306
+ .fields([
307
+ field()
308
+ .key('street')
309
+ .label('Street')
310
+ .type('text')
311
+ .help('Help text')
312
+ .labelDescription('Label description text')
313
+ .build(),
314
+ field().key('city').label('City').type('text').build()
315
+ ])
316
+ .build()
205
317
  ];
206
318
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
207
319
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
208
320
  }));
209
- expect(screen.getByText('Add')).toBeInTheDocument();
210
- yield act(() => __awaiter(void 0, void 0, void 0, function* () {
211
- fireEvent.click(screen.getByText('Add'));
212
- }));
213
- expect(screen.getByLabelText('Street')).toBeInTheDocument();
214
- expect(screen.getByLabelText('City')).toBeInTheDocument();
215
- expect(screen.getByText('Remove')).toBeInTheDocument();
321
+ expect(screen.getByText('Add Addresses')).toBeInTheDocument();
322
+ yield user.click(screen.getByTestId('addresses-add-button'));
323
+ yield expandCollapsable();
324
+ expect(screen.getAllByText('Street')).toHaveLength(1);
325
+ expect(screen.getAllByText('City')).toHaveLength(1);
326
+ expect(screen.getByText('Help text')).toBeInTheDocument();
327
+ expect(screen.getByText('Label description text')).toBeInTheDocument();
216
328
  }));
217
329
  it('handles form with field array and nested validation', () => __awaiter(void 0, void 0, void 0, function* () {
330
+ const user = userEvent.setup();
218
331
  const fields = [
219
332
  {
220
333
  key: 'items',
@@ -241,25 +354,24 @@ describe('AkiformBuilder', () => {
241
354
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
242
355
  }));
243
356
  // Add an item
244
- yield act(() => __awaiter(void 0, void 0, void 0, function* () {
245
- fireEvent.click(screen.getByText('Add'));
246
- }));
357
+ yield user.click(screen.getByTestId('items-add-button'));
247
358
  // Try to submit without filling required fields
248
359
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
249
360
  fireEvent.submit(screen.getByTestId('akiform-builder'));
250
361
  }));
251
362
  yield waitFor(() => {
252
- expect(screen.getByText('Item name is required')).toBeInTheDocument();
363
+ expect(screen.getByText('An error occurred in here')).toBeInTheDocument();
253
364
  expect(onSubmitMock).not.toHaveBeenCalled();
254
365
  });
366
+ yield expandCollapsable();
255
367
  // Fill in valid data
256
368
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
257
- fireEvent.change(screen.getByLabelText('Item Name'), {
258
- target: { value: 'Test Item' }
259
- });
260
- fireEvent.change(screen.getByLabelText('Quantity'), {
261
- target: { value: '2' }
369
+ const nameInput = screen.getByRole('textbox', { name: /item name/i });
370
+ const quantityInput = screen.getByRole('spinbutton', {
371
+ name: /quantity/i
262
372
  });
373
+ yield userEvent.type(nameInput, 'Test Item');
374
+ yield userEvent.type(quantityInput, '2');
263
375
  }));
264
376
  // Submit the form
265
377
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
@@ -272,6 +384,7 @@ describe('AkiformBuilder', () => {
272
384
  });
273
385
  }));
274
386
  it('handles field array operations correctly', () => __awaiter(void 0, void 0, void 0, function* () {
387
+ const user = userEvent.setup();
275
388
  const fields = [
276
389
  {
277
390
  key: 'items',
@@ -295,9 +408,8 @@ describe('AkiformBuilder', () => {
295
408
  render(React.createElement(TestComponent, null));
296
409
  }));
297
410
  // Add an item
298
- yield act(() => __awaiter(void 0, void 0, void 0, function* () {
299
- fireEvent.click(screen.getByText('Add'));
300
- }));
411
+ yield user.click(screen.getByTestId('items-add-button'));
412
+ yield expandCollapsable();
301
413
  // Fill in the fields
302
414
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
303
415
  fireEvent.change(screen.getByLabelText('Item Name'), {
@@ -379,7 +491,7 @@ describe('AkiformBuilder', () => {
379
491
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: mockOnSubmit }));
380
492
  }));
381
493
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
382
- fireEvent.change(screen.getByLabelText('Email'), {
494
+ fireEvent.change(screen.getByRole('textbox', { name: /email/i }), {
383
495
  target: { value: 'invalid-email' }
384
496
  });
385
497
  fireEvent.submit(screen.getByTestId('akiform-builder'));
@@ -493,6 +605,8 @@ describe('AkiformBuilder', () => {
493
605
  key: 'customField',
494
606
  label: 'Custom Field',
495
607
  type: 'custom',
608
+ help: 'Help text',
609
+ labelDescription: 'Label description text',
496
610
  render: ({ field }) => (React.createElement(CustomComponent, { field: field }))
497
611
  }
498
612
  ];
@@ -500,6 +614,8 @@ describe('AkiformBuilder', () => {
500
614
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
501
615
  }));
502
616
  expect(screen.getByTestId('custom-field')).toHaveTextContent('Custom Field');
617
+ expect(screen.getByText('Help text')).toBeInTheDocument();
618
+ expect(screen.getByText('Label description text')).toBeInTheDocument();
503
619
  }));
504
620
  it('cleans up throttle timeout on unmount', () => __awaiter(void 0, void 0, void 0, function* () {
505
621
  vi.useFakeTimers();
@@ -534,6 +650,33 @@ describe('AkiformBuilder', () => {
534
650
  // The form should still be rendered
535
651
  expect(screen.getByTestId('akiform-builder')).toBeInTheDocument();
536
652
  }));
653
+ it('renders custom submit and reset button props', () => __awaiter(void 0, void 0, void 0, function* () {
654
+ const submitButtonProps = {
655
+ className: 'custom-submit-btn',
656
+ children: 'submit button'
657
+ };
658
+ const resetButtonProps = {
659
+ className: 'custom-reset-btn',
660
+ children: 'reset button'
661
+ };
662
+ yield act(() => __awaiter(void 0, void 0, void 0, function* () {
663
+ render(React.createElement(AkiformBuilder, { fields: defaultFields, onSubmit: mockOnSubmit, showResetButton: true, onReset: mockOnReset, submitButtonProps: submitButtonProps, resetButtonProps: resetButtonProps }));
664
+ }));
665
+ const submitButton = screen
666
+ .getByText(submitButtonProps.children)
667
+ .closest('button');
668
+ const resetButton = screen
669
+ .getByText(resetButtonProps.children)
670
+ .closest('button');
671
+ expect(submitButton).toBeInTheDocument();
672
+ expect(resetButton).toBeInTheDocument();
673
+ expect(submitButton).toHaveClass(submitButtonProps.className);
674
+ expect(resetButton).toHaveClass(resetButtonProps.className);
675
+ yield userEvent.click(resetButton);
676
+ expect(mockOnReset).toHaveBeenCalled();
677
+ yield userEvent.click(submitButton);
678
+ expect(mockOnSubmit).toHaveBeenCalled();
679
+ }));
537
680
  });
538
681
  describe('AkiformBuilder in controlled mode', () => {
539
682
  it('uses provided values in controlled mode', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -630,11 +773,12 @@ describe('AkiformBuilder', () => {
630
773
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
631
774
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: vi.fn(), initialValues: initialValues }));
632
775
  }));
776
+ yield expandCollapsable();
633
777
  expect(screen.getAllByLabelText('Item Name')).toHaveLength(2);
634
778
  expect(screen.getAllByLabelText('Quantity')).toHaveLength(2);
635
- expect(screen.getAllByText('Remove')).toHaveLength(2);
636
779
  }));
637
780
  it('adds and removes field array items', () => __awaiter(void 0, void 0, void 0, function* () {
781
+ const user = userEvent.setup();
638
782
  const fields = [
639
783
  {
640
784
  key: 'items',
@@ -647,22 +791,20 @@ describe('AkiformBuilder', () => {
647
791
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
648
792
  }));
649
793
  // Add an item
650
- yield act(() => __awaiter(void 0, void 0, void 0, function* () {
651
- fireEvent.click(screen.getByText('Add'));
652
- }));
794
+ yield user.click(screen.getByTestId('items-add-button'));
795
+ yield expandCollapsable();
653
796
  expect(screen.getByLabelText('Item Name')).toBeInTheDocument();
654
797
  // Add another item
655
- yield act(() => __awaiter(void 0, void 0, void 0, function* () {
656
- fireEvent.click(screen.getByText('Add'));
657
- }));
798
+ yield user.click(screen.getByLabelText('Add Items'));
799
+ yield expandCollapsable();
658
800
  expect(screen.getAllByLabelText('Item Name')).toHaveLength(2);
659
801
  // Remove an item
660
- yield act(() => __awaiter(void 0, void 0, void 0, function* () {
661
- fireEvent.click(screen.getAllByText('Remove')[0]);
662
- }));
802
+ yield user.click(screen.getAllByLabelText('Remove Items')[0]);
803
+ yield expandCollapsable();
663
804
  expect(screen.getAllByLabelText('Item Name')).toHaveLength(1);
664
805
  }));
665
806
  it('handles field array with conditional fields', () => __awaiter(void 0, void 0, void 0, function* () {
807
+ const user = userEvent.setup();
666
808
  const fields = [
667
809
  {
668
810
  key: 'items',
@@ -682,10 +824,10 @@ describe('AkiformBuilder', () => {
682
824
  }
683
825
  ];
684
826
  const { rerender } = render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
827
+ yield expandCollapsable();
685
828
  // Add an item
686
- yield act(() => __awaiter(void 0, void 0, void 0, function* () {
687
- fireEvent.click(screen.getByText('Add'));
688
- }));
829
+ yield user.click(screen.getByLabelText('Add Items'));
830
+ yield expandCollapsable();
689
831
  // Description should not be visible initially
690
832
  expect(screen.queryByLabelText('Description')).not.toBeInTheDocument();
691
833
  // Enter a name longer than 5 characters
@@ -716,9 +858,10 @@ describe('AkiformBuilder', () => {
716
858
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
717
859
  }));
718
860
  // The field array should be rendered with an "Add" button
719
- expect(screen.getByText('Add')).toBeInTheDocument();
861
+ expect(screen.getByTestId('emptyFieldArray-add-button')).toBeInTheDocument();
720
862
  }));
721
863
  it('handles form submission with field array', () => __awaiter(void 0, void 0, void 0, function* () {
864
+ const user = userEvent.setup();
722
865
  const fields = [
723
866
  {
724
867
  key: 'items',
@@ -735,10 +878,9 @@ describe('AkiformBuilder', () => {
735
878
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
736
879
  }));
737
880
  // Add two items
738
- yield act(() => __awaiter(void 0, void 0, void 0, function* () {
739
- fireEvent.click(screen.getByText('Add'));
740
- fireEvent.click(screen.getByText('Add'));
741
- }));
881
+ yield user.click(screen.getByTestId('items-add-button'));
882
+ yield user.click(screen.getByLabelText('Add Items'));
883
+ yield expandCollapsable();
742
884
  // Fill in the fields
743
885
  const itemNames = screen.getAllByLabelText('Item Name');
744
886
  const quantities = screen.getAllByLabelText('Quantity');
@@ -796,7 +938,7 @@ describe('AkiformBuilder', () => {
796
938
  expect(screen.getByLabelText('Checkbox')).toBeInTheDocument();
797
939
  expect(screen.getByLabelText('Date')).toBeInTheDocument();
798
940
  expect(screen.getByLabelText('Textarea')).toBeInTheDocument();
799
- expect(screen.getByText('Add')).toBeInTheDocument(); // For field array
941
+ expect(screen.getByTestId('fieldArray-add-button')).toBeInTheDocument(); // For field array
800
942
  expect(screen.getByTestId('custom-field')).toBeInTheDocument();
801
943
  }));
802
944
  it('handles form with inline layout', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -825,6 +967,8 @@ describe('AkiformBuilder', () => {
825
967
  .label('Name')
826
968
  .type('text')
827
969
  .placeholder('Enter your name')
970
+ .help('Help text')
971
+ .labelDescription('Label description text')
828
972
  .build(),
829
973
  field()
830
974
  .key('age')
@@ -852,7 +996,9 @@ describe('AkiformBuilder', () => {
852
996
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
853
997
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
854
998
  }));
855
- expect(screen.getByLabelText('Name')).toBeInTheDocument();
999
+ expect(screen.getByText('Name')).toBeInTheDocument();
1000
+ expect(screen.getByText('Label description text')).toBeInTheDocument();
1001
+ expect(screen.getByText('Help text')).toBeInTheDocument();
856
1002
  expect(screen.getByLabelText('Age')).toBeInTheDocument();
857
1003
  expect(screen.getByLabelText('Country')).toBeInTheDocument();
858
1004
  expect(screen.getByLabelText('Subscribe to newsletter')).toBeInTheDocument();
@@ -879,10 +1025,10 @@ describe('AkiformBuilder', () => {
879
1025
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
880
1026
  }));
881
1027
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
882
- fireEvent.change(screen.getByLabelText('Name'), {
1028
+ fireEvent.change(screen.getByRole('textbox', { name: /name/i }), {
883
1029
  target: { value: 'John Doe' }
884
1030
  });
885
- fireEvent.change(screen.getByLabelText('Age'), {
1031
+ fireEvent.change(screen.getByRole('spinbutton', { name: /age/i }), {
886
1032
  target: { value: '25' }
887
1033
  });
888
1034
  fireEvent.submit(screen.getByTestId('akiform-builder'));
@@ -901,6 +1047,8 @@ describe('AkiformBuilder', () => {
901
1047
  .key('customField')
902
1048
  .label('Custom Field')
903
1049
  .type('custom')
1050
+ .help('Help text')
1051
+ .labelDescription('Label description text')
904
1052
  .render(({ field }) => React.createElement(CustomComponent, { field: field }))
905
1053
  .build()
906
1054
  ];
@@ -908,15 +1056,25 @@ describe('AkiformBuilder', () => {
908
1056
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
909
1057
  }));
910
1058
  expect(screen.getByTestId('custom-field')).toHaveTextContent('Custom Field');
1059
+ expect(screen.getByText('Help text')).toBeInTheDocument();
1060
+ expect(screen.getByText('Label description text')).toBeInTheDocument();
911
1061
  }));
912
1062
  it('handles form with field array created by FieldBuilder', () => __awaiter(void 0, void 0, void 0, function* () {
1063
+ const user = userEvent.setup();
913
1064
  const fields = [
914
1065
  field()
915
1066
  .key('addresses')
916
1067
  .label('Addresses')
917
1068
  .type('fieldArray')
918
1069
  .fields([
919
- field().key('street').label('Street').type('text').build(),
1070
+ field()
1071
+ .key('street')
1072
+ .label('Street')
1073
+ .type('text')
1074
+ .help('Help text')
1075
+ .labelDescription('Label description text')
1076
+ .placeholder('Enter your street')
1077
+ .build(),
920
1078
  field().key('city').label('City').type('text').build()
921
1079
  ])
922
1080
  .build()
@@ -926,12 +1084,16 @@ describe('AkiformBuilder', () => {
926
1084
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: onSubmitMock }));
927
1085
  }));
928
1086
  // Add an address
929
- yield act(() => __awaiter(void 0, void 0, void 0, function* () {
930
- fireEvent.click(screen.getByText('Add'));
931
- }));
1087
+ yield user.click(screen.getByTestId('addresses-add-button'));
1088
+ yield expandCollapsable();
1089
+ //Check rendered fields
1090
+ expect(screen.getByText('Street')).toBeInTheDocument();
1091
+ expect(screen.getByText('Help text')).toBeInTheDocument();
1092
+ expect(screen.getByText('Label description text')).toBeInTheDocument();
1093
+ expect(screen.getByLabelText('City')).toBeInTheDocument();
932
1094
  // Fill in the fields
933
1095
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
934
- fireEvent.change(screen.getByLabelText('Street'), {
1096
+ fireEvent.change(screen.getByPlaceholderText('Enter your street'), {
935
1097
  target: { value: '123 Main St' }
936
1098
  });
937
1099
  fireEvent.change(screen.getByLabelText('City'), {
@@ -998,10 +1160,10 @@ describe('AkiformBuilder', () => {
998
1160
  }));
999
1161
  const form = screen.getByRole('form');
1000
1162
  expect(form).toHaveAttribute('aria-label', 'Form');
1001
- const nameInput = screen.getByLabelText('Name');
1163
+ const nameInput = screen.getByRole('textbox', { name: /name/i });
1002
1164
  expect(nameInput).toHaveAttribute('aria-required', 'true');
1003
1165
  expect(nameInput).toHaveAttribute('aria-invalid', 'false');
1004
- const ageInput = screen.getByLabelText('Age');
1166
+ const ageInput = screen.getByRole('spinbutton', { name: /age/i });
1005
1167
  expect(ageInput).toHaveAttribute('aria-required', 'false');
1006
1168
  expect(ageInput).toHaveAttribute('aria-invalid', 'false');
1007
1169
  }));
@@ -1017,7 +1179,7 @@ describe('AkiformBuilder', () => {
1017
1179
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
1018
1180
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1019
1181
  }));
1020
- const nameInput = screen.getByLabelText('Name');
1182
+ const nameInput = screen.getByRole('textbox', { name: /name/i });
1021
1183
  expect(nameInput).toHaveAttribute('aria-invalid', 'false');
1022
1184
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
1023
1185
  fireEvent.submit(screen.getByRole('form'));
@@ -1028,6 +1190,7 @@ describe('AkiformBuilder', () => {
1028
1190
  });
1029
1191
  }));
1030
1192
  it('renders field array with proper ARIA attributes', () => __awaiter(void 0, void 0, void 0, function* () {
1193
+ const user = userEvent.setup();
1031
1194
  const fields = [
1032
1195
  {
1033
1196
  key: 'addresses',
@@ -1042,16 +1205,15 @@ describe('AkiformBuilder', () => {
1042
1205
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
1043
1206
  render(React.createElement(AkiformBuilder, { fields: fields, onSubmit: vi.fn() }));
1044
1207
  }));
1208
+ yield user.click(screen.getByTestId('addresses-add-button'));
1209
+ yield expandCollapsable();
1045
1210
  const fieldArrayGroup = screen.getByRole('group', { name: 'Addresses' });
1046
1211
  expect(fieldArrayGroup).toBeInTheDocument();
1047
- const addButton = screen.getByRole('button', { name: 'Add Addresses' });
1212
+ const addButton = screen.getByLabelText('Add Addresses');
1048
1213
  expect(addButton).toBeInTheDocument();
1049
- yield act(() => __awaiter(void 0, void 0, void 0, function* () {
1050
- fireEvent.click(addButton);
1051
- }));
1052
- const removeButton = screen.getByRole('button', {
1053
- name: 'Remove Addresses 1'
1054
- });
1214
+ yield user.click(addButton);
1215
+ yield expandCollapsable();
1216
+ const removeButton = screen.getAllByLabelText('Remove Addresses')[1];
1055
1217
  expect(removeButton).toBeInTheDocument();
1056
1218
  }));
1057
1219
  it('supports keyboard navigation', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -1085,15 +1247,24 @@ describe('AkiformBuilder', () => {
1085
1247
  .label('Personal Information')
1086
1248
  .type('section')
1087
1249
  .fields([
1088
- field().key('name').label('Name').type('text').build(),
1250
+ field()
1251
+ .key('name')
1252
+ .label('Name')
1253
+ .type('text')
1254
+ .help('Help text')
1255
+ .labelDescription('Label description text')
1256
+ .build(),
1089
1257
  field().key('age').label('Age').type('number').build()
1090
1258
  ])
1259
+ .collapsible(true)
1091
1260
  .defaultExpanded(true)
1092
1261
  .build(),
1093
1262
  field()
1094
1263
  .key('contactInfo')
1095
1264
  .label('Contact Information')
1096
1265
  .type('section')
1266
+ .collapsible(true)
1267
+ .defaultExpanded(false)
1097
1268
  .fields([
1098
1269
  field().key('email').label('Email').type('text').build(),
1099
1270
  field().key('phone').label('Phone').type('text').build()
@@ -1105,10 +1276,12 @@ describe('AkiformBuilder', () => {
1105
1276
  }));
1106
1277
  expect(screen.getByText('Personal Information')).toBeInTheDocument();
1107
1278
  expect(screen.getByText('Contact Information')).toBeInTheDocument();
1108
- expect(screen.getByLabelText('Name')).toBeInTheDocument();
1279
+ expect(screen.getByText('Name')).toBeInTheDocument();
1280
+ expect(screen.getByText('Help text')).toBeInTheDocument();
1281
+ expect(screen.getByText('Label description text')).toBeInTheDocument();
1109
1282
  expect(screen.getByLabelText('Age')).toBeInTheDocument();
1110
1283
  // Check if the first section is expanded by default
1111
- expect(screen.getByLabelText('Name')).toBeVisible();
1284
+ expect(screen.getByText('Name').closest('label')).toBeVisible();
1112
1285
  // Check if the second section is collapsed by default
1113
1286
  expect(screen.queryByLabelText('Email')).not.toBeInTheDocument();
1114
1287
  // Expand the second section
@@ -1164,18 +1337,19 @@ describe('AkiformBuilder', () => {
1164
1337
  delay: 1
1165
1338
  });
1166
1339
  // Wait for submit button to become interactable
1340
+ const submitButton = screen.getByRole('button', { name: /submit/i });
1167
1341
  yield waitFor(() => {
1168
- expect(screen.getByRole('button', { name: 'Submit' })).toBeEnabled();
1342
+ expect(submitButton).toBeEnabled();
1169
1343
  });
1170
1344
  // Submit the form
1171
- yield userEvent.click(screen.getByRole('button', { name: 'SUBMIT' }));
1345
+ yield userEvent.click(submitButton);
1172
1346
  // Validate submission
1173
1347
  expect(onSubmitMock).toHaveBeenCalledWith({
1174
1348
  name: 'John Doe',
1175
1349
  age: 30,
1176
1350
  email: 'john@example.com'
1177
1351
  }, expect.anything());
1178
- }), 10000);
1352
+ }));
1179
1353
  it('handles conditional rendering within sections', () => __awaiter(void 0, void 0, void 0, function* () {
1180
1354
  const fields = [
1181
1355
  field()
@@ -1212,7 +1386,7 @@ describe('AkiformBuilder', () => {
1212
1386
  .key('name')
1213
1387
  .label('Name')
1214
1388
  .type('text')
1215
- .tooltip({ title: 'Enter your full name' })
1389
+ .tooltip({ title: 'Enter your full name', defaultOpen: true })
1216
1390
  .build()
1217
1391
  ];
1218
1392
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
@@ -1235,7 +1409,7 @@ describe('AkiformBuilder', () => {
1235
1409
  .key('email')
1236
1410
  .label('Email')
1237
1411
  .type('text')
1238
- .tooltip('Enter your email address')
1412
+ .tooltip({ title: 'Enter your full name', defaultOpen: true })
1239
1413
  .build()
1240
1414
  ];
1241
1415
  yield act(() => __awaiter(void 0, void 0, void 0, function* () {
@@ -1249,7 +1423,7 @@ describe('AkiformBuilder', () => {
1249
1423
  }));
1250
1424
  // Wait for the tooltip to appear
1251
1425
  yield waitFor(() => {
1252
- expect(screen.getByText('Enter your email address')).toBeInTheDocument();
1426
+ expect(screen.getByText('Enter your full name')).toBeInTheDocument();
1253
1427
  });
1254
1428
  }));
1255
1429
  });