@oslokommune/punkt-elements 13.4.1 → 13.5.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/CHANGELOG.md +35 -0
- package/dist/calendar-32W9p9uc.cjs +115 -0
- package/dist/{calendar-DevQhOup.js → calendar-CJSxvwAq.js} +353 -340
- package/dist/{card-uccD6Pnv.cjs → card-BUITGoqX.cjs} +10 -10
- package/dist/{card-BI1NZONj.js → card-Dtw26f7i.js} +96 -76
- package/dist/checkbox-Gn7Wtk9h.cjs +31 -0
- package/dist/checkbox-ym7z6cpt.js +142 -0
- package/dist/{combobox-BhcqC30d.cjs → combobox-DjO0RMUB.cjs} +1 -1
- package/dist/{combobox-D9dGKWuZ.js → combobox-yE4aYhTi.js} +1 -1
- package/dist/{datepicker-CYOn3tRm.js → datepicker-BJKJBoy_.js} +102 -59
- package/dist/datepicker-CmTrG5GE.cjs +164 -0
- package/dist/index.d.ts +9 -2
- package/dist/pkt-calendar.cjs +1 -1
- package/dist/pkt-calendar.js +1 -1
- package/dist/pkt-card.cjs +1 -1
- package/dist/pkt-card.js +1 -1
- package/dist/pkt-checkbox.cjs +1 -1
- package/dist/pkt-checkbox.js +1 -1
- package/dist/pkt-combobox.cjs +1 -1
- package/dist/pkt-combobox.js +1 -1
- package/dist/pkt-datepicker.cjs +1 -1
- package/dist/pkt-datepicker.js +1 -1
- package/dist/pkt-index.cjs +1 -1
- package/dist/pkt-index.js +6 -6
- package/package.json +3 -3
- package/src/components/calendar/calendar.accessibility.test.ts +111 -0
- package/src/components/calendar/calendar.constraints.test.ts +110 -0
- package/src/components/calendar/calendar.core.test.ts +367 -0
- package/src/components/calendar/calendar.interaction.test.ts +139 -0
- package/src/components/calendar/calendar.selection.test.ts +273 -0
- package/src/components/calendar/calendar.ts +74 -42
- package/src/components/card/card.test.ts +606 -0
- package/src/components/card/card.ts +24 -1
- package/src/components/checkbox/checkbox.test.ts +535 -0
- package/src/components/checkbox/checkbox.ts +44 -1
- package/src/components/combobox/combobox.test.ts +737 -0
- package/src/components/combobox/combobox.ts +1 -1
- package/src/components/datepicker/datepicker.accessibility.test.ts +193 -0
- package/src/components/datepicker/datepicker.core.test.ts +322 -0
- package/src/components/datepicker/datepicker.input.test.ts +268 -0
- package/src/components/datepicker/datepicker.selection.test.ts +286 -0
- package/src/components/datepicker/datepicker.ts +121 -19
- package/src/components/datepicker/datepicker.validation.test.ts +176 -0
- package/dist/calendar-BZe2D4Sr.cjs +0 -108
- package/dist/checkbox-CTRbpbye.js +0 -120
- package/dist/checkbox-wJ26voZd.cjs +0 -30
- package/dist/datepicker-B9rhz_AF.cjs +0 -154
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|
|
2
|
+
import { fireEvent } from '@testing-library/dom'
|
|
3
|
+
|
|
4
|
+
import './datepicker'
|
|
5
|
+
import '../calendar/calendar'
|
|
6
|
+
import { PktDatepicker } from './datepicker'
|
|
7
|
+
|
|
8
|
+
const waitForCustomElements = async () => {
|
|
9
|
+
await customElements.whenDefined('pkt-datepicker')
|
|
10
|
+
await customElements.whenDefined('pkt-calendar')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Helper function to create datepicker markup
|
|
14
|
+
const createDatepicker = async (datepickerProps = '') => {
|
|
15
|
+
const container = document.createElement('div')
|
|
16
|
+
container.innerHTML = `
|
|
17
|
+
<pkt-datepicker ${datepickerProps}></pkt-datepicker>
|
|
18
|
+
`
|
|
19
|
+
document.body.appendChild(container)
|
|
20
|
+
await waitForCustomElements()
|
|
21
|
+
return container
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Cleanup after each test
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
document.body.innerHTML = ''
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
describe('PktDatepicker', () => {
|
|
30
|
+
describe('Date input validation and formatting', () => {
|
|
31
|
+
test('validates date input format', async () => {
|
|
32
|
+
const container = await createDatepicker('label="Test"')
|
|
33
|
+
|
|
34
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
35
|
+
await datepicker.updateComplete
|
|
36
|
+
|
|
37
|
+
const input = datepicker.querySelector('input') as HTMLInputElement
|
|
38
|
+
|
|
39
|
+
// Test invalid date input - HTML5 date inputs will reject invalid formats
|
|
40
|
+
// For date inputs, we test boundary validation instead
|
|
41
|
+
fireEvent.change(input, { target: { value: '2024-02-30' } }) // Invalid date (Feb 30th)
|
|
42
|
+
fireEvent.blur(input)
|
|
43
|
+
await datepicker.updateComplete
|
|
44
|
+
|
|
45
|
+
// Should show validation error or handle gracefully
|
|
46
|
+
// For HTML5 date inputs, this might not trigger hasError, so we test that it doesn't crash
|
|
47
|
+
expect(datepicker).toBeInTheDocument()
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('formats dates according to dateformat property', async () => {
|
|
51
|
+
const container = await createDatepicker('dateformat="yyyy-MM-dd" value="2024-06-15"')
|
|
52
|
+
|
|
53
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
54
|
+
await datepicker.updateComplete
|
|
55
|
+
|
|
56
|
+
const input = datepicker.querySelector('input') as HTMLInputElement
|
|
57
|
+
expect(input.value).toBe('2024-06-15')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('handles different date formats', async () => {
|
|
61
|
+
const testCases = [
|
|
62
|
+
{ format: 'dd.MM.yyyy', expected: /\d{2}\.\d{2}\.\d{4}/ },
|
|
63
|
+
{ format: 'MM/dd/yyyy', expected: /\d{2}\/\d{2}\/\d{4}/ },
|
|
64
|
+
{ format: 'yyyy-MM-dd', expected: /\d{4}-\d{2}-\d{2}/ },
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
for (const testCase of testCases) {
|
|
68
|
+
const container = await createDatepicker(
|
|
69
|
+
`dateformat="${testCase.format}" value="2024-06-15" multiple`,
|
|
70
|
+
)
|
|
71
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
72
|
+
await datepicker.updateComplete
|
|
73
|
+
|
|
74
|
+
// Multiple mode input should be empty (for new input)
|
|
75
|
+
const input = datepicker.querySelector('input') as HTMLInputElement
|
|
76
|
+
expect(input.value).toBe('')
|
|
77
|
+
|
|
78
|
+
// Selected dates should show in tags with custom format
|
|
79
|
+
const tag = datepicker.querySelector('pkt-tag time')
|
|
80
|
+
expect(tag).toBeInTheDocument()
|
|
81
|
+
if (tag) {
|
|
82
|
+
expect(tag.textContent).toMatch(testCase.expected)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Cleanup
|
|
86
|
+
container.remove()
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test('handles leap year dates correctly', async () => {
|
|
91
|
+
const leapYearDate = '2024-02-29'
|
|
92
|
+
const container = await createDatepicker(`value="${leapYearDate}"`)
|
|
93
|
+
|
|
94
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
95
|
+
await datepicker.updateComplete
|
|
96
|
+
|
|
97
|
+
expect(datepicker.value).toBe(leapYearDate)
|
|
98
|
+
expect(datepicker.hasError).toBe(false)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
test('validates February 29 in non-leap years', async () => {
|
|
102
|
+
const invalidLeapDate = '2023-02-29'
|
|
103
|
+
const container = await createDatepicker(`value="${invalidLeapDate}"`)
|
|
104
|
+
|
|
105
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
106
|
+
await datepicker.updateComplete
|
|
107
|
+
|
|
108
|
+
// Should handle gracefully or show error
|
|
109
|
+
expect(datepicker).toBeInTheDocument()
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
test('handles edge case dates', async () => {
|
|
113
|
+
const edgeDates = ['1900-01-01', '2000-01-01', '2100-12-31', '1999-12-31']
|
|
114
|
+
|
|
115
|
+
for (const date of edgeDates) {
|
|
116
|
+
const container = await createDatepicker(`value="${date}"`)
|
|
117
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
118
|
+
await datepicker.updateComplete
|
|
119
|
+
|
|
120
|
+
expect(datepicker.value).toBe(date)
|
|
121
|
+
container.remove()
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
describe('Input field behavior', () => {
|
|
127
|
+
test('allows manual date entry', async () => {
|
|
128
|
+
const container = await createDatepicker('dateformat="yyyy-MM-dd"')
|
|
129
|
+
|
|
130
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
131
|
+
await datepicker.updateComplete
|
|
132
|
+
|
|
133
|
+
const input = datepicker.querySelector('input') as HTMLInputElement
|
|
134
|
+
|
|
135
|
+
fireEvent.change(input, { target: { value: '2024-06-15' } })
|
|
136
|
+
fireEvent.blur(input)
|
|
137
|
+
await datepicker.updateComplete
|
|
138
|
+
|
|
139
|
+
expect(datepicker.value).toBe('2024-06-15')
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test('validates manual date entry', async () => {
|
|
143
|
+
const container = await createDatepicker()
|
|
144
|
+
|
|
145
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
146
|
+
await datepicker.updateComplete
|
|
147
|
+
|
|
148
|
+
const input = datepicker.querySelector('input') as HTMLInputElement
|
|
149
|
+
|
|
150
|
+
// HTML5 date inputs reject invalid formats, so we test that the component handles this gracefully
|
|
151
|
+
fireEvent.change(input, { target: { value: 'invalid-date' } })
|
|
152
|
+
fireEvent.blur(input)
|
|
153
|
+
await datepicker.updateComplete
|
|
154
|
+
|
|
155
|
+
// HTML5 date input will reject invalid dates, component should handle gracefully
|
|
156
|
+
expect(datepicker).toBeInTheDocument()
|
|
157
|
+
expect(input.value).toBe('') // Invalid dates become empty
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
test('shows placeholder text correctly', async () => {
|
|
161
|
+
const placeholderText = 'Select a date'
|
|
162
|
+
const container = await createDatepicker(`placeholder="${placeholderText}"`)
|
|
163
|
+
|
|
164
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
165
|
+
await datepicker.updateComplete
|
|
166
|
+
|
|
167
|
+
const input = datepicker.querySelector('input') as HTMLInputElement
|
|
168
|
+
expect(input.placeholder).toBe(placeholderText)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
test('shows help text correctly', async () => {
|
|
172
|
+
const helpText = 'Choose your preferred date'
|
|
173
|
+
const container = await createDatepicker(`helptext="${helpText}"`)
|
|
174
|
+
|
|
175
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
176
|
+
await datepicker.updateComplete
|
|
177
|
+
|
|
178
|
+
const helpTextElement = datepicker.querySelector('pkt-helptext')
|
|
179
|
+
expect(helpTextElement?.textContent).toContain(helpText)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test('handles readonly state correctly', async () => {
|
|
183
|
+
const container = await createDatepicker('readonly')
|
|
184
|
+
|
|
185
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
186
|
+
await datepicker.updateComplete
|
|
187
|
+
|
|
188
|
+
const input = datepicker.querySelector('input') as HTMLInputElement
|
|
189
|
+
expect(input.readOnly).toBe(true)
|
|
190
|
+
|
|
191
|
+
// Calendar should still be accessible
|
|
192
|
+
const calendarButton = datepicker.querySelector('button[type="button"]') as HTMLButtonElement
|
|
193
|
+
expect(calendarButton.disabled).toBe(false)
|
|
194
|
+
})
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
describe('Keyboard navigation and interaction', () => {
|
|
198
|
+
test('opens calendar with Enter key on calendar button', async () => {
|
|
199
|
+
const container = await createDatepicker()
|
|
200
|
+
|
|
201
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
202
|
+
await datepicker.updateComplete
|
|
203
|
+
|
|
204
|
+
const calendarButton = datepicker.querySelector('button[type="button"]') as HTMLElement
|
|
205
|
+
if (calendarButton) {
|
|
206
|
+
calendarButton.focus()
|
|
207
|
+
|
|
208
|
+
fireEvent.keyDown(calendarButton, { key: 'Enter' })
|
|
209
|
+
await datepicker.updateComplete
|
|
210
|
+
|
|
211
|
+
expect(datepicker.calendarOpen).toBe(true)
|
|
212
|
+
}
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
test('opens calendar with Space key on calendar button', async () => {
|
|
216
|
+
const container = await createDatepicker()
|
|
217
|
+
|
|
218
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
219
|
+
await datepicker.updateComplete
|
|
220
|
+
|
|
221
|
+
const calendarButton = datepicker.querySelector('button[type="button"]') as HTMLElement
|
|
222
|
+
if (calendarButton) {
|
|
223
|
+
calendarButton.focus()
|
|
224
|
+
|
|
225
|
+
fireEvent.keyDown(calendarButton, { key: ' ' })
|
|
226
|
+
await datepicker.updateComplete
|
|
227
|
+
|
|
228
|
+
expect(datepicker.calendarOpen).toBe(true)
|
|
229
|
+
}
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
test('closes calendar with Escape key', async () => {
|
|
233
|
+
const container = await createDatepicker()
|
|
234
|
+
|
|
235
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
236
|
+
await datepicker.updateComplete
|
|
237
|
+
|
|
238
|
+
// Open calendar
|
|
239
|
+
const calendarButton = datepicker.querySelector('button[type="button"]')
|
|
240
|
+
fireEvent.click(calendarButton!)
|
|
241
|
+
await datepicker.updateComplete
|
|
242
|
+
|
|
243
|
+
// Press Escape
|
|
244
|
+
fireEvent.keyDown(datepicker, { key: 'Escape' })
|
|
245
|
+
await datepicker.updateComplete
|
|
246
|
+
|
|
247
|
+
expect(datepicker.calendarOpen).toBe(false)
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
test('navigates between tags with arrow keys in multiple mode', async () => {
|
|
251
|
+
const multipleDates = '2024-06-15,2024-06-20,2024-06-25'
|
|
252
|
+
const container = await createDatepicker(`value="${multipleDates}" multiple`)
|
|
253
|
+
|
|
254
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
255
|
+
await datepicker.updateComplete
|
|
256
|
+
|
|
257
|
+
const tags = datepicker.querySelectorAll('pkt-tag')
|
|
258
|
+
const firstTag = tags[0] as HTMLElement
|
|
259
|
+
|
|
260
|
+
firstTag.focus()
|
|
261
|
+
fireEvent.keyDown(firstTag, { key: 'ArrowRight' })
|
|
262
|
+
await datepicker.updateComplete
|
|
263
|
+
|
|
264
|
+
// Focus should move to next tag
|
|
265
|
+
expect(document.activeElement).toBeTruthy()
|
|
266
|
+
})
|
|
267
|
+
})
|
|
268
|
+
})
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|
|
2
|
+
import { fireEvent } from '@testing-library/dom'
|
|
3
|
+
|
|
4
|
+
import './datepicker'
|
|
5
|
+
import '../calendar/calendar'
|
|
6
|
+
import { PktDatepicker } from './datepicker'
|
|
7
|
+
|
|
8
|
+
const waitForCustomElements = async () => {
|
|
9
|
+
await customElements.whenDefined('pkt-datepicker')
|
|
10
|
+
await customElements.whenDefined('pkt-calendar')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Helper function to create datepicker markup
|
|
14
|
+
const createDatepicker = async (datepickerProps = '') => {
|
|
15
|
+
const container = document.createElement('div')
|
|
16
|
+
container.innerHTML = `
|
|
17
|
+
<pkt-datepicker ${datepickerProps}></pkt-datepicker>
|
|
18
|
+
`
|
|
19
|
+
document.body.appendChild(container)
|
|
20
|
+
await waitForCustomElements()
|
|
21
|
+
return container
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Cleanup after each test
|
|
25
|
+
afterEach(() => {
|
|
26
|
+
document.body.innerHTML = ''
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
describe('PktDatepicker', () => {
|
|
30
|
+
describe('Multiple date selection', () => {
|
|
31
|
+
test('displays multiple selected dates as tags', async () => {
|
|
32
|
+
const multipleDates = '2024-06-15,2024-06-20,2024-06-25'
|
|
33
|
+
const container = await createDatepicker(`value="${multipleDates}" multiple`)
|
|
34
|
+
|
|
35
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
36
|
+
await datepicker.updateComplete
|
|
37
|
+
|
|
38
|
+
const tags = datepicker.querySelectorAll('pkt-tag')
|
|
39
|
+
expect(tags.length).toBe(3)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('allows adding dates through calendar in multiple mode', async () => {
|
|
43
|
+
const container = await createDatepicker('multiple')
|
|
44
|
+
|
|
45
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
46
|
+
await datepicker.updateComplete
|
|
47
|
+
|
|
48
|
+
// Open calendar
|
|
49
|
+
const calendarButton = datepicker.querySelector('button[type="button"]')
|
|
50
|
+
fireEvent.click(calendarButton!)
|
|
51
|
+
await datepicker.updateComplete
|
|
52
|
+
|
|
53
|
+
// Select a date
|
|
54
|
+
const availableDate = datepicker.querySelector('[data-date]:not([data-disabled="disabled"])')
|
|
55
|
+
if (availableDate) {
|
|
56
|
+
fireEvent.click(availableDate)
|
|
57
|
+
await datepicker.updateComplete
|
|
58
|
+
|
|
59
|
+
// Should add tag
|
|
60
|
+
const tags = datepicker.querySelectorAll('pkt-tag')
|
|
61
|
+
expect(tags.length).toBe(1)
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('removes dates when clicking tag close button', async () => {
|
|
66
|
+
const multipleDates = '2024-06-15,2024-06-20'
|
|
67
|
+
const container = await createDatepicker(`value="${multipleDates}" multiple`)
|
|
68
|
+
|
|
69
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
70
|
+
await datepicker.updateComplete
|
|
71
|
+
|
|
72
|
+
const closeButtons = datepicker.querySelectorAll('pkt-tag .pkt-tag__close-btn')
|
|
73
|
+
expect(closeButtons.length).toBe(2)
|
|
74
|
+
|
|
75
|
+
// Click first close button
|
|
76
|
+
fireEvent.click(closeButtons[0])
|
|
77
|
+
await datepicker.updateComplete
|
|
78
|
+
|
|
79
|
+
const remainingTags = datepicker.querySelectorAll('pkt-tag')
|
|
80
|
+
expect(remainingTags.length).toBe(1)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test('respects maxlength in multiple mode', async () => {
|
|
84
|
+
const container = await createDatepicker('multiple maxlength="2"')
|
|
85
|
+
|
|
86
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
87
|
+
await datepicker.updateComplete
|
|
88
|
+
|
|
89
|
+
// Open calendar and try to select more than maxlength dates
|
|
90
|
+
const calendarButton = datepicker.querySelector('button[type="button"]')
|
|
91
|
+
fireEvent.click(calendarButton!)
|
|
92
|
+
await datepicker.updateComplete
|
|
93
|
+
|
|
94
|
+
const availableDates = datepicker.querySelectorAll(
|
|
95
|
+
'.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
// Select 3 dates
|
|
99
|
+
fireEvent.click(availableDates[0])
|
|
100
|
+
await datepicker.updateComplete
|
|
101
|
+
fireEvent.click(availableDates[1])
|
|
102
|
+
await datepicker.updateComplete
|
|
103
|
+
fireEvent.click(availableDates[2])
|
|
104
|
+
await datepicker.updateComplete
|
|
105
|
+
|
|
106
|
+
// Should only have maxlength tags
|
|
107
|
+
const tags = datepicker.querySelectorAll('pkt-tag')
|
|
108
|
+
expect(tags.length).toBeLessThanOrEqual(2)
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
test('sorts multiple dates chronologically', async () => {
|
|
112
|
+
const unsortedDates = '2024-06-25,2024-06-15,2024-06-20'
|
|
113
|
+
const container = await createDatepicker(`value="${unsortedDates}" multiple`)
|
|
114
|
+
|
|
115
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
116
|
+
await datepicker.updateComplete
|
|
117
|
+
|
|
118
|
+
const tags = datepicker.querySelectorAll('pkt-tag')
|
|
119
|
+
const tagTexts = Array.from(tags).map((tag) => tag.textContent?.trim())
|
|
120
|
+
|
|
121
|
+
// Should be sorted chronologically
|
|
122
|
+
expect(tagTexts[0]).toContain('15')
|
|
123
|
+
expect(tagTexts[1]).toContain('20')
|
|
124
|
+
expect(tagTexts[2]).toContain('25')
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
describe('Range selection', () => {
|
|
129
|
+
test('displays range labels when showRangeLabels is true', async () => {
|
|
130
|
+
const rangeValue = '2024-06-15,2024-06-20'
|
|
131
|
+
const container = await createDatepicker(`value="${rangeValue}" range showRangeLabels`)
|
|
132
|
+
|
|
133
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
134
|
+
await datepicker.updateComplete
|
|
135
|
+
|
|
136
|
+
expect(datepicker.showRangeLabels).toBe(true)
|
|
137
|
+
|
|
138
|
+
const rangeLabels = datepicker.querySelectorAll('.pkt-input-prefix')
|
|
139
|
+
expect(rangeLabels.length).toBeGreaterThan(0)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
test('populates both input fields when initialized with range value', async () => {
|
|
143
|
+
const rangeValue = '2024-06-15,2024-06-20'
|
|
144
|
+
const container = await createDatepicker(`value="${rangeValue}" range`)
|
|
145
|
+
|
|
146
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
147
|
+
await datepicker.updateComplete
|
|
148
|
+
|
|
149
|
+
const inputs = datepicker.querySelectorAll('input')
|
|
150
|
+
expect(inputs.length).toBe(2)
|
|
151
|
+
|
|
152
|
+
// Check that both input fields are populated
|
|
153
|
+
expect(inputs[0].value).toBe('2024-06-15')
|
|
154
|
+
expect(inputs[1].value).toBe('2024-06-20')
|
|
155
|
+
|
|
156
|
+
// Check internal state
|
|
157
|
+
expect(datepicker._value).toEqual(['2024-06-15', '2024-06-20'])
|
|
158
|
+
expect(datepicker.value).toBe('2024-06-15,2024-06-20')
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
test('dispatches value-change event with array for range and multiple datepickers', async () => {
|
|
162
|
+
// Test range datepicker
|
|
163
|
+
const rangeContainer = await createDatepicker('range')
|
|
164
|
+
const rangeDatepicker = rangeContainer.querySelector('pkt-datepicker') as PktDatepicker
|
|
165
|
+
await rangeDatepicker.updateComplete
|
|
166
|
+
|
|
167
|
+
let valueChangeEvent: CustomEvent | null = null
|
|
168
|
+
rangeDatepicker.addEventListener('value-change', (e: Event) => {
|
|
169
|
+
valueChangeEvent = e as CustomEvent
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
// Set a range value programmatically
|
|
173
|
+
rangeDatepicker.value = '2024-06-15,2024-06-20'
|
|
174
|
+
await rangeDatepicker.updateComplete
|
|
175
|
+
|
|
176
|
+
expect(valueChangeEvent).toBeTruthy()
|
|
177
|
+
expect(valueChangeEvent!.detail).toEqual(['2024-06-15', '2024-06-20'])
|
|
178
|
+
|
|
179
|
+
// Test multiple datepicker
|
|
180
|
+
const multipleContainer = await createDatepicker('multiple')
|
|
181
|
+
const multipleDatepicker = multipleContainer.querySelector('pkt-datepicker') as PktDatepicker
|
|
182
|
+
await multipleDatepicker.updateComplete
|
|
183
|
+
|
|
184
|
+
valueChangeEvent = null
|
|
185
|
+
multipleDatepicker.addEventListener('value-change', (e: Event) => {
|
|
186
|
+
valueChangeEvent = e as CustomEvent
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
// Set multiple values programmatically
|
|
190
|
+
multipleDatepicker.value = '2024-06-15,2024-06-20,2024-06-25'
|
|
191
|
+
await multipleDatepicker.updateComplete
|
|
192
|
+
|
|
193
|
+
expect(valueChangeEvent).toBeTruthy()
|
|
194
|
+
expect(valueChangeEvent!.detail).toEqual(['2024-06-15', '2024-06-20', '2024-06-25'])
|
|
195
|
+
|
|
196
|
+
// Test single datepicker
|
|
197
|
+
const singleContainer = await createDatepicker('')
|
|
198
|
+
const singleDatepicker = singleContainer.querySelector('pkt-datepicker') as PktDatepicker
|
|
199
|
+
await singleDatepicker.updateComplete
|
|
200
|
+
|
|
201
|
+
valueChangeEvent = null
|
|
202
|
+
singleDatepicker.addEventListener('value-change', (e: Event) => {
|
|
203
|
+
valueChangeEvent = e as CustomEvent
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
// Set single value programmatically
|
|
207
|
+
singleDatepicker.value = '2024-06-15'
|
|
208
|
+
await singleDatepicker.updateComplete
|
|
209
|
+
|
|
210
|
+
expect(valueChangeEvent).toBeTruthy()
|
|
211
|
+
expect(valueChangeEvent!.detail).toBe('2024-06-15')
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
test('handles range selection through calendar', async () => {
|
|
215
|
+
const container = await createDatepicker('range')
|
|
216
|
+
|
|
217
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
218
|
+
await datepicker.updateComplete
|
|
219
|
+
|
|
220
|
+
// Open calendar
|
|
221
|
+
const calendarButton = datepicker.querySelector('button[type="button"]')
|
|
222
|
+
fireEvent.click(calendarButton!)
|
|
223
|
+
await datepicker.updateComplete
|
|
224
|
+
|
|
225
|
+
const availableDates = datepicker.querySelectorAll(
|
|
226
|
+
'[data-date]:not([data-disabled="disabled"])',
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
// Select start date
|
|
230
|
+
if (availableDates.length > 5) {
|
|
231
|
+
fireEvent.click(availableDates[5])
|
|
232
|
+
await datepicker.updateComplete
|
|
233
|
+
|
|
234
|
+
// Select end date
|
|
235
|
+
if (availableDates.length > 10) {
|
|
236
|
+
fireEvent.click(availableDates[10])
|
|
237
|
+
await datepicker.updateComplete
|
|
238
|
+
|
|
239
|
+
// Should have range value
|
|
240
|
+
expect(datepicker.value).toContain(',')
|
|
241
|
+
const values = (datepicker.value as string).split(',')
|
|
242
|
+
expect(values.length).toBe(2)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
test('validates range order', async () => {
|
|
248
|
+
const invalidRange = '2024-06-20,2024-06-15' // End before start
|
|
249
|
+
const container = await createDatepicker(`value="${invalidRange}" range`)
|
|
250
|
+
|
|
251
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
252
|
+
await datepicker.updateComplete
|
|
253
|
+
|
|
254
|
+
// Should handle invalid range gracefully
|
|
255
|
+
expect(datepicker).toBeInTheDocument()
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
test('shows range preview on hover', async () => {
|
|
259
|
+
const container = await createDatepicker('range')
|
|
260
|
+
|
|
261
|
+
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
|
|
262
|
+
await datepicker.updateComplete
|
|
263
|
+
|
|
264
|
+
// Open calendar
|
|
265
|
+
const calendarButton = datepicker.querySelector('button[type="button"]')
|
|
266
|
+
fireEvent.click(calendarButton!)
|
|
267
|
+
await datepicker.updateComplete
|
|
268
|
+
|
|
269
|
+
const availableDates = datepicker.querySelectorAll(
|
|
270
|
+
'.pkt-calendar__date:not(.pkt-calendar__date--disabled)',
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
// Select start date
|
|
274
|
+
fireEvent.click(availableDates[5])
|
|
275
|
+
await datepicker.updateComplete
|
|
276
|
+
|
|
277
|
+
// Hover over potential end date
|
|
278
|
+
fireEvent.mouseOver(availableDates[10])
|
|
279
|
+
await datepicker.updateComplete
|
|
280
|
+
|
|
281
|
+
// Should show hover preview
|
|
282
|
+
const hoverRanges = datepicker.querySelectorAll('.pkt-calendar__date--in-range-hover')
|
|
283
|
+
expect(hoverRanges.length).toBeGreaterThan(0)
|
|
284
|
+
})
|
|
285
|
+
})
|
|
286
|
+
})
|