@oslokommune/punkt-elements 13.5.2 → 13.5.3
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 +17 -0
- package/dist/{alert-DQNBDKjT.cjs → alert-7rUOhlNi.cjs} +2 -1
- package/dist/{alert-B07oUpkq.js → alert-cUBtwi2k.js} +12 -11
- package/dist/pkt-alert.cjs +1 -1
- package/dist/pkt-alert.js +1 -1
- package/dist/pkt-index.cjs +1 -1
- package/dist/pkt-index.js +1 -1
- package/package.json +6 -2
- package/src/components/alert/alert.test.ts +64 -79
- package/src/components/alert/alert.ts +1 -0
- package/src/components/backlink/backlink.test.ts +50 -96
- package/src/components/button/button.test.ts +211 -249
- package/src/components/calendar/calendar.accessibility.test.ts +30 -43
- package/src/components/card/card.test.ts +71 -121
- package/src/components/checkbox/checkbox.test.ts +231 -156
- package/src/components/consent/consent.test.ts +87 -91
- package/src/components/icon/icon.test.ts +368 -0
- package/src/components/input-wrapper/input-wrapper.test.ts +505 -0
- package/src/components/link/link.test.ts +224 -0
- package/src/components/linkcard/linkcard.test.ts +14 -12
|
@@ -1,30 +1,39 @@
|
|
|
1
1
|
import '@testing-library/jest-dom'
|
|
2
2
|
import { axe, toHaveNoViolations } from 'jest-axe'
|
|
3
3
|
import { fireEvent } from '@testing-library/dom'
|
|
4
|
+
import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
|
|
5
|
+
import { CustomElementFor } from '../../tests/component-registry'
|
|
6
|
+
import './button'
|
|
4
7
|
|
|
5
8
|
expect.extend(toHaveNoViolations)
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
export interface ButtonTestConfig extends BaseTestConfig {
|
|
11
|
+
size?: string
|
|
12
|
+
skin?: string
|
|
13
|
+
variant?: string
|
|
14
|
+
color?: string
|
|
15
|
+
type?: string
|
|
16
|
+
disabled?: boolean
|
|
17
|
+
isLoading?: boolean
|
|
18
|
+
iconName?: string
|
|
19
|
+
iconNameSecond?: string
|
|
20
|
+
iconPosition?: string
|
|
21
|
+
mode?: string
|
|
22
|
+
form?: string
|
|
23
|
+
content?: string
|
|
15
24
|
}
|
|
16
25
|
|
|
17
|
-
//
|
|
18
|
-
const
|
|
19
|
-
const container =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
// Use shared framework
|
|
27
|
+
export const createButtonTest = async (config: ButtonTestConfig = {}) => {
|
|
28
|
+
const { container, element } = await createElementTest<
|
|
29
|
+
CustomElementFor<'pkt-button'>,
|
|
30
|
+
ButtonTestConfig
|
|
31
|
+
>('pkt-button', config)
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
container,
|
|
35
|
+
button: element,
|
|
36
|
+
}
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
// Cleanup after each test
|
|
@@ -35,41 +44,36 @@ afterEach(() => {
|
|
|
35
44
|
describe('PktButton', () => {
|
|
36
45
|
describe('Rendering and basic functionality', () => {
|
|
37
46
|
test('renders without errors', async () => {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
41
|
-
expect(pktButton).toBeInTheDocument()
|
|
47
|
+
const { button } = await createButtonTest({ content: 'Test Button' })
|
|
42
48
|
|
|
43
|
-
await pktButton.updateComplete
|
|
44
|
-
expect(pktButton).toBeTruthy()
|
|
45
|
-
|
|
46
|
-
const button = pktButton.querySelector('button')
|
|
47
49
|
expect(button).toBeInTheDocument()
|
|
50
|
+
expect(button).toBeTruthy()
|
|
51
|
+
|
|
52
|
+
const nativeButton = button.querySelector('button')
|
|
53
|
+
expect(nativeButton).toBeInTheDocument()
|
|
48
54
|
})
|
|
49
55
|
|
|
50
56
|
test('renders with correct structure', async () => {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
const { button } = await createButtonTest({
|
|
58
|
+
variant: 'icon-left',
|
|
59
|
+
iconName: 'user',
|
|
60
|
+
content: 'Click Me',
|
|
61
|
+
})
|
|
55
62
|
|
|
56
|
-
const
|
|
57
|
-
const icon =
|
|
58
|
-
const textSpan =
|
|
63
|
+
const nativeButton = button.querySelector('button')
|
|
64
|
+
const icon = nativeButton?.querySelector('pkt-icon')
|
|
65
|
+
const textSpan = nativeButton?.querySelector('.pkt-btn__text')
|
|
59
66
|
|
|
60
|
-
expect(
|
|
67
|
+
expect(nativeButton).toHaveClass('pkt-btn')
|
|
61
68
|
expect(icon).toHaveClass('pkt-btn__icon')
|
|
62
69
|
expect(textSpan).toHaveClass('pkt-btn__text')
|
|
63
70
|
expect(textSpan?.textContent?.trim()).toContain('Click Me')
|
|
64
71
|
})
|
|
65
72
|
|
|
66
73
|
test('renders text correctly', async () => {
|
|
67
|
-
const
|
|
74
|
+
const { button } = await createButtonTest({ content: 'Button Text Content' })
|
|
68
75
|
|
|
69
|
-
const
|
|
70
|
-
await pktButton.updateComplete
|
|
71
|
-
|
|
72
|
-
const textSpan = pktButton.querySelector('.pkt-btn__text')
|
|
76
|
+
const textSpan = button.querySelector('.pkt-btn__text')
|
|
73
77
|
expect(textSpan).toBeInTheDocument()
|
|
74
78
|
expect(textSpan?.textContent?.trim()).toContain('Button Text Content')
|
|
75
79
|
})
|
|
@@ -77,41 +81,35 @@ describe('PktButton', () => {
|
|
|
77
81
|
|
|
78
82
|
describe('Properties and attributes', () => {
|
|
79
83
|
test('applies default properties correctly', async () => {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
expect(
|
|
86
|
-
expect(
|
|
87
|
-
expect(
|
|
88
|
-
expect(
|
|
89
|
-
expect(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
expect(
|
|
95
|
-
expect(
|
|
96
|
-
expect(button).toHaveClass('pkt-btn--primary')
|
|
97
|
-
expect(button).toHaveClass('pkt-btn--label-only')
|
|
84
|
+
const { button } = await createButtonTest({ content: 'Test Button' })
|
|
85
|
+
await button.updateComplete
|
|
86
|
+
|
|
87
|
+
expect(button.size).toBe('medium')
|
|
88
|
+
expect(button.skin).toBe('primary')
|
|
89
|
+
expect(button.variant).toBe('label-only')
|
|
90
|
+
expect(button.type).toBe('button')
|
|
91
|
+
expect(button.mode).toBe('light')
|
|
92
|
+
expect(button.disabled).toBe(false)
|
|
93
|
+
expect(button.isLoading).toBe(false)
|
|
94
|
+
|
|
95
|
+
const buttonEl = button.querySelector('button')
|
|
96
|
+
expect(buttonEl).toHaveClass('pkt-btn')
|
|
97
|
+
expect(buttonEl).toHaveClass('pkt-btn--medium')
|
|
98
|
+
expect(buttonEl).toHaveClass('pkt-btn--primary')
|
|
99
|
+
expect(buttonEl).toHaveClass('pkt-btn--label-only')
|
|
98
100
|
})
|
|
99
101
|
|
|
100
102
|
test('applies different size properties correctly', async () => {
|
|
101
103
|
const sizes = ['small', 'medium', 'large'] as const
|
|
102
104
|
|
|
103
105
|
for (const size of sizes) {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
await pktButton.updateComplete
|
|
107
|
-
|
|
108
|
-
expect(pktButton.size).toBe(size)
|
|
106
|
+
const { button } = await createButtonTest({ size, content: 'Test Button' })
|
|
107
|
+
await button.updateComplete
|
|
109
108
|
|
|
110
|
-
|
|
111
|
-
expect(button).toHaveClass(`pkt-btn--${size}`)
|
|
109
|
+
expect(button.size).toBe(size)
|
|
112
110
|
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
const buttonEl = button.querySelector('button')
|
|
112
|
+
expect(buttonEl).toHaveClass(`pkt-btn--${size}`)
|
|
115
113
|
}
|
|
116
114
|
})
|
|
117
115
|
|
|
@@ -119,17 +117,13 @@ describe('PktButton', () => {
|
|
|
119
117
|
const skins = ['primary', 'secondary', 'tertiary'] as const
|
|
120
118
|
|
|
121
119
|
for (const skin of skins) {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
await pktButton.updateComplete
|
|
120
|
+
const { button } = await createButtonTest({ skin, content: 'Test Button' })
|
|
121
|
+
await button.updateComplete
|
|
125
122
|
|
|
126
|
-
expect(
|
|
123
|
+
expect(button.skin).toBe(skin)
|
|
127
124
|
|
|
128
|
-
const
|
|
129
|
-
expect(
|
|
130
|
-
|
|
131
|
-
// Cleanup for next iteration
|
|
132
|
-
container.remove()
|
|
125
|
+
const buttonEl = button.querySelector('button')
|
|
126
|
+
expect(buttonEl).toHaveClass(`pkt-btn--${skin}`)
|
|
133
127
|
}
|
|
134
128
|
})
|
|
135
129
|
|
|
@@ -143,19 +137,21 @@ describe('PktButton', () => {
|
|
|
143
137
|
] as const
|
|
144
138
|
|
|
145
139
|
for (const variant of variants) {
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
140
|
+
const { button } = await createButtonTest({
|
|
141
|
+
variant,
|
|
142
|
+
iconName: 'user',
|
|
143
|
+
iconNameSecond: 'star',
|
|
144
|
+
content: 'Test Button',
|
|
145
|
+
})
|
|
146
|
+
await button.updateComplete
|
|
151
147
|
|
|
152
|
-
expect(
|
|
148
|
+
expect(button.variant).toBe(variant)
|
|
153
149
|
|
|
154
|
-
const
|
|
155
|
-
expect(
|
|
150
|
+
const buttonEl = button.querySelector('button')
|
|
151
|
+
expect(buttonEl).toHaveClass(`pkt-btn--${variant}`)
|
|
156
152
|
|
|
157
153
|
// Check icon rendering based on variant
|
|
158
|
-
const icons =
|
|
154
|
+
const icons = buttonEl?.querySelectorAll('pkt-icon:not(.pkt-btn__spinner)')
|
|
159
155
|
if (variant === 'label-only') {
|
|
160
156
|
expect(icons).toHaveLength(0)
|
|
161
157
|
} else if (variant === 'icons-right-and-left') {
|
|
@@ -163,9 +159,6 @@ describe('PktButton', () => {
|
|
|
163
159
|
} else {
|
|
164
160
|
expect(icons).toHaveLength(1)
|
|
165
161
|
}
|
|
166
|
-
|
|
167
|
-
// Cleanup for next iteration
|
|
168
|
-
container.remove()
|
|
169
162
|
}
|
|
170
163
|
})
|
|
171
164
|
|
|
@@ -173,17 +166,13 @@ describe('PktButton', () => {
|
|
|
173
166
|
const colors = ['blue', 'green', 'red', 'yellow'] as const
|
|
174
167
|
|
|
175
168
|
for (const color of colors) {
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
await pktButton.updateComplete
|
|
169
|
+
const { button } = await createButtonTest({ color, content: 'Test Button' })
|
|
170
|
+
await button.updateComplete
|
|
179
171
|
|
|
180
|
-
expect(
|
|
172
|
+
expect(button.color).toBe(color)
|
|
181
173
|
|
|
182
|
-
const
|
|
183
|
-
expect(
|
|
184
|
-
|
|
185
|
-
// Cleanup for next iteration
|
|
186
|
-
container.remove()
|
|
174
|
+
const buttonEl = button.querySelector('button')
|
|
175
|
+
expect(buttonEl).toHaveClass(`pkt-btn--${color}`)
|
|
187
176
|
}
|
|
188
177
|
})
|
|
189
178
|
|
|
@@ -191,46 +180,46 @@ describe('PktButton', () => {
|
|
|
191
180
|
const types = ['button', 'submit', 'reset'] as const
|
|
192
181
|
|
|
193
182
|
for (const type of types) {
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
await pktButton.updateComplete
|
|
197
|
-
|
|
198
|
-
expect(pktButton.type).toBe(type)
|
|
183
|
+
const { button } = await createButtonTest({ type, content: 'Test Button' })
|
|
184
|
+
await button.updateComplete
|
|
199
185
|
|
|
200
|
-
|
|
201
|
-
expect(button?.getAttribute('type')).toBe(type)
|
|
186
|
+
expect(button.type).toBe(type)
|
|
202
187
|
|
|
203
|
-
|
|
204
|
-
|
|
188
|
+
const buttonEl = button.querySelector('button')
|
|
189
|
+
expect(buttonEl?.getAttribute('type')).toBe(type)
|
|
205
190
|
}
|
|
206
191
|
})
|
|
207
192
|
|
|
208
193
|
test('handles icon properties correctly', async () => {
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
194
|
+
const { button } = await createButtonTest({
|
|
195
|
+
variant: 'icon-left',
|
|
196
|
+
iconName: 'user',
|
|
197
|
+
content: 'Test Button',
|
|
198
|
+
})
|
|
199
|
+
await button.updateComplete
|
|
213
200
|
|
|
214
|
-
expect(
|
|
201
|
+
expect(button.iconName).toBe('user')
|
|
215
202
|
|
|
216
|
-
const icon =
|
|
203
|
+
const icon = button.querySelector('pkt-icon:not(.pkt-btn__spinner)')
|
|
217
204
|
expect(icon?.getAttribute('name')).toBe('user')
|
|
218
205
|
expect(icon).toHaveClass('pkt-btn__icon')
|
|
219
206
|
})
|
|
220
207
|
|
|
221
208
|
test('handles second icon for icons-right-and-left variant', async () => {
|
|
222
|
-
const
|
|
223
|
-
|
|
209
|
+
const { button } = await createButtonTest({
|
|
210
|
+
variant: 'icons-right-and-left',
|
|
211
|
+
content: 'Test Button',
|
|
212
|
+
})
|
|
224
213
|
|
|
225
214
|
// Set both icon names as properties
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
await
|
|
215
|
+
button.iconName = 'home'
|
|
216
|
+
button.secondIconName = 'star'
|
|
217
|
+
await button.updateComplete
|
|
229
218
|
|
|
230
|
-
expect(
|
|
231
|
-
expect(
|
|
219
|
+
expect(button.iconName).toBe('home')
|
|
220
|
+
expect(button.secondIconName).toBe('star')
|
|
232
221
|
|
|
233
|
-
const icons =
|
|
222
|
+
const icons = button.querySelectorAll('pkt-icon:not(.pkt-btn__spinner)')
|
|
234
223
|
expect(icons).toHaveLength(2)
|
|
235
224
|
expect(icons[0]?.getAttribute('name')).toBe('home')
|
|
236
225
|
expect(icons[1]?.getAttribute('name')).toBe('star')
|
|
@@ -239,190 +228,175 @@ describe('PktButton', () => {
|
|
|
239
228
|
|
|
240
229
|
describe('Disabled state', () => {
|
|
241
230
|
test('handles disabled property correctly', async () => {
|
|
242
|
-
const
|
|
231
|
+
const { button } = await createButtonTest({ disabled: true, content: 'Test Button' })
|
|
232
|
+
await button.updateComplete
|
|
243
233
|
|
|
244
|
-
|
|
245
|
-
await pktButton.updateComplete
|
|
234
|
+
expect(button.disabled).toBe(true)
|
|
246
235
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
expect(
|
|
251
|
-
expect(button?.hasAttribute('disabled')).toBe(true)
|
|
252
|
-
expect(button?.getAttribute('aria-disabled')).toBe('true')
|
|
236
|
+
const buttonEl = button.querySelector('button')
|
|
237
|
+
expect(buttonEl).toHaveClass('pkt-btn--disabled')
|
|
238
|
+
expect(buttonEl?.hasAttribute('disabled')).toBe(true)
|
|
239
|
+
expect(buttonEl?.getAttribute('aria-disabled')).toBe('true')
|
|
253
240
|
})
|
|
254
241
|
|
|
255
242
|
test('prevents click events when disabled', async () => {
|
|
256
|
-
const
|
|
243
|
+
const { button } = await createButtonTest({ disabled: true, content: 'Test Button' })
|
|
257
244
|
const clickSpy = jest.fn()
|
|
258
245
|
|
|
259
|
-
|
|
260
|
-
await pktButton.updateComplete
|
|
246
|
+
await button.updateComplete
|
|
261
247
|
|
|
262
|
-
|
|
248
|
+
button.addEventListener('click', clickSpy)
|
|
263
249
|
|
|
264
|
-
const
|
|
265
|
-
fireEvent.click(
|
|
250
|
+
const buttonEl = button.querySelector('button')
|
|
251
|
+
fireEvent.click(buttonEl!)
|
|
266
252
|
|
|
267
253
|
expect(clickSpy).not.toHaveBeenCalled()
|
|
268
254
|
})
|
|
269
255
|
|
|
270
256
|
test('prevents keyboard events when disabled', async () => {
|
|
271
|
-
const
|
|
257
|
+
const { button } = await createButtonTest({ disabled: true, content: 'Test Button' })
|
|
272
258
|
const clickSpy = jest.fn()
|
|
273
259
|
|
|
274
|
-
|
|
275
|
-
await pktButton.updateComplete
|
|
260
|
+
await button.updateComplete
|
|
276
261
|
|
|
277
|
-
|
|
262
|
+
button.addEventListener('click', clickSpy)
|
|
278
263
|
|
|
279
|
-
const
|
|
280
|
-
fireEvent.keyDown(
|
|
281
|
-
fireEvent.keyDown(
|
|
264
|
+
const buttonEl = button.querySelector('button')
|
|
265
|
+
fireEvent.keyDown(buttonEl!, { key: 'Enter' })
|
|
266
|
+
fireEvent.keyDown(buttonEl!, { key: ' ' })
|
|
282
267
|
|
|
283
268
|
expect(clickSpy).not.toHaveBeenCalled()
|
|
284
269
|
})
|
|
285
270
|
|
|
286
271
|
test('converts string "false" to boolean false for disabled', async () => {
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
290
|
-
await pktButton.updateComplete
|
|
272
|
+
const { button } = await createButtonTest({ disabled: false, content: 'Test Button' })
|
|
273
|
+
await button.updateComplete
|
|
291
274
|
|
|
292
|
-
expect(
|
|
275
|
+
expect(button.disabled).toBe(false)
|
|
293
276
|
|
|
294
|
-
const
|
|
295
|
-
expect(
|
|
296
|
-
expect(
|
|
277
|
+
const buttonEl = button.querySelector('button')
|
|
278
|
+
expect(buttonEl).not.toHaveClass('pkt-btn--disabled')
|
|
279
|
+
expect(buttonEl?.hasAttribute('disabled')).toBe(false)
|
|
297
280
|
})
|
|
298
281
|
})
|
|
299
282
|
|
|
300
283
|
describe('Loading state', () => {
|
|
301
284
|
test('handles isLoading property correctly', async () => {
|
|
302
|
-
const
|
|
303
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
285
|
+
const { button } = await createButtonTest({ content: 'Test Button' })
|
|
304
286
|
|
|
305
287
|
// Set isLoading as a property
|
|
306
|
-
|
|
307
|
-
await
|
|
288
|
+
button.isLoading = true
|
|
289
|
+
await button.updateComplete
|
|
308
290
|
|
|
309
|
-
expect(
|
|
291
|
+
expect(button.isLoading).toBe(true)
|
|
310
292
|
|
|
311
|
-
const
|
|
312
|
-
expect(
|
|
313
|
-
expect(
|
|
314
|
-
expect(
|
|
293
|
+
const buttonEl = button.querySelector('button')
|
|
294
|
+
expect(buttonEl).toHaveClass('pkt-btn--isLoading')
|
|
295
|
+
expect(buttonEl?.getAttribute('aria-busy')).toBe('true')
|
|
296
|
+
expect(buttonEl?.getAttribute('aria-disabled')).toBe('true')
|
|
315
297
|
})
|
|
316
298
|
|
|
317
299
|
test('renders loading spinner when isLoading is true', async () => {
|
|
318
|
-
const
|
|
319
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
300
|
+
const { button } = await createButtonTest({ content: 'Test Button' })
|
|
320
301
|
|
|
321
302
|
// Set isLoading as a property
|
|
322
|
-
|
|
323
|
-
await
|
|
303
|
+
button.isLoading = true
|
|
304
|
+
await button.updateComplete
|
|
324
305
|
|
|
325
|
-
const spinner =
|
|
306
|
+
const spinner = button.querySelector('.pkt-btn__spinner')
|
|
326
307
|
expect(spinner).toBeInTheDocument()
|
|
327
308
|
expect(spinner?.getAttribute('name')).toBe('spinner-blue')
|
|
328
309
|
})
|
|
329
310
|
|
|
330
311
|
test('prevents click events when loading', async () => {
|
|
331
|
-
const
|
|
312
|
+
const { button } = await createButtonTest({ content: 'Test Button' })
|
|
332
313
|
const clickSpy = jest.fn()
|
|
333
314
|
|
|
334
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
335
|
-
|
|
336
315
|
// Set isLoading as a property
|
|
337
|
-
|
|
338
|
-
await
|
|
316
|
+
button.isLoading = true
|
|
317
|
+
await button.updateComplete
|
|
339
318
|
|
|
340
|
-
|
|
319
|
+
button.addEventListener('click', clickSpy)
|
|
341
320
|
|
|
342
|
-
const
|
|
343
|
-
fireEvent.click(
|
|
321
|
+
const buttonEl = button.querySelector('button')
|
|
322
|
+
fireEvent.click(buttonEl!)
|
|
344
323
|
|
|
345
324
|
expect(clickSpy).not.toHaveBeenCalled()
|
|
346
325
|
})
|
|
347
326
|
|
|
348
327
|
test('uses custom loading animation path', async () => {
|
|
349
328
|
const customPath = 'https://custom.example.com/animations/'
|
|
350
|
-
const
|
|
351
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
329
|
+
const { button } = await createButtonTest({ isLoading: true, content: 'Test Button' })
|
|
352
330
|
|
|
353
|
-
|
|
354
|
-
await
|
|
331
|
+
button.loadingAnimationPath = customPath
|
|
332
|
+
await button.updateComplete
|
|
355
333
|
|
|
356
|
-
expect(
|
|
334
|
+
expect(button.loadingAnimationPath).toBe(customPath)
|
|
357
335
|
|
|
358
|
-
const spinner =
|
|
336
|
+
const spinner = button.querySelector('.pkt-btn__spinner')
|
|
359
337
|
expect(spinner?.getAttribute('path')).toBe(customPath)
|
|
360
338
|
})
|
|
361
339
|
|
|
362
340
|
test('converts string "false" to boolean false for isLoading', async () => {
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
366
|
-
await pktButton.updateComplete
|
|
341
|
+
const { button } = await createButtonTest({ isLoading: false, content: 'Test Button' })
|
|
342
|
+
await button.updateComplete
|
|
367
343
|
|
|
368
|
-
expect(
|
|
344
|
+
expect(button.isLoading).toBe(false)
|
|
369
345
|
|
|
370
|
-
const
|
|
371
|
-
expect(
|
|
346
|
+
const buttonEl = button.querySelector('button')
|
|
347
|
+
expect(buttonEl).not.toHaveClass('pkt-btn--isLoading')
|
|
372
348
|
})
|
|
373
349
|
})
|
|
374
350
|
|
|
375
351
|
describe('Form integration', () => {
|
|
376
352
|
test('handles form attribute correctly', async () => {
|
|
377
|
-
const
|
|
353
|
+
const { button } = await createButtonTest({
|
|
354
|
+
form: 'test-form',
|
|
355
|
+
type: 'submit',
|
|
356
|
+
content: 'Test Button',
|
|
357
|
+
})
|
|
358
|
+
await button.updateComplete
|
|
378
359
|
|
|
379
|
-
|
|
380
|
-
await pktButton.updateComplete
|
|
360
|
+
expect(button.form).toBe('test-form')
|
|
381
361
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
const button = pktButton.querySelector('button')
|
|
385
|
-
expect(button?.getAttribute('form')).toBe('test-form')
|
|
362
|
+
const buttonEl = button.querySelector('button')
|
|
363
|
+
expect(buttonEl?.getAttribute('form')).toBe('test-form')
|
|
386
364
|
})
|
|
387
365
|
|
|
388
366
|
test('works as submit button', async () => {
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
392
|
-
await pktButton.updateComplete
|
|
367
|
+
const { button } = await createButtonTest({ type: 'submit', content: 'Test Button' })
|
|
368
|
+
await button.updateComplete
|
|
393
369
|
|
|
394
|
-
const
|
|
395
|
-
expect(
|
|
370
|
+
const buttonEl = button.querySelector('button')
|
|
371
|
+
expect(buttonEl?.getAttribute('type')).toBe('submit')
|
|
396
372
|
})
|
|
397
373
|
})
|
|
398
374
|
|
|
399
375
|
describe('Click functionality', () => {
|
|
400
376
|
test('allows click events when not disabled or loading', async () => {
|
|
401
|
-
const
|
|
377
|
+
const { button } = await createButtonTest({ content: 'Test Button' })
|
|
402
378
|
const clickSpy = jest.fn()
|
|
403
379
|
|
|
404
|
-
|
|
405
|
-
await pktButton.updateComplete
|
|
380
|
+
await button.updateComplete
|
|
406
381
|
|
|
407
|
-
|
|
382
|
+
button.addEventListener('click', clickSpy)
|
|
408
383
|
|
|
409
|
-
const
|
|
410
|
-
fireEvent.click(
|
|
384
|
+
const buttonEl = button.querySelector('button')
|
|
385
|
+
fireEvent.click(buttonEl!)
|
|
411
386
|
|
|
412
387
|
expect(clickSpy).toHaveBeenCalledTimes(1)
|
|
413
388
|
})
|
|
414
389
|
|
|
415
390
|
test('allows keyboard activation when not disabled or loading', async () => {
|
|
416
|
-
const
|
|
391
|
+
const { button } = await createButtonTest({ content: 'Test Button' })
|
|
417
392
|
const clickSpy = jest.fn()
|
|
418
393
|
|
|
419
|
-
|
|
420
|
-
await pktButton.updateComplete
|
|
394
|
+
await button.updateComplete
|
|
421
395
|
|
|
422
|
-
|
|
396
|
+
button.addEventListener('click', clickSpy)
|
|
423
397
|
|
|
424
|
-
const
|
|
425
|
-
fireEvent.keyDown(
|
|
398
|
+
const buttonEl = button.querySelector('button')
|
|
399
|
+
fireEvent.keyDown(buttonEl!, { key: 'Enter' })
|
|
426
400
|
|
|
427
401
|
// Note: Native button handles Enter key, so we just test that events aren't prevented
|
|
428
402
|
// The actual click event would be triggered by the browser
|
|
@@ -431,81 +405,69 @@ describe('PktButton', () => {
|
|
|
431
405
|
|
|
432
406
|
describe('Accessibility', () => {
|
|
433
407
|
test('has correct ARIA attributes', async () => {
|
|
434
|
-
const
|
|
435
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
408
|
+
const { button } = await createButtonTest({ disabled: true, content: 'Test Button' })
|
|
436
409
|
|
|
437
410
|
// Set isLoading as a property
|
|
438
|
-
|
|
439
|
-
await
|
|
411
|
+
button.isLoading = true
|
|
412
|
+
await button.updateComplete
|
|
440
413
|
|
|
441
|
-
const
|
|
414
|
+
const buttonEl = button.querySelector('button')
|
|
442
415
|
|
|
443
|
-
expect(
|
|
444
|
-
expect(
|
|
445
|
-
expect(
|
|
416
|
+
expect(buttonEl?.getAttribute('aria-disabled')).toBe('true')
|
|
417
|
+
expect(buttonEl?.getAttribute('aria-busy')).toBe('true')
|
|
418
|
+
expect(buttonEl?.hasAttribute('disabled')).toBe(true)
|
|
446
419
|
})
|
|
447
420
|
|
|
448
421
|
test('provides semantic button structure', async () => {
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
452
|
-
await pktButton.updateComplete
|
|
422
|
+
const { button } = await createButtonTest({ content: 'Test Button' })
|
|
423
|
+
await button.updateComplete
|
|
453
424
|
|
|
454
|
-
const
|
|
425
|
+
const buttonEl = button.querySelector('button')
|
|
455
426
|
|
|
456
|
-
expect(
|
|
457
|
-
expect(
|
|
458
|
-
expect(
|
|
427
|
+
expect(buttonEl).toBeInTheDocument()
|
|
428
|
+
expect(buttonEl?.tagName.toLowerCase()).toBe('button')
|
|
429
|
+
expect(buttonEl?.getAttribute('type')).toBe('button')
|
|
459
430
|
})
|
|
460
431
|
|
|
461
432
|
test('renders with no WCAG errors with axe - default button', async () => {
|
|
462
|
-
const container = await
|
|
463
|
-
|
|
464
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
465
|
-
await pktButton.updateComplete
|
|
433
|
+
const { container } = await createButtonTest({ content: 'Click me' })
|
|
466
434
|
|
|
467
435
|
const results = await axe(container)
|
|
468
436
|
expect(results).toHaveNoViolations()
|
|
469
437
|
})
|
|
470
438
|
|
|
471
439
|
test('renders with no WCAG errors with axe - icon button', async () => {
|
|
472
|
-
const container = await
|
|
473
|
-
'
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
await pktButton.updateComplete
|
|
440
|
+
const { container } = await createButtonTest({
|
|
441
|
+
variant: 'icon-left',
|
|
442
|
+
iconName: 'user',
|
|
443
|
+
skin: 'secondary',
|
|
444
|
+
content: 'User Profile',
|
|
445
|
+
})
|
|
479
446
|
|
|
480
447
|
const results = await axe(container)
|
|
481
448
|
expect(results).toHaveNoViolations()
|
|
482
449
|
})
|
|
483
450
|
|
|
484
451
|
test('renders with no WCAG errors with axe - disabled button', async () => {
|
|
485
|
-
const container = await
|
|
486
|
-
|
|
487
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
488
|
-
await pktButton.updateComplete
|
|
452
|
+
const { container } = await createButtonTest({ disabled: true, content: 'Disabled Button' })
|
|
489
453
|
|
|
490
454
|
const results = await axe(container)
|
|
491
455
|
expect(results).toHaveNoViolations()
|
|
492
456
|
})
|
|
493
457
|
|
|
494
458
|
test('renders with no WCAG errors with axe - loading button', async () => {
|
|
495
|
-
const container = await
|
|
496
|
-
|
|
497
|
-
const pktButton = container.querySelector('pkt-button') as PktButton
|
|
498
|
-
await pktButton.updateComplete
|
|
459
|
+
const { container } = await createButtonTest({ isLoading: true, content: 'Loading...' })
|
|
499
460
|
|
|
500
461
|
const results = await axe(container)
|
|
501
462
|
expect(results).toHaveNoViolations()
|
|
502
463
|
})
|
|
503
464
|
|
|
504
465
|
test('renders with no WCAG errors with axe - submit button', async () => {
|
|
505
|
-
const container = await
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
466
|
+
const { container } = await createButtonTest({
|
|
467
|
+
type: 'submit',
|
|
468
|
+
color: 'green',
|
|
469
|
+
content: 'Submit Form',
|
|
470
|
+
})
|
|
509
471
|
|
|
510
472
|
const results = await axe(container)
|
|
511
473
|
expect(results).toHaveNoViolations()
|