@oslokommune/punkt-react 14.5.3 → 15.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 +33 -0
  2. package/dist/index.d.ts +64 -21
  3. package/dist/punkt-react.es.js +7198 -4674
  4. package/dist/punkt-react.umd.js +573 -569
  5. package/package.json +5 -5
  6. package/src/components/calendar/Calendar.accessibility.test.tsx +75 -0
  7. package/src/components/calendar/Calendar.constraints.test.tsx +84 -0
  8. package/src/components/calendar/Calendar.core.test.tsx +272 -0
  9. package/src/components/calendar/Calendar.interaction.test.tsx +96 -0
  10. package/src/components/calendar/Calendar.selection.test.tsx +227 -0
  11. package/src/components/calendar/Calendar.tsx +54 -0
  12. package/src/components/calendar/CalendarGrid.tsx +192 -0
  13. package/src/components/calendar/CalendarNav.tsx +111 -0
  14. package/src/components/calendar/calendar-utils.ts +90 -0
  15. package/src/components/calendar/types.ts +160 -0
  16. package/src/components/calendar/useCalendarState.ts +426 -0
  17. package/src/components/datepicker/DateTags.tsx +43 -0
  18. package/src/components/datepicker/Datepicker.accessibility.test.tsx +404 -0
  19. package/src/components/datepicker/Datepicker.core.test.tsx +270 -0
  20. package/src/components/datepicker/Datepicker.input.test.tsx +218 -0
  21. package/src/components/datepicker/Datepicker.selection.test.tsx +302 -0
  22. package/src/components/datepicker/Datepicker.tsx +61 -79
  23. package/src/components/datepicker/Datepicker.validation.test.tsx +317 -0
  24. package/src/components/datepicker/DatepickerInputs.tsx +184 -0
  25. package/src/components/datepicker/DatepickerPopup.tsx +90 -0
  26. package/src/components/datepicker/types.ts +139 -0
  27. package/src/components/datepicker/useDatepickerState.ts +502 -0
  28. package/src/components/index.ts +1 -0
  29. package/src/components/datepicker/Datepicker.test.tsx +0 -395
@@ -0,0 +1,404 @@
1
+ import '@testing-library/jest-dom'
2
+
3
+ import { fireEvent, render, screen } from '@testing-library/react'
4
+ import { axe, toHaveNoViolations } from 'jest-axe'
5
+
6
+ import { IPktDatepicker, PktDatepicker } from './Datepicker'
7
+
8
+ expect.extend(toHaveNoViolations)
9
+
10
+ const datePickerId = 'datepickerId'
11
+ const label = 'Date Picker Label'
12
+
13
+ const createDatepickerTest = (props: Partial<IPktDatepicker> = {}) => {
14
+ const defaultProps: IPktDatepicker = {
15
+ label,
16
+ id: datePickerId,
17
+ ...props,
18
+ }
19
+
20
+ return render(<PktDatepicker {...defaultProps} />)
21
+ }
22
+
23
+ describe('PktDatepicker', () => {
24
+ describe('Event handling', () => {
25
+ test('dispatches onChange event when value changes', () => {
26
+ const handleChange = jest.fn()
27
+ const { container } = createDatepickerTest({
28
+ onChange: handleChange,
29
+ })
30
+
31
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
32
+ fireEvent.change(input, { target: { value: '2024-06-15' } })
33
+
34
+ expect(handleChange).toHaveBeenCalled()
35
+ })
36
+
37
+ test('dispatches onValueChange event when value changes', () => {
38
+ const handleValueChange = jest.fn()
39
+ const { container } = createDatepickerTest({
40
+ onValueChange: handleValueChange,
41
+ })
42
+
43
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
44
+ fireEvent.change(input, { target: { value: '2024-06-15' } })
45
+
46
+ expect(handleValueChange).toHaveBeenCalledWith(['2024-06-15'])
47
+ })
48
+
49
+ test('input can receive focus', () => {
50
+ const { container } = createDatepickerTest()
51
+
52
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
53
+ input.focus()
54
+
55
+ expect(document.activeElement).toBe(input)
56
+ })
57
+
58
+ test('input can be blurred', () => {
59
+ const { container } = createDatepickerTest()
60
+
61
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
62
+ input.focus()
63
+ expect(document.activeElement).toBe(input)
64
+
65
+ input.blur()
66
+ expect(document.activeElement).not.toBe(input)
67
+ })
68
+
69
+ test('dispatches both onChange and onValueChange', () => {
70
+ const handleChange = jest.fn()
71
+ const handleValueChange = jest.fn()
72
+ const { container } = createDatepickerTest({
73
+ onChange: handleChange,
74
+ onValueChange: handleValueChange,
75
+ })
76
+
77
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
78
+ fireEvent.change(input, { target: { value: '2024-06-15' } })
79
+
80
+ expect(handleChange).toHaveBeenCalled()
81
+ expect(handleValueChange).toHaveBeenCalledWith(['2024-06-15'])
82
+ })
83
+ })
84
+
85
+ describe('Accessibility', () => {
86
+ test('has no accessibility violations with single date set', async () => {
87
+ const { container } = createDatepickerTest({
88
+ value: '2024-06-15',
89
+ helptext: 'Choose a date from the calendar',
90
+ })
91
+
92
+ const results = await axe(container)
93
+ expect(results).toHaveNoViolations()
94
+ })
95
+
96
+ test('has no accessibility violations with range dates set', async () => {
97
+ const { container } = createDatepickerTest({
98
+ range: true,
99
+ value: ['2024-06-15', '2024-06-25'],
100
+ helptext: 'Choose start and end dates',
101
+ })
102
+
103
+ const results = await axe(container)
104
+ expect(results).toHaveNoViolations()
105
+ })
106
+
107
+ test('has no accessibility violations with multiple dates', async () => {
108
+ const { container } = createDatepickerTest({
109
+ multiple: true,
110
+ value: ['2024-06-15', '2024-06-20', '2024-06-25'],
111
+ helptext: 'Choose multiple dates',
112
+ })
113
+
114
+ const results = await axe(container)
115
+ expect(results).toHaveNoViolations()
116
+ })
117
+
118
+ test('has no accessibility violations when disabled', async () => {
119
+ const { container } = createDatepickerTest({
120
+ disabled: true,
121
+ helptext: 'This field is disabled',
122
+ })
123
+
124
+ const results = await axe(container)
125
+ expect(results).toHaveNoViolations()
126
+ })
127
+
128
+ test('has no accessibility violations with error state', async () => {
129
+ const { container } = createDatepickerTest({
130
+ hasError: true,
131
+ errorMessage: 'Please enter a valid date',
132
+ helptext: 'Required field',
133
+ })
134
+
135
+ const results = await axe(container)
136
+ expect(results).toHaveNoViolations()
137
+ })
138
+
139
+ test('associates label with input correctly', () => {
140
+ const { container } = createDatepickerTest()
141
+
142
+ const labelEl = container.querySelector('label')
143
+ expect(labelEl).toBeInTheDocument()
144
+ expect(labelEl).toHaveAttribute('for', `${datePickerId}-input`)
145
+
146
+ const input = container.querySelector(`#${datePickerId}-input`)
147
+ expect(input).toBeInTheDocument()
148
+ })
149
+
150
+ test('has proper ARIA attributes for calendar button', () => {
151
+ const { container } = createDatepickerTest()
152
+
153
+ const button = container.querySelector('button[type="button"]')
154
+ expect(button).toBeInTheDocument()
155
+ expect(button).toHaveAttribute('aria-label', 'Åpne kalender')
156
+ })
157
+
158
+ test('input has aria-describedby when helptext is present', () => {
159
+ const { container } = createDatepickerTest({
160
+ helptext: 'Some help text',
161
+ })
162
+
163
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
164
+ expect(input).toHaveAttribute('aria-describedby', `${datePickerId}-helptext`)
165
+ })
166
+
167
+ test('input does not have aria-describedby when no helptext', () => {
168
+ const { container } = createDatepickerTest()
169
+
170
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
171
+ expect(input).not.toHaveAttribute('aria-describedby')
172
+ })
173
+
174
+ test('input has aria-invalid when hasError is true', () => {
175
+ const { container } = createDatepickerTest({
176
+ hasError: true,
177
+ errorMessage: 'Invalid date',
178
+ })
179
+
180
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
181
+ expect(input).toHaveAttribute('aria-invalid', 'true')
182
+ })
183
+
184
+ test('input has aria-errormessage when hasError is true', () => {
185
+ const { container } = createDatepickerTest({
186
+ hasError: true,
187
+ errorMessage: 'Invalid date',
188
+ })
189
+
190
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
191
+ expect(input).toHaveAttribute('aria-errormessage', `${datePickerId}-error`)
192
+ })
193
+
194
+ test('input does not have aria-invalid when no error', () => {
195
+ const { container } = createDatepickerTest()
196
+
197
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
198
+ expect(input).not.toHaveAttribute('aria-invalid', 'true')
199
+ })
200
+
201
+ test('calendar popup has aria-hidden when closed', () => {
202
+ const { container } = createDatepickerTest()
203
+
204
+ const popup = container.querySelector('.pkt-calendar-popup')
205
+ expect(popup).toHaveAttribute('aria-hidden', 'true')
206
+ })
207
+
208
+ test('calendar popup has aria-hidden false when open', () => {
209
+ const { container } = createDatepickerTest()
210
+
211
+ const button = container.querySelector('button[type="button"]') as HTMLButtonElement
212
+ fireEvent.click(button)
213
+
214
+ const popup = container.querySelector('.pkt-calendar-popup')
215
+ expect(popup).toHaveAttribute('aria-hidden', 'false')
216
+ })
217
+
218
+ test('date tags container has aria-live polite', () => {
219
+ const { container } = createDatepickerTest({
220
+ multiple: true,
221
+ value: ['2024-06-15'],
222
+ })
223
+
224
+ const tagsContainer = container.querySelector('.pkt-date-tags')
225
+ expect(tagsContainer).toHaveAttribute('aria-live', 'polite')
226
+ })
227
+
228
+ test('handles focus management - button can be focused', () => {
229
+ const { container } = createDatepickerTest()
230
+
231
+ const button = container.querySelector('button[type="button"]') as HTMLButtonElement
232
+ button.focus()
233
+
234
+ expect(document.activeElement).toBe(button)
235
+ })
236
+
237
+ test('supports keyboard-only interaction to open and close calendar', () => {
238
+ const { container } = createDatepickerTest()
239
+
240
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
241
+
242
+ // Open with Space
243
+ fireEvent.keyDown(input, { key: ' ' })
244
+ let popup = container.querySelector('.pkt-calendar-popup')
245
+ expect(popup).not.toHaveAttribute('hidden')
246
+
247
+ // Close with Escape
248
+ fireEvent.keyDown(document, { key: 'Escape' })
249
+ popup = container.querySelector('.pkt-calendar-popup')
250
+ expect(popup).toHaveAttribute('hidden')
251
+ })
252
+ })
253
+
254
+ describe('Localization', () => {
255
+ test('uses custom strings for calendar button', () => {
256
+ const { container } = createDatepickerTest({
257
+ strings: {
258
+ calendar: { buttonAltText: 'Open calendar' },
259
+ },
260
+ })
261
+
262
+ const button = container.querySelector('button[type="button"]')
263
+ expect(button).toHaveAttribute('aria-label', 'Open calendar')
264
+ })
265
+
266
+ test('uses custom strings for range labels', () => {
267
+ const { container } = createDatepickerTest({
268
+ range: true,
269
+ showRangeLabels: true,
270
+ strings: {
271
+ generic: { from: 'From', to: 'To' },
272
+ calendar: { buttonAltText: 'Open calendar' },
273
+ },
274
+ })
275
+
276
+ const prefix = container.querySelector('.pkt-input-prefix')
277
+ expect(prefix).toHaveTextContent('From')
278
+ })
279
+
280
+ test('uses default Norwegian strings', () => {
281
+ const { container } = createDatepickerTest({
282
+ range: true,
283
+ showRangeLabels: true,
284
+ })
285
+
286
+ const button = container.querySelector('button[type="button"]')
287
+ expect(button).toHaveAttribute('aria-label', 'Åpne kalender')
288
+
289
+ const prefix = container.querySelector('.pkt-input-prefix')
290
+ expect(prefix).toHaveTextContent('Fra')
291
+ })
292
+ })
293
+
294
+ describe('InputWrapper integration', () => {
295
+ test('renders helptext', () => {
296
+ createDatepickerTest({
297
+ helptext: 'Please select a date',
298
+ })
299
+
300
+ expect(screen.getByText('Please select a date')).toBeInTheDocument()
301
+ })
302
+
303
+ test('renders error message when hasError is true', () => {
304
+ createDatepickerTest({
305
+ hasError: true,
306
+ errorMessage: 'Date is required',
307
+ })
308
+
309
+ expect(screen.getByText('Date is required')).toBeInTheDocument()
310
+ })
311
+
312
+ test('renders optional tag', () => {
313
+ const { container } = createDatepickerTest({
314
+ optionalTag: true,
315
+ optionalText: 'Valgfritt',
316
+ })
317
+
318
+ expect(container.textContent).toContain('Valgfritt')
319
+ })
320
+
321
+ test('renders required tag', () => {
322
+ const { container } = createDatepickerTest({
323
+ requiredTag: true,
324
+ requiredText: 'Må fylles ut',
325
+ })
326
+
327
+ expect(container.textContent).toContain('Må fylles ut')
328
+ })
329
+
330
+ test('applies fullwidth class to input', () => {
331
+ const { container } = createDatepickerTest({
332
+ fullwidth: true,
333
+ })
334
+
335
+ const input = container.querySelector('.pkt-datepicker__input') as HTMLInputElement
336
+ expect(input).toHaveClass('pkt-input--fullwidth')
337
+ })
338
+ })
339
+
340
+ describe('CSS classes', () => {
341
+ test('applies pkt-datepicker class to outer wrapper', () => {
342
+ const { container } = createDatepickerTest()
343
+
344
+ const wrapper = container.querySelector('.pkt-datepicker')
345
+ expect(wrapper).toBeInTheDocument()
346
+ })
347
+
348
+ test('applies pkt-datepicker__inputs class', () => {
349
+ const { container } = createDatepickerTest()
350
+
351
+ const inputs = container.querySelector('.pkt-datepicker__inputs')
352
+ expect(inputs).toBeInTheDocument()
353
+ })
354
+
355
+ test('applies datepicker input classes', () => {
356
+ const { container } = createDatepickerTest()
357
+
358
+ const input = container.querySelector('.pkt-datepicker__input')
359
+ expect(input).toBeInTheDocument()
360
+ expect(input).toHaveClass('pkt-input')
361
+ })
362
+
363
+ test('applies range class for range mode', () => {
364
+ const { container } = createDatepickerTest({
365
+ range: true,
366
+ })
367
+
368
+ const inputs = container.querySelectorAll('.pkt-datepicker--range')
369
+ expect(inputs.length).toBe(2)
370
+ })
371
+
372
+ test('applies multiple class for multiple mode', () => {
373
+ const { container } = createDatepickerTest({
374
+ multiple: true,
375
+ })
376
+
377
+ const input = container.querySelector('.pkt-datepicker--multiple')
378
+ expect(input).toBeInTheDocument()
379
+ })
380
+
381
+ test('applies calendar button classes', () => {
382
+ const { container } = createDatepickerTest()
383
+
384
+ const button = container.querySelector('button[type="button"]')
385
+ expect(button).toHaveClass('pkt-input-icon')
386
+ expect(button).toHaveClass('pkt-btn')
387
+ expect(button).toHaveClass('pkt-btn--icon-only')
388
+ expect(button).toHaveClass('pkt-btn--tertiary')
389
+ expect(button).toHaveClass('pkt-datepicker__calendar-button')
390
+ })
391
+
392
+ test('popup has show/hide classes based on open state', () => {
393
+ const { container } = createDatepickerTest()
394
+
395
+ const popup = container.querySelector('.pkt-calendar-popup')
396
+ expect(popup).toHaveClass('hide')
397
+
398
+ const button = container.querySelector('button[type="button"]') as HTMLButtonElement
399
+ fireEvent.click(button)
400
+
401
+ expect(popup).toHaveClass('show')
402
+ })
403
+ })
404
+ })
@@ -0,0 +1,270 @@
1
+ import '@testing-library/jest-dom'
2
+
3
+ import { render, screen } from '@testing-library/react'
4
+
5
+ import { IPktDatepicker, PktDatepicker } from './Datepicker'
6
+
7
+ const datePickerId = 'datepickerId'
8
+ const label = 'Date Picker Label'
9
+
10
+ const createDatepickerTest = (props: Partial<IPktDatepicker> = {}) => {
11
+ const defaultProps: IPktDatepicker = {
12
+ label,
13
+ id: datePickerId,
14
+ ...props,
15
+ }
16
+
17
+ return render(<PktDatepicker {...defaultProps} />)
18
+ }
19
+
20
+ describe('PktDatepicker', () => {
21
+ describe('Rendering and basic functionality', () => {
22
+ test('renders without errors', () => {
23
+ const { container } = createDatepickerTest()
24
+
25
+ expect(container.querySelector('.pkt-datepicker')).toBeInTheDocument()
26
+ })
27
+
28
+ test('renders with correct structure', () => {
29
+ const { container } = createDatepickerTest()
30
+
31
+ const inputWrapper = container.querySelector('.pkt-inputwrapper')
32
+ expect(inputWrapper).toBeInTheDocument()
33
+
34
+ const input = container.querySelector('input[type="date"]')
35
+ expect(input).toBeInTheDocument()
36
+
37
+ const button = container.querySelector('button[type="button"]')
38
+ expect(button).toBeInTheDocument()
39
+
40
+ const popup = container.querySelector('.pkt-calendar-popup')
41
+ expect(popup).toBeInTheDocument()
42
+ expect(popup).toHaveAttribute('hidden')
43
+ })
44
+
45
+ test('renders pkt-datepicker class on outer wrapper', () => {
46
+ const { container } = createDatepickerTest()
47
+
48
+ const outer = container.querySelector('.pkt-datepicker')
49
+ expect(outer).toBeInTheDocument()
50
+ })
51
+
52
+ test('renders datepicker inputs container', () => {
53
+ const { container } = createDatepickerTest()
54
+
55
+ const inputs = container.querySelector('.pkt-datepicker__inputs')
56
+ expect(inputs).toBeInTheDocument()
57
+ })
58
+
59
+ test('renders calendar button with icon', () => {
60
+ const { container } = createDatepickerTest()
61
+
62
+ const button = container.querySelector('button[type="button"]')
63
+ expect(button).toBeInTheDocument()
64
+ expect(button).toHaveAttribute('aria-label', 'Åpne kalender')
65
+ })
66
+ })
67
+
68
+ describe('Properties and attributes', () => {
69
+ test('applies default properties correctly', () => {
70
+ const { container } = createDatepickerTest()
71
+
72
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
73
+ expect(input).toBeInTheDocument()
74
+ expect(input.value).toBe('')
75
+ expect(input).not.toBeDisabled()
76
+ expect(input).not.toBeRequired()
77
+ })
78
+
79
+ test('handles value property correctly', () => {
80
+ const { container } = createDatepickerTest({
81
+ value: '2024-06-15',
82
+ })
83
+
84
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
85
+ expect(input.value).toBe('2024-06-15')
86
+ })
87
+
88
+ test('handles multiple values correctly', () => {
89
+ const { container } = createDatepickerTest({
90
+ multiple: true,
91
+ value: ['2024-06-15', '2024-06-20', '2024-06-25'],
92
+ })
93
+
94
+ const tags = container.querySelectorAll('.pkt-date-tags .pkt-tag')
95
+ expect(tags.length).toBe(3)
96
+ })
97
+
98
+ test('handles range values correctly', () => {
99
+ const { container } = createDatepickerTest({
100
+ range: true,
101
+ value: ['2024-06-15', '2024-06-25'],
102
+ })
103
+
104
+ const inputs = container.querySelectorAll('input[type="date"]') as NodeListOf<HTMLInputElement>
105
+ expect(inputs.length).toBe(2)
106
+ expect(inputs[0].value).toBe('2024-06-15')
107
+ expect(inputs[1].value).toBe('2024-06-25')
108
+ })
109
+
110
+ test('handles label property correctly', () => {
111
+ createDatepickerTest({ label: 'Custom Label' })
112
+
113
+ expect(screen.getByText('Custom Label')).toBeInTheDocument()
114
+ })
115
+
116
+ test('handles maxlength property correctly', () => {
117
+ const { container } = createDatepickerTest({
118
+ multiple: true,
119
+ maxlength: 5,
120
+ value: ['2024-06-15', '2024-06-20'],
121
+ })
122
+
123
+ const counter = container.querySelector('.pkt-input__counter')
124
+ expect(counter).toBeInTheDocument()
125
+ })
126
+
127
+ test('handles disabled property correctly', () => {
128
+ const { container } = createDatepickerTest({
129
+ disabled: true,
130
+ })
131
+
132
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
133
+ expect(input).toBeDisabled()
134
+
135
+ const button = container.querySelector('button[type="button"]')
136
+ expect(button).toBeDisabled()
137
+ })
138
+
139
+ test('handles required attribute', () => {
140
+ const { container } = createDatepickerTest({
141
+ required: true,
142
+ })
143
+
144
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
145
+ expect(input).toBeRequired()
146
+ })
147
+
148
+ test('sets min and max date boundaries on input', () => {
149
+ const { container } = createDatepickerTest({
150
+ min: '2024-01-01',
151
+ max: '2024-12-31',
152
+ value: '2024-06-15',
153
+ })
154
+
155
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
156
+ expect(input).toHaveAttribute('min', '2024-01-01')
157
+ expect(input).toHaveAttribute('max', '2024-12-31')
158
+ })
159
+
160
+ test('sets min and max on both range inputs', () => {
161
+ const { container } = createDatepickerTest({
162
+ range: true,
163
+ min: '2024-01-01',
164
+ max: '2024-12-31',
165
+ })
166
+
167
+ const inputs = container.querySelectorAll('input[type="date"]') as NodeListOf<HTMLInputElement>
168
+ expect(inputs[0]).toHaveAttribute('min', '2024-01-01')
169
+ expect(inputs[0]).toHaveAttribute('max', '2024-12-31')
170
+ expect(inputs[1]).toHaveAttribute('min', '2024-01-01')
171
+ expect(inputs[1]).toHaveAttribute('max', '2024-12-31')
172
+ })
173
+
174
+ test('renders placeholder text correctly', () => {
175
+ const { container } = createDatepickerTest({
176
+ placeholder: 'dd.mm.yyyy',
177
+ })
178
+
179
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
180
+ expect(input).toHaveAttribute('placeholder', 'dd.mm.yyyy')
181
+ })
182
+
183
+ test('renders with custom className', () => {
184
+ const { container } = createDatepickerTest({
185
+ className: 'my-custom-class',
186
+ })
187
+
188
+ const wrapper = container.querySelector('.pkt-datepicker')
189
+ expect(wrapper).toHaveClass('my-custom-class')
190
+ })
191
+
192
+ test('uses id for input name when no name specified', () => {
193
+ const { container } = createDatepickerTest()
194
+
195
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
196
+ expect(input).toHaveAttribute('name', datePickerId)
197
+ })
198
+
199
+ test('uses custom name when specified', () => {
200
+ const { container } = createDatepickerTest({
201
+ name: 'dateField',
202
+ value: '2024-06-15',
203
+ })
204
+
205
+ const hiddenInput = container.querySelector('input[type="hidden"]') as HTMLInputElement
206
+ expect(hiddenInput).toHaveAttribute('name', 'dateField')
207
+ expect(hiddenInput.value).toBe('2024-06-15')
208
+ })
209
+ })
210
+
211
+ describe('Calendar integration', () => {
212
+ test('renders calendar popup hidden by default', () => {
213
+ const { container } = createDatepickerTest()
214
+
215
+ const popup = container.querySelector('.pkt-calendar-popup')
216
+ expect(popup).toHaveAttribute('hidden')
217
+ expect(popup).toHaveClass('hide')
218
+ })
219
+
220
+ test('renders calendar inside popup', () => {
221
+ const { container } = createDatepickerTest({ calendarOpen: true })
222
+
223
+ const calendar = container.querySelector('.pkt-calendar')
224
+ expect(calendar).toBeInTheDocument()
225
+ })
226
+
227
+ test('passes min/max to calendar component', () => {
228
+ const { container } = createDatepickerTest({
229
+ calendarOpen: true,
230
+ min: '2024-01-01',
231
+ max: '2024-12-31',
232
+ })
233
+
234
+ const calendar = container.querySelector('.pkt-calendar') as HTMLElement
235
+ expect(calendar).toBeInTheDocument()
236
+
237
+ const input = container.querySelector('input[type="date"]') as HTMLInputElement
238
+ expect(input).toHaveAttribute('min', '2024-01-01')
239
+ expect(input).toHaveAttribute('max', '2024-12-31')
240
+ })
241
+
242
+ test('passes weeknumbers to calendar', () => {
243
+ const { container } = createDatepickerTest({
244
+ calendarOpen: true,
245
+ weeknumbers: true,
246
+ })
247
+
248
+ const calendar = container.querySelector('.pkt-calendar') as HTMLElement
249
+ expect(calendar).toBeInTheDocument()
250
+ })
251
+
252
+ test('passes multiple and range to calendar', () => {
253
+ const { container: multipleContainer } = createDatepickerTest({
254
+ calendarOpen: true,
255
+ multiple: true,
256
+ })
257
+
258
+ const multiCal = multipleContainer.querySelector('.pkt-calendar') as HTMLElement
259
+ expect(multiCal).toBeInTheDocument()
260
+
261
+ const { container: rangeContainer } = createDatepickerTest({
262
+ calendarOpen: true,
263
+ range: true,
264
+ })
265
+
266
+ const rangeCal = rangeContainer.querySelector('.pkt-calendar') as HTMLElement
267
+ expect(rangeCal).toBeInTheDocument()
268
+ })
269
+ })
270
+ })