@imposium-hub/components 2.15.0-3 → 2.16.0
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/components/app-wrapper/AppWrapper.d.ts +0 -1
- package/dist/cjs/components/app-wrapper/AppWrapper.js +1 -1
- package/dist/cjs/components/app-wrapper/AppWrapper.js.map +1 -1
- package/dist/cjs/components/assets/AssetsTypeIcon.js +2 -0
- package/dist/cjs/components/assets/AssetsTypeIcon.js.map +1 -1
- package/dist/cjs/components/change-report/ChangeReportTree.js +65 -10
- package/dist/cjs/components/change-report/ChangeReportTree.js.map +1 -1
- package/dist/cjs/components/number-field/NumberField.d.ts +2 -2
- package/dist/cjs/components/number-field/NumberField.js +7 -4
- package/dist/cjs/components/number-field/NumberField.js.map +1 -1
- package/dist/cjs/components/publish-wizard/PublishWizard.js +40 -39
- package/dist/cjs/components/publish-wizard/PublishWizard.js.map +1 -1
- package/dist/cjs/constants/copy.d.ts +1 -0
- package/dist/cjs/constants/copy.js +3 -2
- package/dist/cjs/constants/copy.js.map +1 -1
- package/dist/cjs/constants/icons.d.ts +5 -0
- package/dist/cjs/constants/icons.js +12 -2
- package/dist/cjs/constants/icons.js.map +1 -1
- package/dist/cjs/constants/snippets.d.ts +2 -0
- package/dist/cjs/redux/actions/publish.d.ts +1 -1
- package/dist/cjs/redux/actions/publish.js +2 -2
- package/dist/cjs/redux/actions/publish.js.map +1 -1
- package/dist/esm/components/app-wrapper/AppWrapper.d.ts +0 -1
- package/dist/esm/components/app-wrapper/AppWrapper.js +1 -1
- package/dist/esm/components/app-wrapper/AppWrapper.js.map +1 -1
- package/dist/esm/components/assets/AssetsTypeIcon.js +2 -0
- package/dist/esm/components/assets/AssetsTypeIcon.js.map +1 -1
- package/dist/esm/components/change-report/ChangeReportTree.js +64 -10
- package/dist/esm/components/change-report/ChangeReportTree.js.map +1 -1
- package/dist/esm/components/number-field/NumberField.d.ts +2 -2
- package/dist/esm/components/number-field/NumberField.js +5 -4
- package/dist/esm/components/number-field/NumberField.js.map +1 -1
- package/dist/esm/components/publish-wizard/PublishWizard.js +40 -39
- package/dist/esm/components/publish-wizard/PublishWizard.js.map +1 -1
- package/dist/esm/constants/copy.d.ts +1 -0
- package/dist/esm/constants/copy.js +3 -2
- package/dist/esm/constants/copy.js.map +1 -1
- package/dist/esm/constants/icons.d.ts +5 -0
- package/dist/esm/constants/icons.js +10 -0
- package/dist/esm/constants/icons.js.map +1 -1
- package/dist/esm/constants/snippets.d.ts +2 -0
- package/dist/esm/redux/actions/publish.d.ts +1 -1
- package/dist/esm/redux/actions/publish.js +2 -2
- package/dist/esm/redux/actions/publish.js.map +1 -1
- package/dist/styles.css +54 -10
- package/dist/styles.less +65 -13
- package/less/components/change-report.less +50 -9
- package/less/components/publish-wizard.less +15 -4
- package/package.json +5 -1
- package/src/components/advanced-number-field/AdvancedNumberField.test.tsx +724 -0
- package/src/components/anchor-field/AnchorField.test.tsx +130 -0
- package/src/components/app-wrapper/AppWrapper.tsx +1 -6
- package/src/components/asset-details/AssetDetails.test.tsx +494 -0
- package/src/components/assets/AssetField.test.tsx +449 -0
- package/src/components/assets/AssetsTableAssetIdCell.test.tsx +142 -0
- package/src/components/assets/AssetsTableAssetIdFilter.test.tsx +95 -0
- package/src/components/assets/AssetsTableComplexTagCell.test.tsx +161 -0
- package/src/components/assets/AssetsTableDateCell.test.tsx +106 -0
- package/src/components/assets/AssetsTableDropzone.test.tsx +132 -0
- package/src/components/assets/AssetsTableDurationCell.test.tsx +119 -0
- package/src/components/assets/AssetsTableGlobalCell.test.tsx +46 -0
- package/src/components/assets/AssetsTableNameCell.test.tsx +166 -0
- package/src/components/assets/AssetsTableNameFilter.test.tsx +95 -0
- package/src/components/assets/AssetsTablePreviewCell.test.tsx +191 -0
- package/src/components/assets/AssetsTableRateCell.test.tsx +87 -0
- package/src/components/assets/AssetsTableSelectCell.test.tsx +156 -0
- package/src/components/assets/AssetsTableSelectFilter.test.tsx +119 -0
- package/src/components/assets/AssetsTableStatusCell.test.tsx +60 -0
- package/src/components/assets/AssetsTypeIcon.tsx +2 -0
- package/src/components/change-report/ChangeReportTree.tsx +104 -16
- package/src/components/number-field/NumberField.test.tsx +383 -0
- package/src/components/number-field/NumberField.tsx +15 -9
- package/src/components/publish-wizard/PublishWizard.tsx +59 -54
- package/src/components/text-field/TextField.test.tsx +988 -0
- package/src/constants/copy.ts +3 -2
- package/src/constants/icons.tsx +10 -0
- package/src/constants/snippets.ts +2 -0
- package/src/redux/actions/publish.ts +7 -2
- package/src/test/setup.ts +91 -0
- package/src/test/utils.tsx +44 -0
- package/tsconfig.eslint.json +8 -0
- package/tsconfig.json +1 -1
- package/vitest.config.ts +31 -0
- package/src/components/service-icon/ServiceIcon.test.tsx +0 -0
|
@@ -0,0 +1,724 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, fireEvent, screen } from '../../test/utils';
|
|
3
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
4
|
+
import AdvancedNumberField from './AdvancedNumberField';
|
|
5
|
+
|
|
6
|
+
describe('AdvancedNumberField', () => {
|
|
7
|
+
const defaultProps = {
|
|
8
|
+
value: 12,
|
|
9
|
+
onChange: vi.fn(),
|
|
10
|
+
label: 'Test Advanced Number Field',
|
|
11
|
+
activeOverride: 'test-override'
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
vi.clearAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('Basic Rendering', () => {
|
|
19
|
+
it('renders without crashing', () => {
|
|
20
|
+
render(<AdvancedNumberField {...defaultProps} />);
|
|
21
|
+
const input = screen.getByRole('spinbutton');
|
|
22
|
+
expect(input).toBeDefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('displays the correct value', () => {
|
|
26
|
+
render(
|
|
27
|
+
<AdvancedNumberField
|
|
28
|
+
{...defaultProps}
|
|
29
|
+
value={25}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
const input: HTMLInputElement = screen.getByRole('spinbutton');
|
|
33
|
+
expect(input.value).toBe('25');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('displays placeholder when provided', () => {
|
|
37
|
+
render(
|
|
38
|
+
<AdvancedNumberField
|
|
39
|
+
{...defaultProps}
|
|
40
|
+
placeholder='Enter font size'
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
const input: HTMLInputElement = screen.getByRole('spinbutton');
|
|
44
|
+
expect(input.placeholder).toBe('Enter font size');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('sets readOnly attribute when readOnly prop is true', () => {
|
|
48
|
+
render(
|
|
49
|
+
<AdvancedNumberField
|
|
50
|
+
{...defaultProps}
|
|
51
|
+
readOnly
|
|
52
|
+
/>
|
|
53
|
+
);
|
|
54
|
+
const input: HTMLInputElement = screen.getByRole('spinbutton');
|
|
55
|
+
expect(input.readOnly).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('applies min and max attributes', () => {
|
|
59
|
+
render(
|
|
60
|
+
<AdvancedNumberField
|
|
61
|
+
{...defaultProps}
|
|
62
|
+
min={8}
|
|
63
|
+
max={72}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
const input: HTMLInputElement = screen.getByRole('spinbutton');
|
|
67
|
+
expect(input.min).toBe('8');
|
|
68
|
+
expect(input.max).toBe('72');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('renders increment and decrement buttons', () => {
|
|
72
|
+
const { container } = render(<AdvancedNumberField {...defaultProps} />);
|
|
73
|
+
|
|
74
|
+
const decrementButton: HTMLInputElement | null =
|
|
75
|
+
container.querySelector('.minus-font-size');
|
|
76
|
+
const incrementButton: HTMLInputElement | null =
|
|
77
|
+
container.querySelector('.add-font-size');
|
|
78
|
+
|
|
79
|
+
if (decrementButton && incrementButton) {
|
|
80
|
+
expect(decrementButton).toBeDefined();
|
|
81
|
+
expect(incrementButton).toBeDefined();
|
|
82
|
+
expect(decrementButton.value).toBe('-');
|
|
83
|
+
expect(incrementButton.value).toBe('+');
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('renders with custom width', () => {
|
|
88
|
+
const { container } = render(
|
|
89
|
+
<AdvancedNumberField
|
|
90
|
+
{...defaultProps}
|
|
91
|
+
width='200px'
|
|
92
|
+
/>
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const fieldWrapper = container.querySelector('[data-testid="field-wrapper"]');
|
|
96
|
+
expect(fieldWrapper).toBeDefined();
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('Value Changes', () => {
|
|
101
|
+
it('calls onChange when value is typed', () => {
|
|
102
|
+
const onChange = vi.fn();
|
|
103
|
+
render(
|
|
104
|
+
<AdvancedNumberField
|
|
105
|
+
{...defaultProps}
|
|
106
|
+
onChange={onChange}
|
|
107
|
+
/>
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const input = screen.getByRole('spinbutton');
|
|
111
|
+
fireEvent.change(input, { target: { value: '18' } });
|
|
112
|
+
|
|
113
|
+
expect(onChange).toHaveBeenCalledWith(18);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('calls onChange with null when empty string is entered', () => {
|
|
117
|
+
const onChange = vi.fn();
|
|
118
|
+
render(
|
|
119
|
+
<AdvancedNumberField
|
|
120
|
+
{...defaultProps}
|
|
121
|
+
onChange={onChange}
|
|
122
|
+
/>
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const input = screen.getByRole('spinbutton');
|
|
126
|
+
fireEvent.change(input, { target: { value: '' } });
|
|
127
|
+
|
|
128
|
+
expect(onChange).toHaveBeenCalledWith(null);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('parses float values correctly', () => {
|
|
132
|
+
const onChange = vi.fn();
|
|
133
|
+
render(
|
|
134
|
+
<AdvancedNumberField
|
|
135
|
+
{...defaultProps}
|
|
136
|
+
onChange={onChange}
|
|
137
|
+
/>
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const input = screen.getByRole('spinbutton');
|
|
141
|
+
fireEvent.change(input, { target: { value: '14.5' } });
|
|
142
|
+
|
|
143
|
+
expect(onChange).toHaveBeenCalledWith(14.5);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe('Increment/Decrement Buttons', () => {
|
|
148
|
+
it('increments value when plus button is clicked', () => {
|
|
149
|
+
const onChange = vi.fn();
|
|
150
|
+
const { container } = render(
|
|
151
|
+
<AdvancedNumberField
|
|
152
|
+
{...defaultProps}
|
|
153
|
+
value={12}
|
|
154
|
+
onChange={onChange}
|
|
155
|
+
/>
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
const incrementButton = container.querySelector('.add-font-size');
|
|
159
|
+
if (incrementButton) {
|
|
160
|
+
fireEvent.click(incrementButton);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
expect(onChange).toHaveBeenCalledWith(13);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('decrements value when minus button is clicked', () => {
|
|
167
|
+
const onChange = vi.fn();
|
|
168
|
+
const { container } = render(
|
|
169
|
+
<AdvancedNumberField
|
|
170
|
+
{...defaultProps}
|
|
171
|
+
value={12}
|
|
172
|
+
onChange={onChange}
|
|
173
|
+
/>
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const decrementButton = container.querySelector('.minus-font-size');
|
|
177
|
+
if (decrementButton) {
|
|
178
|
+
fireEvent.click(decrementButton);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
expect(onChange).toHaveBeenCalledWith(11);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('does not call onChange when incrementing would exceed max', () => {
|
|
185
|
+
const onChange = vi.fn();
|
|
186
|
+
const { container } = render(
|
|
187
|
+
<AdvancedNumberField
|
|
188
|
+
{...defaultProps}
|
|
189
|
+
value={72}
|
|
190
|
+
max={72}
|
|
191
|
+
onChange={onChange}
|
|
192
|
+
/>
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const incrementButton = container.querySelector('.add-font-size');
|
|
196
|
+
if (incrementButton) {
|
|
197
|
+
fireEvent.click(incrementButton);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('does not call onChange when decrementing would go below min', () => {
|
|
204
|
+
const onChange = vi.fn();
|
|
205
|
+
const { container } = render(
|
|
206
|
+
<AdvancedNumberField
|
|
207
|
+
{...defaultProps}
|
|
208
|
+
value={8}
|
|
209
|
+
min={8}
|
|
210
|
+
onChange={onChange}
|
|
211
|
+
/>
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const decrementButton = container.querySelector('.minus-font-size');
|
|
215
|
+
if (decrementButton) {
|
|
216
|
+
fireEvent.click(decrementButton);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
expect(onChange).not.toHaveBeenCalled();
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe('Validation', () => {
|
|
224
|
+
it('shows error state when value is below minimum', () => {
|
|
225
|
+
const { container } = render(
|
|
226
|
+
<AdvancedNumberField
|
|
227
|
+
{...defaultProps}
|
|
228
|
+
value={5}
|
|
229
|
+
min={8}
|
|
230
|
+
/>
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
const input = screen.getByRole('spinbutton');
|
|
234
|
+
fireEvent.change(input, { target: { value: '5' } });
|
|
235
|
+
|
|
236
|
+
const fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
237
|
+
expect(fieldWrapper).toBeDefined();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it('shows error state when value is above maximum', () => {
|
|
241
|
+
const { container } = render(
|
|
242
|
+
<AdvancedNumberField
|
|
243
|
+
{...defaultProps}
|
|
244
|
+
value={100}
|
|
245
|
+
max={72}
|
|
246
|
+
/>
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const input = screen.getByRole('spinbutton');
|
|
250
|
+
fireEvent.change(input, { target: { value: '100' } });
|
|
251
|
+
|
|
252
|
+
const fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
253
|
+
expect(fieldWrapper).toBeDefined();
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('shows correct error message for min constraint only', () => {
|
|
257
|
+
const { container } = render(
|
|
258
|
+
<AdvancedNumberField
|
|
259
|
+
{...defaultProps}
|
|
260
|
+
value={12}
|
|
261
|
+
min={8}
|
|
262
|
+
/>
|
|
263
|
+
);
|
|
264
|
+
|
|
265
|
+
const input = screen.getByRole('spinbutton');
|
|
266
|
+
fireEvent.change(input, { target: { value: '5' } });
|
|
267
|
+
|
|
268
|
+
// Check for error class which indicates validation failed
|
|
269
|
+
const fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
270
|
+
expect(fieldWrapper).toBeDefined();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('shows correct error message for max constraint only', () => {
|
|
274
|
+
const { container } = render(
|
|
275
|
+
<AdvancedNumberField
|
|
276
|
+
{...defaultProps}
|
|
277
|
+
value={12}
|
|
278
|
+
max={72}
|
|
279
|
+
/>
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
const input = screen.getByRole('spinbutton');
|
|
283
|
+
fireEvent.change(input, { target: { value: '100' } });
|
|
284
|
+
|
|
285
|
+
// Check for error class which indicates validation failed
|
|
286
|
+
const fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
287
|
+
expect(fieldWrapper).toBeDefined();
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
it('shows correct error message for min and max constraints', () => {
|
|
291
|
+
const { container } = render(
|
|
292
|
+
<AdvancedNumberField
|
|
293
|
+
{...defaultProps}
|
|
294
|
+
value={12}
|
|
295
|
+
min={8}
|
|
296
|
+
max={72}
|
|
297
|
+
/>
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
const input = screen.getByRole('spinbutton');
|
|
301
|
+
fireEvent.change(input, { target: { value: '100' } });
|
|
302
|
+
|
|
303
|
+
// Check for error class which indicates validation failed
|
|
304
|
+
const fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
305
|
+
expect(fieldWrapper).toBeDefined();
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('does not show error state when value is valid', () => {
|
|
309
|
+
const { container } = render(
|
|
310
|
+
<AdvancedNumberField
|
|
311
|
+
{...defaultProps}
|
|
312
|
+
value={24}
|
|
313
|
+
min={8}
|
|
314
|
+
max={72}
|
|
315
|
+
/>
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
const fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
319
|
+
expect(fieldWrapper).toBeNull();
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('calls onChange when valid value is entered with constraints', () => {
|
|
323
|
+
const onChange = vi.fn();
|
|
324
|
+
render(
|
|
325
|
+
<AdvancedNumberField
|
|
326
|
+
{...defaultProps}
|
|
327
|
+
value={12}
|
|
328
|
+
min={8}
|
|
329
|
+
max={72}
|
|
330
|
+
onChange={onChange}
|
|
331
|
+
/>
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
const input = screen.getByRole('spinbutton');
|
|
335
|
+
fireEvent.change(input, { target: { value: '24' } });
|
|
336
|
+
|
|
337
|
+
// Should call onChange with valid value
|
|
338
|
+
expect(onChange).toHaveBeenCalledWith(24);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it('clears error state when valid value is entered after error', () => {
|
|
342
|
+
const onChange = vi.fn();
|
|
343
|
+
const { container } = render(
|
|
344
|
+
<AdvancedNumberField
|
|
345
|
+
{...defaultProps}
|
|
346
|
+
value={12}
|
|
347
|
+
min={8}
|
|
348
|
+
max={72}
|
|
349
|
+
onChange={onChange}
|
|
350
|
+
/>
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
const input = screen.getByRole('spinbutton');
|
|
354
|
+
|
|
355
|
+
// First enter invalid value
|
|
356
|
+
fireEvent.change(input, { target: { value: '100' } });
|
|
357
|
+
let fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
358
|
+
expect(fieldWrapper).toBeDefined();
|
|
359
|
+
|
|
360
|
+
// Then enter valid value
|
|
361
|
+
fireEvent.change(input, { target: { value: '24' } });
|
|
362
|
+
fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
363
|
+
expect(fieldWrapper).toBeNull();
|
|
364
|
+
expect(onChange).toHaveBeenCalledWith(24);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
describe('Font Size Dropdown', () => {
|
|
369
|
+
it('shows dropdown when input is clicked', () => {
|
|
370
|
+
const { container } = render(<AdvancedNumberField {...defaultProps} />);
|
|
371
|
+
|
|
372
|
+
const input = screen.getByRole('spinbutton');
|
|
373
|
+
fireEvent.click(input);
|
|
374
|
+
|
|
375
|
+
const dropdown = container.querySelector('.font-size-list');
|
|
376
|
+
expect(dropdown).toBeDefined();
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it('hides dropdown when input is clicked again', () => {
|
|
380
|
+
const { container } = render(<AdvancedNumberField {...defaultProps} />);
|
|
381
|
+
|
|
382
|
+
const input = screen.getByRole('spinbutton');
|
|
383
|
+
|
|
384
|
+
// Click to show dropdown
|
|
385
|
+
fireEvent.click(input);
|
|
386
|
+
let dropdown = container.querySelector('.font-size-list');
|
|
387
|
+
expect(dropdown).toBeDefined();
|
|
388
|
+
|
|
389
|
+
// Click again to hide dropdown
|
|
390
|
+
fireEvent.click(input);
|
|
391
|
+
dropdown = container.querySelector('.font-size-list');
|
|
392
|
+
expect(dropdown).toBeNull();
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it('renders all font sizes in dropdown', () => {
|
|
396
|
+
const { container } = render(<AdvancedNumberField {...defaultProps} />);
|
|
397
|
+
|
|
398
|
+
const input = screen.getByRole('spinbutton');
|
|
399
|
+
fireEvent.click(input);
|
|
400
|
+
|
|
401
|
+
const fontSizeButtons = container.querySelectorAll('.font-size-btn');
|
|
402
|
+
expect(fontSizeButtons.length).toBe(13); // FONT_SIZES array length
|
|
403
|
+
|
|
404
|
+
// Check if all font sizes are present
|
|
405
|
+
const expectedSizes = [8, 9, 10, 12, 14, 18, 24, 30, 36, 48, 60, 72, 96];
|
|
406
|
+
expectedSizes.forEach((size, index) => {
|
|
407
|
+
expect(fontSizeButtons[index].textContent).toBe(size.toString());
|
|
408
|
+
});
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it('selects font size when dropdown item is clicked', () => {
|
|
412
|
+
const onChange = vi.fn();
|
|
413
|
+
const { container } = render(
|
|
414
|
+
<AdvancedNumberField
|
|
415
|
+
{...defaultProps}
|
|
416
|
+
onChange={onChange}
|
|
417
|
+
/>
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
const input = screen.getByRole('spinbutton');
|
|
421
|
+
fireEvent.click(input);
|
|
422
|
+
|
|
423
|
+
const fontSizeButton = container.querySelector('.font-size-btn');
|
|
424
|
+
if (fontSizeButton) {
|
|
425
|
+
fireEvent.click(fontSizeButton);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
expect(onChange).toHaveBeenCalledWith(8); // First font size
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it('hides dropdown after selecting a font size', () => {
|
|
432
|
+
const { container } = render(<AdvancedNumberField {...defaultProps} />);
|
|
433
|
+
|
|
434
|
+
const input = screen.getByRole('spinbutton');
|
|
435
|
+
fireEvent.click(input);
|
|
436
|
+
|
|
437
|
+
const fontSizeButton = container.querySelector('.font-size-btn');
|
|
438
|
+
if (fontSizeButton) {
|
|
439
|
+
fireEvent.click(fontSizeButton);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const dropdown = container.querySelector('.font-size-list');
|
|
443
|
+
expect(dropdown).toBeNull();
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it('hides dropdown when key is pressed', () => {
|
|
447
|
+
const { container } = render(<AdvancedNumberField {...defaultProps} />);
|
|
448
|
+
|
|
449
|
+
const input = screen.getByRole('spinbutton');
|
|
450
|
+
fireEvent.click(input);
|
|
451
|
+
|
|
452
|
+
let dropdown = container.querySelector('.font-size-list');
|
|
453
|
+
expect(dropdown).toBeDefined();
|
|
454
|
+
|
|
455
|
+
fireEvent.keyDown(input, { key: 'Escape' });
|
|
456
|
+
|
|
457
|
+
dropdown = container.querySelector('.font-size-list');
|
|
458
|
+
expect(dropdown).toBeNull();
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
describe('Focus and Blur Events', () => {
|
|
463
|
+
it('handles focus event', () => {
|
|
464
|
+
render(<AdvancedNumberField {...defaultProps} />);
|
|
465
|
+
|
|
466
|
+
const input = screen.getByRole('spinbutton');
|
|
467
|
+
fireEvent.focus(input);
|
|
468
|
+
|
|
469
|
+
// Test that focus event was handled (no errors thrown)
|
|
470
|
+
expect(input).toBeDefined();
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
it('handles blur event', () => {
|
|
474
|
+
render(<AdvancedNumberField {...defaultProps} />);
|
|
475
|
+
|
|
476
|
+
const input = screen.getByRole('spinbutton');
|
|
477
|
+
fireEvent.blur(input);
|
|
478
|
+
|
|
479
|
+
// Test that blur event was handled (no errors thrown)
|
|
480
|
+
expect(input).toBeDefined();
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
describe('Component Lifecycle', () => {
|
|
485
|
+
it('initializes with correct state on mount', () => {
|
|
486
|
+
render(
|
|
487
|
+
<AdvancedNumberField
|
|
488
|
+
{...defaultProps}
|
|
489
|
+
value={24}
|
|
490
|
+
/>
|
|
491
|
+
);
|
|
492
|
+
|
|
493
|
+
const input: HTMLInputElement = screen.getByRole('spinbutton');
|
|
494
|
+
expect(input.value).toBe('24');
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
it('updates state when props.value changes', () => {
|
|
498
|
+
const { rerender } = render(
|
|
499
|
+
<AdvancedNumberField
|
|
500
|
+
{...defaultProps}
|
|
501
|
+
value={12}
|
|
502
|
+
/>
|
|
503
|
+
);
|
|
504
|
+
|
|
505
|
+
rerender(
|
|
506
|
+
<AdvancedNumberField
|
|
507
|
+
{...defaultProps}
|
|
508
|
+
value={18}
|
|
509
|
+
/>
|
|
510
|
+
);
|
|
511
|
+
|
|
512
|
+
const input: HTMLInputElement = screen.getByRole('spinbutton');
|
|
513
|
+
expect(input.value).toBe('18');
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
it('clears error state when props.value changes', () => {
|
|
517
|
+
const { container, rerender } = render(
|
|
518
|
+
<AdvancedNumberField
|
|
519
|
+
{...defaultProps}
|
|
520
|
+
value={100}
|
|
521
|
+
max={72}
|
|
522
|
+
/>
|
|
523
|
+
);
|
|
524
|
+
|
|
525
|
+
// Trigger error state
|
|
526
|
+
const input = screen.getByRole('spinbutton');
|
|
527
|
+
fireEvent.change(input, { target: { value: '100' } });
|
|
528
|
+
|
|
529
|
+
let fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
530
|
+
expect(fieldWrapper).toBeDefined();
|
|
531
|
+
|
|
532
|
+
// Update props to valid value
|
|
533
|
+
rerender(
|
|
534
|
+
<AdvancedNumberField
|
|
535
|
+
{...defaultProps}
|
|
536
|
+
value={24}
|
|
537
|
+
max={72}
|
|
538
|
+
/>
|
|
539
|
+
);
|
|
540
|
+
|
|
541
|
+
fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
542
|
+
expect(fieldWrapper).toBeNull();
|
|
543
|
+
});
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
describe('Edge Cases', () => {
|
|
547
|
+
it('handles null value correctly', () => {
|
|
548
|
+
render(
|
|
549
|
+
<AdvancedNumberField
|
|
550
|
+
{...defaultProps}
|
|
551
|
+
value={undefined as any}
|
|
552
|
+
/>
|
|
553
|
+
);
|
|
554
|
+
|
|
555
|
+
const input: HTMLInputElement = screen.getByRole('spinbutton');
|
|
556
|
+
expect(input.value).toBe('');
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
it('handles zero value correctly', () => {
|
|
560
|
+
render(
|
|
561
|
+
<AdvancedNumberField
|
|
562
|
+
{...defaultProps}
|
|
563
|
+
value={0}
|
|
564
|
+
/>
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
const input: HTMLInputElement = screen.getByRole('spinbutton');
|
|
568
|
+
expect(input.value).toBe('0');
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
it('handles negative values correctly', () => {
|
|
572
|
+
render(
|
|
573
|
+
<AdvancedNumberField
|
|
574
|
+
{...defaultProps}
|
|
575
|
+
value={-5}
|
|
576
|
+
/>
|
|
577
|
+
);
|
|
578
|
+
|
|
579
|
+
const input: HTMLInputElement = screen.getByRole('spinbutton');
|
|
580
|
+
expect(input.value).toBe('-5');
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
it('renders custom buttons when provided', () => {
|
|
584
|
+
const customButton = <button key='custom'>Custom</button>;
|
|
585
|
+
render(
|
|
586
|
+
<AdvancedNumberField
|
|
587
|
+
{...defaultProps}
|
|
588
|
+
buttons={customButton}
|
|
589
|
+
/>
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
const button = screen.getByText('Custom');
|
|
593
|
+
expect(button).toBeDefined();
|
|
594
|
+
});
|
|
595
|
+
|
|
596
|
+
it('displays info message when no error', () => {
|
|
597
|
+
const { container } = render(
|
|
598
|
+
<AdvancedNumberField
|
|
599
|
+
{...defaultProps}
|
|
600
|
+
value={24}
|
|
601
|
+
info='This is helpful information'
|
|
602
|
+
/>
|
|
603
|
+
);
|
|
604
|
+
|
|
605
|
+
// Check that no error class is present (component renders normally)
|
|
606
|
+
const fieldWrapper = container.querySelector('.advanced-number-field.invalid');
|
|
607
|
+
expect(fieldWrapper).toBeNull();
|
|
608
|
+
|
|
609
|
+
// Check that the component renders without errors
|
|
610
|
+
const input = screen.getByRole('spinbutton');
|
|
611
|
+
expect(input).toBeDefined();
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
it('handles validation without min/max constraints', () => {
|
|
615
|
+
const onChange = vi.fn();
|
|
616
|
+
render(
|
|
617
|
+
<AdvancedNumberField
|
|
618
|
+
{...defaultProps}
|
|
619
|
+
onChange={onChange}
|
|
620
|
+
/>
|
|
621
|
+
);
|
|
622
|
+
|
|
623
|
+
const input = screen.getByRole('spinbutton');
|
|
624
|
+
fireEvent.change(input, { target: { value: '999' } });
|
|
625
|
+
|
|
626
|
+
expect(onChange).toHaveBeenCalledWith(999);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
it('handles increment from zero', () => {
|
|
630
|
+
const onChange = vi.fn();
|
|
631
|
+
const { container } = render(
|
|
632
|
+
<AdvancedNumberField
|
|
633
|
+
{...defaultProps}
|
|
634
|
+
value={0}
|
|
635
|
+
onChange={onChange}
|
|
636
|
+
/>
|
|
637
|
+
);
|
|
638
|
+
|
|
639
|
+
const incrementButton = container.querySelector('.add-font-size');
|
|
640
|
+
if (incrementButton) {
|
|
641
|
+
fireEvent.click(incrementButton);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
expect(onChange).toHaveBeenCalledWith(1);
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
it('handles decrement to negative values', () => {
|
|
648
|
+
const onChange = vi.fn();
|
|
649
|
+
const { container } = render(
|
|
650
|
+
<AdvancedNumberField
|
|
651
|
+
{...defaultProps}
|
|
652
|
+
value={0}
|
|
653
|
+
onChange={onChange}
|
|
654
|
+
/>
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
const decrementButton = container.querySelector('.minus-font-size');
|
|
658
|
+
if (decrementButton) {
|
|
659
|
+
fireEvent.click(decrementButton);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
expect(onChange).toHaveBeenCalledWith(-1);
|
|
663
|
+
});
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
describe('Advanced Props', () => {
|
|
667
|
+
it('passes through FieldWrapper props correctly', () => {
|
|
668
|
+
const { container } = render(
|
|
669
|
+
<AdvancedNumberField
|
|
670
|
+
{...defaultProps}
|
|
671
|
+
propKey='fontSize'
|
|
672
|
+
showCopyPropIds={true}
|
|
673
|
+
activeOverride='test-override'
|
|
674
|
+
previewMultiplier={2}
|
|
675
|
+
/>
|
|
676
|
+
);
|
|
677
|
+
|
|
678
|
+
const fieldWrapper = container.querySelector('[data-testid="field-wrapper"]');
|
|
679
|
+
expect(fieldWrapper).toBeDefined();
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
it('handles setOverride callback', () => {
|
|
683
|
+
const setOverride = vi.fn();
|
|
684
|
+
render(
|
|
685
|
+
<AdvancedNumberField
|
|
686
|
+
{...defaultProps}
|
|
687
|
+
setOverride={setOverride}
|
|
688
|
+
/>
|
|
689
|
+
);
|
|
690
|
+
|
|
691
|
+
// Component should render without errors
|
|
692
|
+
const input = screen.getByRole('spinbutton');
|
|
693
|
+
expect(input).toBeDefined();
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
it('handles removeOverride callback', () => {
|
|
697
|
+
const removeOverride = vi.fn();
|
|
698
|
+
render(
|
|
699
|
+
<AdvancedNumberField
|
|
700
|
+
{...defaultProps}
|
|
701
|
+
removeOverride={removeOverride}
|
|
702
|
+
/>
|
|
703
|
+
);
|
|
704
|
+
|
|
705
|
+
// Component should render without errors
|
|
706
|
+
const input = screen.getByRole('spinbutton');
|
|
707
|
+
expect(input).toBeDefined();
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
it('handles onClose callback', () => {
|
|
711
|
+
const onClose = vi.fn();
|
|
712
|
+
render(
|
|
713
|
+
<AdvancedNumberField
|
|
714
|
+
{...defaultProps}
|
|
715
|
+
onClose={onClose}
|
|
716
|
+
/>
|
|
717
|
+
);
|
|
718
|
+
|
|
719
|
+
// Component should render without errors
|
|
720
|
+
const input = screen.getByRole('spinbutton');
|
|
721
|
+
expect(input).toBeDefined();
|
|
722
|
+
});
|
|
723
|
+
});
|
|
724
|
+
});
|