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