@oslokommune/punkt-react 15.4.6 → 16.0.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.
Files changed (29) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/index.d.ts +38 -15
  3. package/dist/punkt-react.es.js +12025 -10664
  4. package/dist/punkt-react.umd.js +562 -549
  5. package/package.json +5 -5
  6. package/src/components/accordion/Accordion.test.tsx +3 -2
  7. package/src/components/alert/Alert.test.tsx +2 -1
  8. package/src/components/backlink/BackLink.test.tsx +2 -1
  9. package/src/components/button/Button.test.tsx +4 -3
  10. package/src/components/calendar/Calendar.interaction.test.tsx +2 -1
  11. package/src/components/checkbox/Checkbox.test.tsx +2 -1
  12. package/src/components/combobox/Combobox.accessibility.test.tsx +277 -0
  13. package/src/components/combobox/Combobox.core.test.tsx +469 -0
  14. package/src/components/combobox/Combobox.interaction.test.tsx +607 -0
  15. package/src/components/combobox/Combobox.selection.test.tsx +548 -0
  16. package/src/components/combobox/Combobox.tsx +59 -54
  17. package/src/components/combobox/ComboboxInput.tsx +140 -0
  18. package/src/components/combobox/ComboboxTags.tsx +110 -0
  19. package/src/components/combobox/Listbox.tsx +172 -0
  20. package/src/components/combobox/types.ts +145 -0
  21. package/src/components/combobox/useComboboxState.ts +1141 -0
  22. package/src/components/datepicker/Datepicker.accessibility.test.tsx +5 -4
  23. package/src/components/datepicker/Datepicker.input.test.tsx +3 -2
  24. package/src/components/datepicker/Datepicker.selection.test.tsx +8 -8
  25. package/src/components/datepicker/Datepicker.validation.test.tsx +2 -1
  26. package/src/components/radio/RadioButton.test.tsx +3 -2
  27. package/src/components/searchinput/SearchInput.test.tsx +6 -5
  28. package/src/components/tabs/Tabs.test.tsx +13 -12
  29. package/src/components/tag/Tag.test.tsx +2 -1
@@ -0,0 +1,607 @@
1
+ import '@testing-library/jest-dom'
2
+
3
+ import { act, fireEvent, render } from '@testing-library/react'
4
+ import { vi } from 'vitest'
5
+
6
+ import type { IPktComboboxOption } from 'shared-types/combobox'
7
+ import { PktCombobox } from './Combobox'
8
+ import type { IPktCombobox } from './types'
9
+
10
+ const comboboxId = 'test-combobox'
11
+ const label = 'Test Combobox'
12
+
13
+ const getDefaultOptions = (): IPktComboboxOption[] => [
14
+ { value: 'apple', label: 'Apple' },
15
+ { value: 'banana', label: 'Banana' },
16
+ { value: 'cherry', label: 'Cherry' },
17
+ { value: 'date', label: 'Date' },
18
+ ]
19
+
20
+ const createComboboxTest = (props: Partial<IPktCombobox> = {}) => {
21
+ const defaultProps: IPktCombobox = {
22
+ label,
23
+ id: comboboxId,
24
+ ...props,
25
+ }
26
+
27
+ return render(<PktCombobox {...defaultProps} />)
28
+ }
29
+
30
+ const getFormInputValue = (container: HTMLElement) => {
31
+ return (container.querySelector('input.pkt-visually-hidden') as HTMLInputElement)?.value ?? ''
32
+ }
33
+
34
+ describe('PktCombobox', () => {
35
+ describe('Keyboard navigation', () => {
36
+ test('opens dropdown with Enter on arrow button', () => {
37
+ const { container } = createComboboxTest()
38
+
39
+ const arrowButton = container.querySelector('.pkt-combobox__input')
40
+ fireEvent.keyDown(arrowButton!, { key: 'Enter' })
41
+
42
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('true')
43
+ })
44
+
45
+ test('opens dropdown with Space on arrow button', () => {
46
+ const { container } = createComboboxTest()
47
+
48
+ const arrowButton = container.querySelector('.pkt-combobox__input')
49
+ fireEvent.keyDown(arrowButton!, { key: ' ' })
50
+
51
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('true')
52
+ })
53
+
54
+ test('opens dropdown with ArrowDown on arrow button', () => {
55
+ const { container } = createComboboxTest()
56
+
57
+ const arrowButton = container.querySelector('.pkt-combobox__input')
58
+ fireEvent.keyDown(arrowButton!, { key: 'ArrowDown' })
59
+
60
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('true')
61
+ })
62
+
63
+ test('toggles dropdown closed with Enter on arrow button', () => {
64
+ const { container } = createComboboxTest()
65
+
66
+ const arrowButton = container.querySelector('.pkt-combobox__input')
67
+
68
+ // Open
69
+ fireEvent.keyDown(arrowButton!, { key: 'Enter' })
70
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('true')
71
+
72
+ // Close
73
+ fireEvent.keyDown(arrowButton!, { key: 'Enter' })
74
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('false')
75
+ })
76
+
77
+ test('does not toggle on non-toggle keys', () => {
78
+ const { container } = createComboboxTest()
79
+
80
+ const arrowButton = container.querySelector('.pkt-combobox__input')
81
+ fireEvent.keyDown(arrowButton!, { key: 'Escape' })
82
+
83
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('false')
84
+ })
85
+
86
+ test('submits value with Enter in text input', () => {
87
+ const handleValueChange = vi.fn()
88
+ const { container } = createComboboxTest({
89
+ allowUserInput: true,
90
+ options: getDefaultOptions(),
91
+ onValueChange: handleValueChange,
92
+ })
93
+
94
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
95
+ fireEvent.focus(textInput)
96
+
97
+ textInput.value = 'apple'
98
+ fireEvent.change(textInput, { target: { value: 'apple' } })
99
+ fireEvent.keyDown(textInput, { key: 'Enter' })
100
+
101
+ expect(handleValueChange).toHaveBeenCalledWith(['apple'])
102
+ })
103
+
104
+ test('closes dropdown with Escape in text input', () => {
105
+ const { container } = createComboboxTest({
106
+ allowUserInput: true,
107
+ options: getDefaultOptions(),
108
+ })
109
+
110
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
111
+ fireEvent.focus(textInput)
112
+
113
+ expect(textInput.getAttribute('aria-expanded')).toBe('true')
114
+
115
+ fireEvent.keyDown(textInput, { key: 'Escape' })
116
+
117
+ expect(textInput.getAttribute('aria-expanded')).toBe('false')
118
+ })
119
+
120
+ test('does not open dropdown when disabled', () => {
121
+ const { container } = createComboboxTest({ disabled: true })
122
+
123
+ const arrowButton = container.querySelector('.pkt-combobox__input')
124
+ fireEvent.keyDown(arrowButton!, { key: 'Enter' })
125
+
126
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('false')
127
+ })
128
+
129
+ test('selects option with Enter key on option element', () => {
130
+ const handleValueChange = vi.fn()
131
+ const { container } = createComboboxTest({
132
+ options: getDefaultOptions(),
133
+ onValueChange: handleValueChange,
134
+ })
135
+
136
+ const arrowButton = container.querySelector('.pkt-combobox__input')
137
+ fireEvent.click(arrowButton!)
138
+
139
+ const option = container.querySelector('[data-value="apple"][role="option"]')
140
+ fireEvent.keyDown(option!, { key: 'Enter' })
141
+
142
+ expect(handleValueChange).toHaveBeenCalledWith(['apple'])
143
+ })
144
+
145
+ test('selects option with Space key on option element', () => {
146
+ const handleValueChange = vi.fn()
147
+ const { container } = createComboboxTest({
148
+ options: getDefaultOptions(),
149
+ onValueChange: handleValueChange,
150
+ })
151
+
152
+ const arrowButton = container.querySelector('.pkt-combobox__input')
153
+ fireEvent.click(arrowButton!)
154
+
155
+ const option = container.querySelector('[data-value="banana"][role="option"]')
156
+ fireEvent.keyDown(option!, { key: ' ' })
157
+
158
+ expect(handleValueChange).toHaveBeenCalledWith(['banana'])
159
+ })
160
+
161
+ test('closes dropdown with Escape on option element', () => {
162
+ const { container } = createComboboxTest({
163
+ options: getDefaultOptions(),
164
+ })
165
+
166
+ const arrowButton = container.querySelector('.pkt-combobox__input')
167
+ fireEvent.click(arrowButton!)
168
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('true')
169
+
170
+ const option = container.querySelector('[data-value="apple"][role="option"]')
171
+ fireEvent.keyDown(option!, { key: 'Escape' })
172
+
173
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('false')
174
+ })
175
+
176
+ test('adds value with comma separator in multiple mode', () => {
177
+ const handleValueChange = vi.fn()
178
+ const { container } = createComboboxTest({
179
+ allowUserInput: true,
180
+ multiple: true,
181
+ options: getDefaultOptions(),
182
+ onValueChange: handleValueChange,
183
+ })
184
+
185
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
186
+ fireEvent.focus(textInput)
187
+
188
+ textInput.value = 'apple'
189
+ fireEvent.change(textInput, { target: { value: 'apple' } })
190
+ fireEvent.keyDown(textInput, { key: ',' })
191
+
192
+ expect(handleValueChange).toHaveBeenCalledWith(['apple'])
193
+ })
194
+ })
195
+
196
+ describe('Focus handling', () => {
197
+ test('opens dropdown on input focus', () => {
198
+ const { container } = createComboboxTest({
199
+ allowUserInput: true,
200
+ options: getDefaultOptions(),
201
+ })
202
+
203
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
204
+ fireEvent.focus(textInput)
205
+
206
+ expect(textInput.getAttribute('aria-expanded')).toBe('true')
207
+ })
208
+
209
+ test('populates input with current value on focus in single-select', () => {
210
+ const { container } = createComboboxTest({
211
+ allowUserInput: true,
212
+ defaultValue: 'apple',
213
+ options: getDefaultOptions(),
214
+ })
215
+
216
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
217
+ fireEvent.focus(textInput)
218
+
219
+ expect(textInput.value).toBe('Apple')
220
+ })
221
+
222
+ test('opens dropdown on input container click (hidden input mode)', () => {
223
+ const { container } = createComboboxTest({
224
+ options: getDefaultOptions(),
225
+ })
226
+
227
+ const inputDiv = container.querySelector('.pkt-combobox__input')
228
+ fireEvent.click(inputDiv!)
229
+
230
+ const arrowButton = container.querySelector('.pkt-combobox__input')
231
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('true')
232
+ })
233
+
234
+ test('toggles dropdown on input container click (hidden input mode)', () => {
235
+ const { container } = createComboboxTest({
236
+ options: getDefaultOptions(),
237
+ })
238
+
239
+ const inputDiv = container.querySelector('.pkt-combobox__input')
240
+
241
+ fireEvent.click(inputDiv!)
242
+ const arrowButton = container.querySelector('.pkt-combobox__input')
243
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('true')
244
+
245
+ fireEvent.click(inputDiv!)
246
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('false')
247
+ })
248
+
249
+ test('does not open when disabled and input container is clicked', () => {
250
+ const { container } = createComboboxTest({ disabled: true })
251
+
252
+ const inputDiv = container.querySelector('.pkt-combobox__input')
253
+ fireEvent.click(inputDiv!)
254
+
255
+ const arrowButton = container.querySelector('.pkt-combobox__input')
256
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('false')
257
+ })
258
+
259
+ test('focuses text input when placeholder is clicked', () => {
260
+ const { container } = createComboboxTest({
261
+ allowUserInput: true,
262
+ placeholder: 'Select...',
263
+ })
264
+
265
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
266
+ expect(textInput.placeholder).toBe('Select...')
267
+ fireEvent.click(textInput)
268
+
269
+ expect(document.activeElement).toBe(textInput)
270
+ })
271
+ })
272
+
273
+ describe('Focus-out behavior', () => {
274
+ test('closes dropdown when clicking outside combobox', () => {
275
+ const { container } = createComboboxTest({
276
+ options: getDefaultOptions(),
277
+ })
278
+
279
+ const arrowButton = container.querySelector('.pkt-combobox__input')
280
+ fireEvent.click(arrowButton!)
281
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('true')
282
+
283
+ fireEvent.click(document.body)
284
+
285
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('false')
286
+ })
287
+
288
+ test('adds custom value on focus-out when allowUserInput is on', () => {
289
+ const handleValueChange = vi.fn()
290
+ const { container } = createComboboxTest({
291
+ allowUserInput: true,
292
+ options: getDefaultOptions(),
293
+ onValueChange: handleValueChange,
294
+ })
295
+
296
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
297
+ fireEvent.focus(textInput)
298
+
299
+ textInput.value = 'NewFruit'
300
+ fireEvent.change(textInput, { target: { value: 'NewFruit' } })
301
+
302
+ // Click outside to trigger close and process input
303
+ fireEvent.click(document.body)
304
+
305
+ expect(handleValueChange).toHaveBeenCalledWith(['NewFruit'])
306
+ })
307
+
308
+ test('selects matching option on focus-out when typeahead', () => {
309
+ const handleValueChange = vi.fn()
310
+ const { container } = createComboboxTest({
311
+ typeahead: true,
312
+ options: getDefaultOptions(),
313
+ onValueChange: handleValueChange,
314
+ })
315
+
316
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
317
+ fireEvent.focus(textInput)
318
+
319
+ textInput.value = 'Apple'
320
+ fireEvent.change(textInput, { target: { value: 'Apple' } })
321
+
322
+ // Click outside to trigger close and process input
323
+ fireEvent.click(document.body)
324
+
325
+ expect(handleValueChange).toHaveBeenCalledWith(['apple'])
326
+ })
327
+ })
328
+
329
+ describe('Search and filtering', () => {
330
+ test('shows add-value banner when search has no exact match and allowUserInput is on', () => {
331
+ const { container } = createComboboxTest({
332
+ allowUserInput: true,
333
+ options: getDefaultOptions(),
334
+ })
335
+
336
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
337
+ fireEvent.focus(textInput)
338
+
339
+ fireEvent.input(textInput, { target: { value: 'NewFruit' } })
340
+
341
+ const addBanner = container.querySelector('.pkt-listbox__banner--new-option')
342
+ expect(addBanner).toBeInTheDocument()
343
+ })
344
+
345
+ test('renders search input in listbox when includeSearch is true', () => {
346
+ const { container } = createComboboxTest({ includeSearch: true })
347
+
348
+ const searchInput = container.querySelector('.pkt-listbox__search input')
349
+ expect(searchInput).toBeInTheDocument()
350
+ expect(searchInput?.getAttribute('role')).toBe('searchbox')
351
+ })
352
+
353
+ test('sets search placeholder in listbox', () => {
354
+ const { container } = createComboboxTest({
355
+ includeSearch: true,
356
+ searchPlaceholder: 'Søk her...',
357
+ })
358
+
359
+ const searchInput = container.querySelector('.pkt-listbox__search input') as HTMLInputElement
360
+ expect(searchInput.placeholder).toBe('Søk her...')
361
+ })
362
+
363
+ test('filters options via listbox search', () => {
364
+ const { container } = createComboboxTest({
365
+ includeSearch: true,
366
+ options: getDefaultOptions(),
367
+ })
368
+
369
+ // Open dropdown
370
+ const arrowButton = container.querySelector('.pkt-combobox__input')
371
+ fireEvent.click(arrowButton!)
372
+
373
+ // Type in listbox search
374
+ const searchInput = container.querySelector('.pkt-listbox__search input') as HTMLInputElement
375
+ fireEvent.change(searchInput, { target: { value: 'app' } })
376
+
377
+ // Options should be filtered
378
+ const visibleOptions = container.querySelectorAll('.pkt-listbox__option')
379
+ expect(visibleOptions.length).toBeLessThan(4)
380
+ })
381
+
382
+ test('search input navigates to first option with ArrowDown', () => {
383
+ const { container } = createComboboxTest({
384
+ includeSearch: true,
385
+ options: getDefaultOptions(),
386
+ })
387
+
388
+ // Open dropdown
389
+ const arrowButton = container.querySelector('.pkt-combobox__input')
390
+ fireEvent.click(arrowButton!)
391
+
392
+ const searchInput = container.querySelector('.pkt-listbox__search input') as HTMLInputElement
393
+
394
+ // ArrowDown in search should not throw
395
+ fireEvent.keyDown(searchInput, { key: 'ArrowDown' })
396
+
397
+ expect(searchInput).toBeInTheDocument()
398
+ })
399
+
400
+ test('search input closes dropdown with Escape', () => {
401
+ const { container } = createComboboxTest({
402
+ includeSearch: true,
403
+ options: getDefaultOptions(),
404
+ })
405
+
406
+ const arrowButton = container.querySelector('.pkt-combobox__input')
407
+ fireEvent.click(arrowButton!)
408
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('true')
409
+
410
+ const searchInput = container.querySelector('.pkt-listbox__search input') as HTMLInputElement
411
+ fireEvent.keyDown(searchInput, { key: 'Escape' })
412
+
413
+ expect(arrowButton?.getAttribute('aria-expanded')).toBe('false')
414
+ })
415
+ })
416
+
417
+ describe('New option banner interaction', () => {
418
+ test('adds new option when clicking add-value banner', () => {
419
+ const handleValueChange = vi.fn()
420
+ const { container } = createComboboxTest({
421
+ allowUserInput: true,
422
+ options: getDefaultOptions(),
423
+ onValueChange: handleValueChange,
424
+ })
425
+
426
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
427
+ fireEvent.focus(textInput)
428
+
429
+ fireEvent.input(textInput, { target: { value: 'NewFruit' } })
430
+
431
+ const addBanner = container.querySelector('.pkt-listbox__banner--new-option')
432
+ expect(addBanner).toBeInTheDocument()
433
+
434
+ fireEvent.click(addBanner!)
435
+
436
+ expect(handleValueChange).toHaveBeenCalledWith(['NewFruit'])
437
+ })
438
+
439
+ test('adds new option when pressing Enter on add-value banner', () => {
440
+ const handleValueChange = vi.fn()
441
+ const { container } = createComboboxTest({
442
+ allowUserInput: true,
443
+ options: getDefaultOptions(),
444
+ onValueChange: handleValueChange,
445
+ })
446
+
447
+ const textInput = container.querySelector('input[type="text"]') as HTMLInputElement
448
+ fireEvent.focus(textInput)
449
+
450
+ fireEvent.input(textInput, { target: { value: 'NewFruit' } })
451
+
452
+ const addBanner = container.querySelector('.pkt-listbox__banner--new-option')
453
+ expect(addBanner).toBeInTheDocument()
454
+
455
+ fireEvent.keyDown(addBanner!, { key: 'Enter' })
456
+
457
+ expect(handleValueChange).toHaveBeenCalledWith(['NewFruit'])
458
+ })
459
+ })
460
+
461
+ describe('Children as options', () => {
462
+ test('handles options from children correctly', () => {
463
+ const handleValueChange = vi.fn()
464
+ const { container } = render(
465
+ <PktCombobox id={comboboxId} label={label} onValueChange={handleValueChange}>
466
+ <option value="opt1">Option 1</option>
467
+ <option value="opt2">Option 2</option>
468
+ <option value="opt3">Option 3</option>
469
+ </PktCombobox>,
470
+ )
471
+
472
+ const arrowButton = container.querySelector('.pkt-combobox__input')
473
+ fireEvent.click(arrowButton!)
474
+
475
+ const option = container.querySelector('[data-value="opt2"][role="option"]')
476
+ fireEvent.click(option!)
477
+
478
+ expect(handleValueChange).toHaveBeenCalledWith(['opt2'])
479
+ })
480
+
481
+ test('handles children with defaultValue', () => {
482
+ const { container } = render(
483
+ <PktCombobox id={comboboxId} label={label} defaultValue="opt1">
484
+ <option value="opt1">Option 1</option>
485
+ <option value="opt2">Option 2</option>
486
+ </PktCombobox>,
487
+ )
488
+
489
+ const valueSpan = container.querySelector('.pkt-combobox__value')
490
+ expect(valueSpan?.textContent?.trim()).toBe('Option 1')
491
+ expect(getFormInputValue(container)).toBe('opt1')
492
+ })
493
+
494
+ test('handles children re-render with new options', () => {
495
+ const { container, rerender } = render(
496
+ <PktCombobox id={comboboxId} label={label}>
497
+ <option value="a">A</option>
498
+ <option value="b">B</option>
499
+ </PktCombobox>,
500
+ )
501
+
502
+ let options = container.querySelectorAll('.pkt-listbox__option')
503
+ expect(options.length).toBe(2)
504
+
505
+ rerender(
506
+ <PktCombobox id={comboboxId} label={label}>
507
+ <option value="a">A</option>
508
+ <option value="b">B</option>
509
+ <option value="c">C</option>
510
+ </PktCombobox>,
511
+ )
512
+
513
+ options = container.querySelectorAll('.pkt-listbox__option')
514
+ expect(options.length).toBe(3)
515
+ })
516
+ })
517
+
518
+ describe('Form reset', () => {
519
+ beforeEach(() => {
520
+ vi.useFakeTimers()
521
+ })
522
+ afterEach(() => {
523
+ vi.useRealTimers()
524
+ })
525
+
526
+ test('resets single value to defaultValue on form reset', () => {
527
+ const { container } = render(
528
+ <form>
529
+ <PktCombobox id={comboboxId} label={label} defaultValue="apple" options={getDefaultOptions()} />
530
+ </form>,
531
+ )
532
+
533
+ // Select a different value
534
+ const arrowButton = container.querySelector('.pkt-combobox__input')
535
+ fireEvent.click(arrowButton!)
536
+ const bananaOption = container.querySelector('[data-value="banana"][role="option"]')
537
+ fireEvent.click(bananaOption!)
538
+
539
+ expect(getFormInputValue(container)).toBe('banana')
540
+
541
+ // Reset the form
542
+ const form = container.querySelector('form')!
543
+ act(() => {
544
+ fireEvent.reset(form)
545
+ vi.advanceTimersByTime(10)
546
+ })
547
+
548
+ expect(getFormInputValue(container)).toBe('apple')
549
+ })
550
+
551
+ test('resets multiple values to defaultValue on form reset', () => {
552
+ const { container } = render(
553
+ <form>
554
+ <PktCombobox
555
+ id={comboboxId}
556
+ label={label}
557
+ defaultValue={['apple', 'banana']}
558
+ multiple
559
+ options={getDefaultOptions()}
560
+ />
561
+ </form>,
562
+ )
563
+
564
+ // Select an additional value
565
+ const arrowButton = container.querySelector('.pkt-combobox__input')
566
+ fireEvent.click(arrowButton!)
567
+ const dateOption = container.querySelector('[data-value="date"][role="option"]')
568
+ fireEvent.click(dateOption!)
569
+
570
+ expect(getFormInputValue(container)).toBe('apple,banana,date')
571
+
572
+ // Reset the form
573
+ const form = container.querySelector('form')!
574
+ act(() => {
575
+ fireEvent.reset(form)
576
+ vi.advanceTimersByTime(10)
577
+ })
578
+
579
+ expect(getFormInputValue(container)).toBe('apple,banana')
580
+ })
581
+
582
+ test('resets to empty when no defaultValue on form reset', () => {
583
+ const { container } = render(
584
+ <form>
585
+ <PktCombobox id={comboboxId} label={label} options={getDefaultOptions()} />
586
+ </form>,
587
+ )
588
+
589
+ // Select a value
590
+ const arrowButton = container.querySelector('.pkt-combobox__input')
591
+ fireEvent.click(arrowButton!)
592
+ const appleOption = container.querySelector('[data-value="apple"][role="option"]')
593
+ fireEvent.click(appleOption!)
594
+
595
+ expect(getFormInputValue(container)).toBe('apple')
596
+
597
+ // Reset the form
598
+ const form = container.querySelector('form')!
599
+ act(() => {
600
+ fireEvent.reset(form)
601
+ vi.advanceTimersByTime(10)
602
+ })
603
+
604
+ expect(getFormInputValue(container)).toBe('')
605
+ })
606
+ })
607
+ })