@oslokommune/punkt-elements 13.5.4 → 13.5.6
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 +34 -0
- package/dist/pkt-index.cjs +1 -1
- package/dist/pkt-index.js +1 -1
- package/dist/pkt-select.cjs +1 -1
- package/dist/pkt-select.js +1 -1
- package/dist/{select-Dkl0KhGW.cjs → select-CD6Zn8YH.cjs} +12 -12
- package/dist/{select-CJS_CIKv.js → select-dcaJHvmR.js} +20 -20
- package/package.json +2 -2
- package/src/components/progressbar/progressbar.test.ts +195 -0
- package/src/components/radiobutton/radiobutton.test.ts +272 -0
- package/src/components/select/select.test.ts +227 -0
- package/src/components/select/select.ts +23 -12
- package/src/components/tag/tag.test.ts +211 -0
- package/src/components/textarea/textarea.test.ts +289 -0
- package/src/components/textinput/textinput.test.ts +421 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|
|
2
|
+
import { axe, toHaveNoViolations } from 'jest-axe'
|
|
3
|
+
import { fireEvent } from '@testing-library/dom'
|
|
4
|
+
import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
|
|
5
|
+
import { CustomElementFor } from '../../tests/component-registry'
|
|
6
|
+
import './radiobutton'
|
|
7
|
+
|
|
8
|
+
export interface RadioButtonTestConfig extends BaseTestConfig {
|
|
9
|
+
value?: string
|
|
10
|
+
checkHelptext?: string | null
|
|
11
|
+
defaultChecked?: boolean
|
|
12
|
+
hasTile?: boolean
|
|
13
|
+
checked?: boolean | string | null
|
|
14
|
+
type?: string
|
|
15
|
+
tagText?: string | null
|
|
16
|
+
optionalTag?: boolean
|
|
17
|
+
optionalText?: string
|
|
18
|
+
requiredTag?: boolean
|
|
19
|
+
requiredText?: string
|
|
20
|
+
|
|
21
|
+
id?: string
|
|
22
|
+
name?: string
|
|
23
|
+
label?: string
|
|
24
|
+
disabled?: boolean
|
|
25
|
+
readonly?: boolean
|
|
26
|
+
required?: boolean
|
|
27
|
+
hasError?: boolean
|
|
28
|
+
inline?: boolean
|
|
29
|
+
ariaDescribedBy?: string | null
|
|
30
|
+
ariaLabelledby?: string | null
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const createRadioButtonTest = async (config: RadioButtonTestConfig = {}) => {
|
|
34
|
+
const { container, element } = await createElementTest<
|
|
35
|
+
CustomElementFor<'pkt-radiobutton'>,
|
|
36
|
+
RadioButtonTestConfig
|
|
37
|
+
>('pkt-radiobutton', config)
|
|
38
|
+
|
|
39
|
+
if (config.label) {
|
|
40
|
+
element.label = config.label
|
|
41
|
+
await element.updateComplete
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
container,
|
|
46
|
+
radiobutton: element,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
expect.extend(toHaveNoViolations)
|
|
51
|
+
|
|
52
|
+
describe('pkt-radiobutton', () => {
|
|
53
|
+
afterEach(() => {
|
|
54
|
+
document.body.innerHTML = ''
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('renders with basic properties', async () => {
|
|
58
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
59
|
+
id: 'test',
|
|
60
|
+
name: 'test',
|
|
61
|
+
value: 'test',
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
expect(radiobutton).toBeInTheDocument()
|
|
65
|
+
expect(radiobutton.tagName).toBe('PKT-RADIOBUTTON')
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('renders input element with correct attributes', async () => {
|
|
69
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
70
|
+
id: 'test',
|
|
71
|
+
name: 'test',
|
|
72
|
+
value: 'test',
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
const input = radiobutton.querySelector('input[type="radio"]') as HTMLInputElement
|
|
76
|
+
expect(input).toBeInTheDocument()
|
|
77
|
+
expect(input.type).toBe('radio')
|
|
78
|
+
expect(input.id).toBe('test-internal')
|
|
79
|
+
expect(input.name).toBe('test-internal')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('displays label correctly', async () => {
|
|
83
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
84
|
+
id: 'test',
|
|
85
|
+
label: 'Test Radio',
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
const label = radiobutton.querySelector('label')
|
|
89
|
+
expect(label).toBeInTheDocument()
|
|
90
|
+
expect(label?.textContent?.trim()).toContain('Test Radio')
|
|
91
|
+
expect(label?.getAttribute('for')).toBe('test-internal')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('handles checked state correctly', async () => {
|
|
95
|
+
const { radiobutton } = await createRadioButtonTest()
|
|
96
|
+
|
|
97
|
+
expect(radiobutton.checked).toBe(null)
|
|
98
|
+
|
|
99
|
+
radiobutton.checked = true
|
|
100
|
+
await radiobutton.updateComplete
|
|
101
|
+
|
|
102
|
+
const input = radiobutton.querySelector('input') as HTMLInputElement
|
|
103
|
+
expect(input.checked).toBe(true)
|
|
104
|
+
expect(radiobutton.checked).toBe(true)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
test('updates checked state on user interaction', async () => {
|
|
108
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
109
|
+
label: 'Test Option',
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
const input = radiobutton.querySelector('input') as HTMLInputElement
|
|
113
|
+
expect(input.checked).toBe(false)
|
|
114
|
+
expect(radiobutton.touched).toBe(false)
|
|
115
|
+
|
|
116
|
+
fireEvent.click(input)
|
|
117
|
+
await radiobutton.updateComplete
|
|
118
|
+
|
|
119
|
+
expect(input.checked).toBe(true)
|
|
120
|
+
expect(radiobutton.touched).toBe(true)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
test('handles disabled state correctly', async () => {
|
|
124
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
125
|
+
disabled: true,
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
const input = radiobutton.querySelector('input') as HTMLInputElement
|
|
129
|
+
expect(input.disabled).toBe(true)
|
|
130
|
+
|
|
131
|
+
const label = radiobutton.querySelector('.pkt-input-check__input-label')
|
|
132
|
+
expect(label).toHaveClass('pkt-input-check__input-label--disabled')
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
test('renders tile variant correctly', async () => {
|
|
136
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
137
|
+
hasTile: true,
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
const container = radiobutton.querySelector('.pkt-input-check__input')
|
|
141
|
+
expect(container).toHaveClass('pkt-input-check__input--tile')
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test('renders disabled tile variant correctly', async () => {
|
|
145
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
146
|
+
hasTile: true,
|
|
147
|
+
disabled: true,
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
const container = radiobutton.querySelector('.pkt-input-check__input')
|
|
151
|
+
expect(container).toHaveClass('pkt-input-check__input--tile-disabled')
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
test('renders helptext when provided', async () => {
|
|
155
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
156
|
+
checkHelptext: 'This is helpful information',
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
const helptext = radiobutton.querySelector('.pkt-input-check__input-helptext')
|
|
160
|
+
expect(helptext).toBeInTheDocument()
|
|
161
|
+
expect(helptext?.textContent).toBe('This is helpful information')
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
test('handles error state correctly', async () => {
|
|
165
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
166
|
+
hasError: true,
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
const input = radiobutton.querySelector('input')
|
|
170
|
+
expect(input).toHaveClass('pkt-input-check__input-checkbox--error')
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
test('renders tag text when provided', async () => {
|
|
174
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
175
|
+
tagText: 'Tag',
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
const tag = radiobutton.querySelector('.pkt-tag--gray')
|
|
179
|
+
expect(tag).toBeInTheDocument()
|
|
180
|
+
expect(tag?.textContent).toBe('Tag')
|
|
181
|
+
})
|
|
182
|
+
|
|
183
|
+
test('renders optional tag when enabled', async () => {
|
|
184
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
185
|
+
optionalTag: true,
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
const tag = radiobutton.querySelector('.pkt-tag--blue-light')
|
|
189
|
+
expect(tag).toBeInTheDocument()
|
|
190
|
+
expect(tag?.textContent).toBe('Valgfritt')
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test('renders required tag when enabled', async () => {
|
|
194
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
195
|
+
requiredTag: true,
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
const tag = radiobutton.querySelector('.pkt-tag--beige')
|
|
199
|
+
expect(tag).toBeInTheDocument()
|
|
200
|
+
expect(tag?.textContent).toBe('Må fylles ut')
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
test('manages focus events correctly', async () => {
|
|
204
|
+
const { radiobutton } = await createRadioButtonTest()
|
|
205
|
+
|
|
206
|
+
const focusSpy = jest.fn()
|
|
207
|
+
const blurSpy = jest.fn()
|
|
208
|
+
radiobutton.addEventListener('focus', focusSpy)
|
|
209
|
+
radiobutton.addEventListener('blur', blurSpy)
|
|
210
|
+
|
|
211
|
+
const input = radiobutton.querySelector('input') as HTMLInputElement
|
|
212
|
+
|
|
213
|
+
fireEvent.focus(input)
|
|
214
|
+
expect(focusSpy).toHaveBeenCalled()
|
|
215
|
+
|
|
216
|
+
fireEvent.blur(input)
|
|
217
|
+
expect(blurSpy).toHaveBeenCalled()
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
test('works with radio button groups', async () => {
|
|
221
|
+
const container = document.createElement('form')
|
|
222
|
+
document.body.appendChild(container)
|
|
223
|
+
|
|
224
|
+
const radio1Container = document.createElement('div')
|
|
225
|
+
radio1Container.innerHTML = '<pkt-radiobutton name="group" value="1"></pkt-radiobutton>'
|
|
226
|
+
container.appendChild(radio1Container)
|
|
227
|
+
await customElements.whenDefined('pkt-radiobutton')
|
|
228
|
+
const radio1 = radio1Container.querySelector(
|
|
229
|
+
'pkt-radiobutton',
|
|
230
|
+
) as CustomElementFor<'pkt-radiobutton'>
|
|
231
|
+
radio1.label = 'Option 1'
|
|
232
|
+
await radio1.updateComplete
|
|
233
|
+
|
|
234
|
+
const radio2Container = document.createElement('div')
|
|
235
|
+
radio2Container.innerHTML = '<pkt-radiobutton name="group" value="2"></pkt-radiobutton>'
|
|
236
|
+
container.appendChild(radio2Container)
|
|
237
|
+
const radio2 = radio2Container.querySelector(
|
|
238
|
+
'pkt-radiobutton',
|
|
239
|
+
) as CustomElementFor<'pkt-radiobutton'>
|
|
240
|
+
radio2.label = 'Option 2'
|
|
241
|
+
await radio2.updateComplete
|
|
242
|
+
|
|
243
|
+
const input1 = radio1.querySelector('input') as HTMLInputElement
|
|
244
|
+
const input2 = radio2.querySelector('input') as HTMLInputElement
|
|
245
|
+
|
|
246
|
+
expect(input1.checked).toBe(false)
|
|
247
|
+
expect(input2.checked).toBe(false)
|
|
248
|
+
|
|
249
|
+
fireEvent.click(input1)
|
|
250
|
+
await radio1.updateComplete
|
|
251
|
+
|
|
252
|
+
expect(input1.checked).toBe(true)
|
|
253
|
+
expect(radio1.touched).toBe(true)
|
|
254
|
+
|
|
255
|
+
fireEvent.click(input2)
|
|
256
|
+
await radio2.updateComplete
|
|
257
|
+
|
|
258
|
+
expect(input2.checked).toBe(true)
|
|
259
|
+
expect(radio2.touched).toBe(true)
|
|
260
|
+
|
|
261
|
+
document.body.removeChild(container)
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
test('meets accessibility standards', async () => {
|
|
265
|
+
const { radiobutton } = await createRadioButtonTest({
|
|
266
|
+
label: 'Accessible Radio Button',
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
const results = await axe(radiobutton)
|
|
270
|
+
expect(results).toHaveNoViolations()
|
|
271
|
+
})
|
|
272
|
+
})
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|
|
2
|
+
import { axe, toHaveNoViolations } from 'jest-axe'
|
|
3
|
+
import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
|
|
4
|
+
import { CustomElementFor } from '../../tests/component-registry'
|
|
5
|
+
import { type IPktSelect, type TSelectOption } from './select'
|
|
6
|
+
import './select'
|
|
7
|
+
|
|
8
|
+
export interface SelectTestConfig extends Partial<IPktSelect>, BaseTestConfig {
|
|
9
|
+
id?: string
|
|
10
|
+
label?: string
|
|
11
|
+
disabled?: boolean
|
|
12
|
+
required?: boolean
|
|
13
|
+
hasError?: boolean
|
|
14
|
+
errorMessage?: string
|
|
15
|
+
helptext?: string
|
|
16
|
+
fullwidth?: boolean
|
|
17
|
+
ariaLabelledby?: string | null
|
|
18
|
+
ariaDescribedBy?: string | null
|
|
19
|
+
counter?: boolean
|
|
20
|
+
inline?: boolean
|
|
21
|
+
useWrapper?: boolean | string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const createSelectTest = async (config: SelectTestConfig = {}) => {
|
|
25
|
+
const { options, ...htmlConfig } = config
|
|
26
|
+
|
|
27
|
+
const { container, element } = await createElementTest<
|
|
28
|
+
CustomElementFor<'pkt-select'>,
|
|
29
|
+
Omit<SelectTestConfig, 'options'>
|
|
30
|
+
>('pkt-select', htmlConfig)
|
|
31
|
+
|
|
32
|
+
if (options) {
|
|
33
|
+
element.options = options
|
|
34
|
+
await element.updateComplete
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
container,
|
|
39
|
+
select: element,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
expect.extend(toHaveNoViolations)
|
|
44
|
+
|
|
45
|
+
describe('pkt-select', () => {
|
|
46
|
+
afterEach(() => {
|
|
47
|
+
document.body.innerHTML = ''
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('renders with basic properties', async () => {
|
|
51
|
+
const { select } = await createSelectTest({
|
|
52
|
+
label: 'Test Select',
|
|
53
|
+
id: 'test-select',
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
expect(select).toBeInTheDocument()
|
|
57
|
+
expect(select.getAttribute('id')).toBe('test-select')
|
|
58
|
+
expect(select.label).toBe('Test Select')
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('displays correct label in input wrapper', async () => {
|
|
62
|
+
const { select } = await createSelectTest({
|
|
63
|
+
label: 'Choose Option',
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const inputWrapper = select.querySelector('pkt-input-wrapper')
|
|
67
|
+
expect(inputWrapper).toBeInTheDocument()
|
|
68
|
+
expect(inputWrapper?.getAttribute('label')).toBe('Choose Option')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('renders select element with correct attributes', async () => {
|
|
72
|
+
const { select } = await createSelectTest({
|
|
73
|
+
id: 'my-select',
|
|
74
|
+
disabled: true,
|
|
75
|
+
value: 'option2',
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
const selectElement = select.querySelector('select')
|
|
79
|
+
expect(selectElement).toBeInTheDocument()
|
|
80
|
+
expect(selectElement?.getAttribute('id')).toBe('my-select-input')
|
|
81
|
+
expect(selectElement?.hasAttribute('disabled')).toBe(true)
|
|
82
|
+
expect(selectElement?.getAttribute('value')).toBe('option2')
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
test('handles options array property', async () => {
|
|
86
|
+
const options: TSelectOption[] = [
|
|
87
|
+
{ value: '1', label: 'Option 1' },
|
|
88
|
+
{ value: '2', label: 'Option 2' },
|
|
89
|
+
{ value: '3', label: 'Option 3', disabled: true },
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
const { select } = await createSelectTest({ options })
|
|
93
|
+
|
|
94
|
+
const optionElements = select.querySelectorAll('option')
|
|
95
|
+
expect(optionElements).toHaveLength(3)
|
|
96
|
+
|
|
97
|
+
expect(optionElements[0].value).toBe('1')
|
|
98
|
+
expect(optionElements[0].textContent?.trim()).toBe('Option 1')
|
|
99
|
+
|
|
100
|
+
expect(optionElements[2].hasAttribute('disabled')).toBe(true)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test('updates value on selection', async () => {
|
|
104
|
+
const options: TSelectOption[] = [
|
|
105
|
+
{ value: 'a', label: 'Option A' },
|
|
106
|
+
{ value: 'b', label: 'Option B' },
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
const { select } = await createSelectTest({ options })
|
|
110
|
+
|
|
111
|
+
const selectElement = select.querySelector('select') as HTMLSelectElement
|
|
112
|
+
|
|
113
|
+
expect(selectElement.options.length).toBe(2)
|
|
114
|
+
expect(selectElement.options[0].value).toBe('a')
|
|
115
|
+
expect(selectElement.options[1].value).toBe('b')
|
|
116
|
+
|
|
117
|
+
expect(select.value).toBe('a')
|
|
118
|
+
|
|
119
|
+
selectElement.selectedIndex = 1
|
|
120
|
+
selectElement.dispatchEvent(new Event('change', { bubbles: true }))
|
|
121
|
+
await select.updateComplete
|
|
122
|
+
|
|
123
|
+
expect(select.value).toBe('b')
|
|
124
|
+
expect(select.touched).toBe(true)
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
test('handles error state correctly', async () => {
|
|
128
|
+
const { select } = await createSelectTest({
|
|
129
|
+
hasError: true,
|
|
130
|
+
errorMessage: 'Selection required',
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
const inputWrapper = select.querySelector('pkt-input-wrapper')
|
|
134
|
+
expect(inputWrapper?.hasAttribute('hasError')).toBe(true)
|
|
135
|
+
expect(inputWrapper?.getAttribute('errorMessage')).toBe('Selection required')
|
|
136
|
+
|
|
137
|
+
const selectElement = select.querySelector('select')
|
|
138
|
+
expect(selectElement?.getAttribute('aria-invalid')).toBe('true')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
test('renders helptext when provided', async () => {
|
|
142
|
+
const { select } = await createSelectTest({
|
|
143
|
+
helptext: 'Choose your preferred option',
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
const inputWrapper = select.querySelector('pkt-input-wrapper')
|
|
147
|
+
expect(inputWrapper?.getAttribute('helptext')).toBe('Choose your preferred option')
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
test('handles fullwidth styling', async () => {
|
|
151
|
+
const { select } = await createSelectTest({
|
|
152
|
+
fullwidth: true,
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
const selectElement = select.querySelector('select')
|
|
156
|
+
expect(selectElement?.className).toContain('pkt-input--fullwidth')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
test('manages focus events correctly', async () => {
|
|
160
|
+
const { select } = await createSelectTest()
|
|
161
|
+
|
|
162
|
+
const focusSpy = jest.spyOn(select, 'onFocus')
|
|
163
|
+
const blurSpy = jest.spyOn(select, 'onBlur')
|
|
164
|
+
|
|
165
|
+
const selectElement = select.querySelector('select') as HTMLSelectElement
|
|
166
|
+
|
|
167
|
+
selectElement.dispatchEvent(new FocusEvent('focus'))
|
|
168
|
+
expect(focusSpy).toHaveBeenCalled()
|
|
169
|
+
|
|
170
|
+
selectElement.dispatchEvent(new FocusEvent('blur'))
|
|
171
|
+
expect(blurSpy).toHaveBeenCalled()
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
test('passes through accessibility attributes', async () => {
|
|
175
|
+
const { select } = await createSelectTest({
|
|
176
|
+
ariaLabelledby: 'external-label',
|
|
177
|
+
ariaDescribedBy: 'external-description',
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
const selectElement = select.querySelector('select')
|
|
181
|
+
expect(selectElement?.getAttribute('aria-labelledby')).toBe('external-label')
|
|
182
|
+
|
|
183
|
+
const inputWrapper = select.querySelector('pkt-input-wrapper')
|
|
184
|
+
expect(inputWrapper?.getAttribute('ariaDescribedBy')).toBe('external-description')
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
test('handles input wrapper properties', async () => {
|
|
188
|
+
const { select } = await createSelectTest({
|
|
189
|
+
counter: true,
|
|
190
|
+
inline: true,
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
const inputWrapper = select.querySelector('pkt-input-wrapper')
|
|
194
|
+
expect(inputWrapper?.hasAttribute('counter')).toBe(true)
|
|
195
|
+
expect(inputWrapper?.hasAttribute('inline')).toBe(true)
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
test('handles useWrapper false', async () => {
|
|
199
|
+
const { select } = await createSelectTest()
|
|
200
|
+
|
|
201
|
+
// Set useWrapper property directly on the element
|
|
202
|
+
select.useWrapper = false
|
|
203
|
+
await select.updateComplete
|
|
204
|
+
|
|
205
|
+
// When useWrapper is false, verify the behavior
|
|
206
|
+
expect(select.useWrapper).toBe(false)
|
|
207
|
+
|
|
208
|
+
// Confirm that there's a label with class pkt-sr-only in the markup
|
|
209
|
+
const srOnlyLabel = select.querySelector('label.pkt-sr-only')
|
|
210
|
+
expect(srOnlyLabel).toBeInTheDocument()
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
test('meets accessibility standards', async () => {
|
|
214
|
+
const options: TSelectOption[] = [
|
|
215
|
+
{ value: '1', label: 'Option 1' },
|
|
216
|
+
{ value: '2', label: 'Option 2' },
|
|
217
|
+
]
|
|
218
|
+
|
|
219
|
+
const { select } = await createSelectTest({
|
|
220
|
+
label: 'Accessible Select',
|
|
221
|
+
options,
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
const results = await axe(select)
|
|
225
|
+
expect(results).toHaveNoViolations()
|
|
226
|
+
})
|
|
227
|
+
})
|
|
@@ -150,6 +150,16 @@ export class PktSelect extends PktInputElement implements IPktSelect {
|
|
|
150
150
|
|
|
151
151
|
update(changedProperties: PropertyValues) {
|
|
152
152
|
super.update(changedProperties)
|
|
153
|
+
if (changedProperties.has('options')) {
|
|
154
|
+
this._options = this.options
|
|
155
|
+
this.requestUpdate('_options')
|
|
156
|
+
|
|
157
|
+
// If no value is set and we have options, set to first option
|
|
158
|
+
if (!this.value && this._options.length > 0) {
|
|
159
|
+
this.value = this._options[0].value
|
|
160
|
+
this.selectedIndex = 0
|
|
161
|
+
}
|
|
162
|
+
}
|
|
153
163
|
if (changedProperties.has('value') && this.value !== changedProperties.get('value')) {
|
|
154
164
|
this.selectedIndex = this.touched
|
|
155
165
|
? this.returnNumberOrNull(this.inputRef.value?.selectedIndex)
|
|
@@ -230,18 +240,19 @@ export class PktSelect extends PktInputElement implements IPktSelect {
|
|
|
230
240
|
}}
|
|
231
241
|
${ref(this.inputRef)}
|
|
232
242
|
>
|
|
233
|
-
${this._options.length > 0
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
243
|
+
${this._options.length > 0
|
|
244
|
+
? this._options.map(
|
|
245
|
+
(option) =>
|
|
246
|
+
html`<option
|
|
247
|
+
value=${option.value}
|
|
248
|
+
?selected=${this.value == option.value || option.selected}
|
|
249
|
+
?disabled=${option.disabled}
|
|
250
|
+
?hidden=${option.hidden}
|
|
251
|
+
>
|
|
252
|
+
${option.label}
|
|
253
|
+
</option>`,
|
|
254
|
+
)
|
|
255
|
+
: ''}
|
|
245
256
|
</select>
|
|
246
257
|
<div class="pkt-contents" ${ref(this.helptextSlot)} name="helptext" slot="helptext"></div>
|
|
247
258
|
</pkt-input-wrapper>
|