@akinon/akiform-builder 1.0.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.
- package/dist/cjs/__tests__/akiform-builder.test.js +257 -83
- package/dist/cjs/__tests__/field-builder.test.js +48 -3
- package/dist/cjs/index.css +10 -0
- package/dist/cjs/src/akiform-builder.d.ts.map +1 -1
- package/dist/cjs/src/akiform-builder.js +230 -63
- package/dist/cjs/src/field-builder.d.ts +22 -5
- package/dist/cjs/src/field-builder.d.ts.map +1 -1
- package/dist/cjs/src/field-builder.js +81 -22
- package/dist/cjs/src/i18n/translations/en.d.ts +7 -0
- package/dist/cjs/src/i18n/translations/en.d.ts.map +1 -1
- package/dist/cjs/src/i18n/translations/en.js +8 -1
- package/dist/cjs/src/i18n/translations/tr.d.ts +7 -0
- package/dist/cjs/src/i18n/translations/tr.d.ts.map +1 -1
- package/dist/cjs/src/i18n/translations/tr.js +8 -1
- package/dist/cjs/src/types.d.ts +27 -5
- package/dist/cjs/src/types.d.ts.map +1 -1
- package/dist/esm/__tests__/akiform-builder.test.js +257 -83
- package/dist/esm/__tests__/field-builder.test.js +48 -3
- package/dist/esm/index.css +10 -0
- package/dist/esm/src/akiform-builder.d.ts.map +1 -1
- package/dist/esm/src/akiform-builder.js +231 -64
- package/dist/esm/src/field-builder.d.ts +22 -5
- package/dist/esm/src/field-builder.d.ts.map +1 -1
- package/dist/esm/src/field-builder.js +81 -22
- package/dist/esm/src/i18n/translations/en.d.ts +7 -0
- package/dist/esm/src/i18n/translations/en.d.ts.map +1 -1
- package/dist/esm/src/i18n/translations/en.js +8 -1
- package/dist/esm/src/i18n/translations/tr.d.ts +7 -0
- package/dist/esm/src/i18n/translations/tr.d.ts.map +1 -1
- package/dist/esm/src/i18n/translations/tr.js +8 -1
- package/dist/esm/src/types.d.ts +27 -5
- package/dist/esm/src/types.d.ts.map +1 -1
- 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:
|
|
51
|
+
render(React.createElement(AkiformBuilder, { fields: newDefaultFields, onSubmit: mockOnSubmit }));
|
|
43
52
|
}));
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
{
|
|
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.
|
|
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
|
|
198
|
-
label
|
|
199
|
-
type
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
expect(screen.
|
|
214
|
-
expect(screen.
|
|
215
|
-
expect(screen.getByText('
|
|
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
|
|
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('
|
|
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
|
-
|
|
258
|
-
|
|
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
|
|
299
|
-
|
|
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.
|
|
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
|
|
651
|
-
|
|
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
|
|
656
|
-
|
|
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
|
|
661
|
-
|
|
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
|
|
687
|
-
|
|
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.
|
|
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
|
|
739
|
-
|
|
740
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
1028
|
+
fireEvent.change(screen.getByRole('textbox', { name: /name/i }), {
|
|
883
1029
|
target: { value: 'John Doe' }
|
|
884
1030
|
});
|
|
885
|
-
fireEvent.change(screen.
|
|
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()
|
|
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
|
|
930
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
1212
|
+
const addButton = screen.getByLabelText('Add Addresses');
|
|
1048
1213
|
expect(addButton).toBeInTheDocument();
|
|
1049
|
-
yield
|
|
1050
|
-
|
|
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()
|
|
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.
|
|
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.
|
|
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(
|
|
1342
|
+
expect(submitButton).toBeEnabled();
|
|
1169
1343
|
});
|
|
1170
1344
|
// Submit the form
|
|
1171
|
-
yield userEvent.click(
|
|
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
|
-
})
|
|
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
|
|
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
|
|
1426
|
+
expect(screen.getByText('Enter your full name')).toBeInTheDocument();
|
|
1253
1427
|
});
|
|
1254
1428
|
}));
|
|
1255
1429
|
});
|