@oslokommune/punkt-elements 13.5.5 → 13.5.9

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 CHANGED
@@ -5,6 +5,40 @@ og skriver commits ca etter [Conventional Commits](https://conventionalcommits.o
5
5
 
6
6
  ---
7
7
 
8
+ ## [13.5.9](https://github.com/oslokommune/punkt/compare/13.5.8...13.5.9) (2025-09-11)
9
+
10
+ ### ⚠ BREAKING CHANGES
11
+ Ingen
12
+
13
+ ### Features
14
+ Ingen
15
+
16
+ ### Bug Fixes
17
+ Ingen
18
+
19
+ ### Chores
20
+ Ingen
21
+
22
+ ---
23
+
24
+
25
+ ## [13.5.6](https://github.com/oslokommune/punkt/compare/13.5.5...13.5.6) (2025-09-09)
26
+
27
+ ### ⚠ BREAKING CHANGES
28
+ Ingen
29
+
30
+ ### Features
31
+ Ingen
32
+
33
+ ### Bug Fixes
34
+ Ingen
35
+
36
+ ### Chores
37
+ Ingen
38
+
39
+ ---
40
+
41
+
8
42
  ## [13.5.5](https://github.com/oslokommune/punkt/compare/13.5.4...13.5.5) (2025-09-09)
9
43
 
10
44
  ### ⚠ BREAKING CHANGES
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oslokommune/punkt-elements",
3
- "version": "13.5.5",
3
+ "version": "13.5.9",
4
4
  "description": "Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo",
5
5
  "homepage": "https://punkt.oslo.kommune.no",
6
6
  "author": "Team Designsystem, Oslo Origo",
@@ -19,14 +19,14 @@
19
19
  "build": "tsc && vite build",
20
20
  "build-app": "tsc && vite build --config vite.config-app.ts",
21
21
  "preview": "vite preview --outDir dist-app",
22
- "test": "jest --config jest.config.cjs"
22
+ "test": "vitest",
23
+ "test:run": "vitest run",
24
+ "test:ui": "vitest --ui"
23
25
  },
24
26
  "dependencies": {
25
27
  "@date-fns/tz": "^1.2.0",
26
28
  "@lit-labs/router": "^0.1.3",
27
- "@types/jest": "^29.5.14",
28
29
  "@types/node": "^20.17.30",
29
- "@types/testing-library__jest-dom": "^5.14.9",
30
30
  "date-fns": "^4.1.0",
31
31
  "dialog-polyfill": "^0.5.6",
32
32
  "lit": "^3.3.0",
@@ -43,15 +43,15 @@
43
43
  "@oslokommune/punkt-assets": "^13.3.1",
44
44
  "@oslokommune/punkt-css": "^13.5.0",
45
45
  "@testing-library/jest-dom": "^6.6.3",
46
- "jest": "^29.7.0",
46
+ "@vitest/ui": "^1.0.0",
47
47
  "jest-axe": "^9.0.0",
48
- "jest-environment-jsdom": "^29.7.0",
48
+ "jsdom": "^23.0.0",
49
49
  "sass": "^1.78.0",
50
- "ts-jest": "^29.2.6",
51
50
  "typescript": "^5.6.2",
52
51
  "vite": "^5.4.18",
53
52
  "vite-plugin-dts": "^4.2.1",
54
- "vite-plugin-web-components-hmr": "^0.1.3"
53
+ "vite-plugin-web-components-hmr": "^0.1.3",
54
+ "vitest": "^1.0.0"
55
55
  },
56
56
  "private": false,
57
57
  "publishConfig": {
@@ -73,5 +73,5 @@
73
73
  "url": "https://github.com/oslokommune/punkt/issues"
74
74
  },
75
75
  "license": "MIT",
76
- "gitHead": "f65d3c81c0543cc360a34fe346b4e0585deb46ac"
76
+ "gitHead": "92ee2058dae920d5ab968d8a1691f435a795e2ca"
77
77
  }
@@ -1,6 +1,7 @@
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 { vi } from 'vitest'
4
5
  import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
5
6
  import { CustomElementFor } from '../../tests/component-registry'
6
7
  import './alert'
@@ -215,8 +216,8 @@ describe('PktAlert', () => {
215
216
  await alert.updateComplete
216
217
 
217
218
  // Listen for close events
218
- const closeSpy = jest.fn()
219
- const onCloseSpy = jest.fn()
219
+ const closeSpy = vi.fn()
220
+ const onCloseSpy = vi.fn()
220
221
  alert.addEventListener('close', closeSpy)
221
222
  alert.addEventListener('on-close', onCloseSpy)
222
223
 
@@ -1,6 +1,7 @@
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 { vi } from 'vitest'
4
5
  import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
5
6
  import { CustomElementFor } from '../../tests/component-registry'
6
7
  import './button'
@@ -241,7 +242,7 @@ describe('PktButton', () => {
241
242
 
242
243
  test('prevents click events when disabled', async () => {
243
244
  const { button } = await createButtonTest({ disabled: true, content: 'Test Button' })
244
- const clickSpy = jest.fn()
245
+ const clickSpy = vi.fn()
245
246
 
246
247
  await button.updateComplete
247
248
 
@@ -255,7 +256,7 @@ describe('PktButton', () => {
255
256
 
256
257
  test('prevents keyboard events when disabled', async () => {
257
258
  const { button } = await createButtonTest({ disabled: true, content: 'Test Button' })
258
- const clickSpy = jest.fn()
259
+ const clickSpy = vi.fn()
259
260
 
260
261
  await button.updateComplete
261
262
 
@@ -310,7 +311,7 @@ describe('PktButton', () => {
310
311
 
311
312
  test('prevents click events when loading', async () => {
312
313
  const { button } = await createButtonTest({ content: 'Test Button' })
313
- const clickSpy = jest.fn()
314
+ const clickSpy = vi.fn()
314
315
 
315
316
  // Set isLoading as a property
316
317
  button.isLoading = true
@@ -375,7 +376,7 @@ describe('PktButton', () => {
375
376
  describe('Click functionality', () => {
376
377
  test('allows click events when not disabled or loading', async () => {
377
378
  const { button } = await createButtonTest({ content: 'Test Button' })
378
- const clickSpy = jest.fn()
379
+ const clickSpy = vi.fn()
379
380
 
380
381
  await button.updateComplete
381
382
 
@@ -389,7 +390,7 @@ describe('PktButton', () => {
389
390
 
390
391
  test('allows keyboard activation when not disabled or loading', async () => {
391
392
  const { button } = await createButtonTest({ content: 'Test Button' })
392
- const clickSpy = jest.fn()
393
+ const clickSpy = vi.fn()
393
394
 
394
395
  await button.updateComplete
395
396
 
@@ -1,5 +1,6 @@
1
1
  import '@testing-library/jest-dom'
2
2
  import { axe, toHaveNoViolations } from 'jest-axe'
3
+ import { vi } from 'vitest'
3
4
  import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
4
5
  import { CustomElementFor } from '../../tests/component-registry'
5
6
  import './card'
@@ -43,9 +44,9 @@ afterEach(() => {
43
44
  })
44
45
 
45
46
  // Global console.warn spy to suppress validation warnings in tests
46
- let consoleWarnSpy: jest.SpyInstance
47
+ let consoleWarnSpy: any
47
48
  beforeEach(() => {
48
- consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {})
49
+ consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
49
50
  })
50
51
 
51
52
  afterEach(() => {
@@ -151,7 +152,7 @@ describe('PktCard', () => {
151
152
  test('validates skin values and logs warnings for invalid skins', async () => {
152
153
  // Clear the global spy and create a new one for this specific test
153
154
  consoleWarnSpy.mockRestore()
154
- const localConsoleSpy = jest.spyOn(console, 'warn').mockImplementation(() => {})
155
+ const localConsoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
155
156
 
156
157
  const { card } = await createCardTest({ skin: 'zebra' })
157
158
  await card.updateComplete
@@ -166,7 +167,7 @@ describe('PktCard', () => {
166
167
 
167
168
  // Restore and recreate global spy for subsequent tests
168
169
  localConsoleSpy.mockRestore()
169
- consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {})
170
+ consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
170
171
  })
171
172
 
172
173
  test('applies different layout properties correctly', async () => {
@@ -1,6 +1,7 @@
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 { vi } from 'vitest'
4
5
 
5
6
  expect.extend(toHaveNoViolations)
6
7
 
@@ -706,7 +707,7 @@ describe('PktCombobox', () => {
706
707
  const combobox = container.querySelector('pkt-combobox') as PktCombobox
707
708
  await combobox.updateComplete
708
709
 
709
- const searchEventSpy = jest.fn()
710
+ const searchEventSpy = vi.fn()
710
711
  combobox.addEventListener('search', searchEventSpy)
711
712
 
712
713
  // Simulate search change
@@ -1,6 +1,7 @@
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 { vi } from 'vitest'
4
5
  import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
5
6
  import { CustomElementFor } from '../../tests/component-registry'
6
7
  import './consent'
@@ -46,13 +47,13 @@ afterEach(() => {
46
47
  }
47
48
  // Clean up global variables
48
49
  delete window.cookieBanner_googleAnalyticsId
49
- delete window.cookieBanner_hotjarId
50
- delete window.cookieBanner_devMode
51
- delete window.cookieBanner_cookieDomain
52
- delete window.cookieBanner_cookieSecure
53
- delete window.cookieBanner_cookieExpiryDays
54
- delete window.cookieBanner
55
- delete window.__cookieEvents
50
+ ;(window as any).cookieBanner_hotjarId = undefined
51
+ ;(window as any).cookieBanner_devMode = undefined
52
+ ;(window as any).cookieBanner_cookieDomain = undefined
53
+ ;(window as any).cookieBanner_cookieSecure = undefined
54
+ ;(window as any).cookieBanner_cookieExpiryDays = undefined
55
+ ;(window as any).cookieBanner = undefined
56
+ ;(window as any).__cookieEvents = undefined
56
57
  })
57
58
 
58
59
  describe('PktConsent', () => {
@@ -218,10 +219,10 @@ describe('PktConsent', () => {
218
219
  Object.defineProperty(window, 'cookieBanner', {
219
220
  value: {
220
221
  cookieConsent: {
221
- validateConsentCookie: jest.fn().mockResolvedValue(true),
222
- getConsentCookie: jest.fn().mockReturnValue('mock-cookie'),
222
+ validateConsentCookie: vi.fn().mockResolvedValue(true),
223
+ getConsentCookie: vi.fn().mockReturnValue('mock-cookie'),
223
224
  },
224
- openCookieModal: jest.fn(),
225
+ openCookieModal: vi.fn(),
225
226
  },
226
227
  writable: true,
227
228
  })
@@ -229,21 +230,21 @@ describe('PktConsent', () => {
229
230
  // Mock window.__cookieEvents
230
231
  Object.defineProperty(window, '__cookieEvents', {
231
232
  value: {
232
- on: jest.fn(),
233
- off: jest.fn(),
233
+ on: vi.fn(),
234
+ off: vi.fn(),
234
235
  },
235
236
  writable: true,
236
237
  })
237
238
 
238
239
  // Use fake timers to control setTimeout
239
- jest.useFakeTimers()
240
+ vi.useFakeTimers()
240
241
  })
241
242
 
242
243
  afterEach(() => {
243
244
  // Clean up mocks and timers
244
- jest.useRealTimers()
245
- delete (window as any).cookieBanner
246
- delete (window as any).__cookieEvents
245
+ vi.useRealTimers()
246
+ ;(window as any).cookieBanner = undefined
247
+ ;(window as any).__cookieEvents = undefined
247
248
  })
248
249
 
249
250
  test('handles click event on button trigger', async () => {
@@ -255,7 +256,7 @@ describe('PktConsent', () => {
255
256
  fireEvent.click(button!)
256
257
 
257
258
  // Fast-forward time to trigger setTimeout
258
- jest.runAllTimers()
259
+ vi.runAllTimers()
259
260
 
260
261
  expect(window.cookieBanner.openCookieModal).toHaveBeenCalled()
261
262
  })
@@ -271,7 +272,7 @@ describe('PktConsent', () => {
271
272
  fireEvent.click(link!)
272
273
 
273
274
  // Fast-forward time to trigger setTimeout
274
- jest.runAllTimers()
275
+ vi.runAllTimers()
275
276
 
276
277
  expect(window.cookieBanner.openCookieModal).toHaveBeenCalled()
277
278
  })
@@ -415,12 +416,12 @@ describe('PktConsent', () => {
415
416
 
416
417
  // Mock the event system
417
418
  window.__cookieEvents = {
418
- on: jest.fn(),
419
- off: jest.fn(),
419
+ on: vi.fn(),
420
+ off: vi.fn(),
420
421
  }
421
422
 
422
423
  // Set up a handler
423
- const mockHandler = jest.fn()
424
+ const mockHandler = vi.fn()
424
425
  consent['_cookieEventHandler'] = mockHandler
425
426
 
426
427
  // Disconnect the component
@@ -1,5 +1,6 @@
1
1
  import '@testing-library/jest-dom'
2
2
  import { axe, toHaveNoViolations } from 'jest-axe'
3
+ import { vi } from 'vitest'
3
4
 
4
5
  expect.extend(toHaveNoViolations)
5
6
 
@@ -241,7 +242,7 @@ describe('PktHeading', () => {
241
242
  })
242
243
 
243
244
  test('handles invalid levels gracefully', async () => {
244
- const consoleSpy = jest.spyOn(console, 'warn').mockImplementation()
245
+ const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
245
246
 
246
247
  const container = await createHeading()
247
248
  const heading = container.querySelector('pkt-heading') as PktHeading
@@ -1,5 +1,6 @@
1
1
  import '@testing-library/jest-dom'
2
2
  import { axe, toHaveNoViolations } from 'jest-axe'
3
+ import { vi } from 'vitest'
3
4
  import {
4
5
  createElementTest,
5
6
  BaseTestConfig,
@@ -43,7 +44,7 @@ afterEach(() => {
43
44
  })
44
45
 
45
46
  // Mock fetch for icon loading
46
- const mockFetch = jest.fn()
47
+ const mockFetch = vi.fn()
47
48
  const mockSvgContent =
48
49
  '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="test-path"></path></svg>'
49
50
 
@@ -270,7 +271,7 @@ describe('PktIcon', () => {
270
271
 
271
272
  describe('Global configuration', () => {
272
273
  test('uses custom pktFetch function when provided', async () => {
273
- const customFetch = jest.fn().mockResolvedValue({
274
+ const customFetch = vi.fn().mockResolvedValue({
274
275
  ok: true,
275
276
  text: () => Promise.resolve('<svg>custom</svg>'),
276
277
  })
@@ -1,6 +1,7 @@
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 { vi } from 'vitest'
4
5
  import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
5
6
  import { CustomElementFor } from '../../tests/component-registry'
6
7
  import './link'
@@ -147,7 +148,7 @@ describe('PktLink', () => {
147
148
  await link.updateComplete
148
149
 
149
150
  const anchor = link.querySelector('a')
150
- const clickHandler = jest.fn()
151
+ const clickHandler = vi.fn()
151
152
  anchor?.addEventListener('click', clickHandler)
152
153
 
153
154
  fireEvent.click(anchor!)
@@ -1,6 +1,7 @@
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 { vi } from 'vitest'
4
5
  import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
5
6
  import { CustomElementFor } from '../../tests/component-registry'
6
7
  import { type IPktMessagebox } from './messagebox'
@@ -167,8 +168,8 @@ describe('PktMessagebox', () => {
167
168
  test('dispatches close events when closed', async () => {
168
169
  const { messagebox } = await createMessageboxTest({ closable: true })
169
170
 
170
- const closeHandler = jest.fn()
171
- const onCloseHandler = jest.fn()
171
+ const closeHandler = vi.fn()
172
+ const onCloseHandler = vi.fn()
172
173
  messagebox.addEventListener('close', closeHandler)
173
174
  messagebox.addEventListener('on-close', onCloseHandler)
174
175
 
@@ -1,6 +1,7 @@
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 { vi } from 'vitest'
4
5
  import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
5
6
  import { CustomElementFor } from '../../tests/component-registry'
6
7
  import './radiobutton'
@@ -203,8 +204,8 @@ describe('pkt-radiobutton', () => {
203
204
  test('manages focus events correctly', async () => {
204
205
  const { radiobutton } = await createRadioButtonTest()
205
206
 
206
- const focusSpy = jest.fn()
207
- const blurSpy = jest.fn()
207
+ const focusSpy = vi.fn()
208
+ const blurSpy = vi.fn()
208
209
  radiobutton.addEventListener('focus', focusSpy)
209
210
  radiobutton.addEventListener('blur', blurSpy)
210
211
 
@@ -1,5 +1,6 @@
1
1
  import '@testing-library/jest-dom'
2
2
  import { axe, toHaveNoViolations } from 'jest-axe'
3
+ import { vi } from 'vitest'
3
4
  import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
4
5
  import { CustomElementFor } from '../../tests/component-registry'
5
6
  import { type IPktSelect, type TSelectOption } from './select'
@@ -159,8 +160,8 @@ describe('pkt-select', () => {
159
160
  test('manages focus events correctly', async () => {
160
161
  const { select } = await createSelectTest()
161
162
 
162
- const focusSpy = jest.spyOn(select, 'onFocus')
163
- const blurSpy = jest.spyOn(select, 'onBlur')
163
+ const focusSpy = vi.spyOn(select, 'onFocus')
164
+ const blurSpy = vi.spyOn(select, 'onBlur')
164
165
 
165
166
  const selectElement = select.querySelector('select') as HTMLSelectElement
166
167
 
@@ -0,0 +1,212 @@
1
+ import '@testing-library/jest-dom'
2
+ import { axe, toHaveNoViolations } from 'jest-axe'
3
+ import { fireEvent } from '@testing-library/dom'
4
+ import { vi } from 'vitest'
5
+ import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
6
+ import { CustomElementFor } from '../../tests/component-registry'
7
+ import { type IPktTag } from './tag'
8
+ import './tag'
9
+
10
+ export interface TagTestConfig extends Partial<IPktTag>, BaseTestConfig {}
11
+
12
+ // Use shared framework
13
+ export const createTagTest = async (config: TagTestConfig = {}) => {
14
+ const { container, element } = await createElementTest<
15
+ CustomElementFor<'pkt-tag'>,
16
+ TagTestConfig
17
+ >('pkt-tag', config)
18
+
19
+ return {
20
+ container,
21
+ tag: element,
22
+ }
23
+ }
24
+
25
+ expect.extend(toHaveNoViolations)
26
+
27
+ // Test data constants
28
+ const VALID_SKINS = [
29
+ 'blue',
30
+ 'blue-dark',
31
+ 'blue-light',
32
+ 'green',
33
+ 'red',
34
+ 'yellow',
35
+ 'beige',
36
+ 'gray',
37
+ 'grey',
38
+ ] as const
39
+ const VALID_SIZES = ['small', 'medium', 'large'] as const
40
+ const VALID_TYPES = ['button', 'reset', 'submit'] as const
41
+
42
+ afterEach(() => {
43
+ document.body.innerHTML = ''
44
+ })
45
+
46
+ describe('PktTag', () => {
47
+ describe('Basic Rendering', () => {
48
+ test('renders without errors', async () => {
49
+ const { tag } = await createTagTest()
50
+ expect(tag).toBeInTheDocument()
51
+ })
52
+
53
+ test('renders with default properties', async () => {
54
+ const { tag } = await createTagTest()
55
+ expect(tag.closeTag).toBe(false)
56
+ expect(tag.size).toBe('medium')
57
+ expect(tag.skin).toBe('blue')
58
+ expect(tag.type).toBe('button')
59
+ })
60
+
61
+ test('renders content in slot', async () => {
62
+ const content = 'Test Tag Content'
63
+ const { tag } = await createTagTest({ content })
64
+ expect(tag.textContent?.trim()).toBe(content)
65
+ })
66
+ })
67
+
68
+ describe('Skin Variations', () => {
69
+ test('applies different skin classes correctly', async () => {
70
+ for (const skin of VALID_SKINS) {
71
+ const { tag } = await createTagTest({ skin })
72
+ // For non-closeable tags, check the span element
73
+ const tagElement = tag.querySelector('span') || tag.querySelector('button')
74
+ expect(tagElement).toHaveClass(`pkt-tag--${skin}`)
75
+ }
76
+ })
77
+ })
78
+
79
+ describe('Size Variations', () => {
80
+ test('applies different size classes correctly', async () => {
81
+ for (const size of VALID_SIZES) {
82
+ const { tag } = await createTagTest({ size })
83
+ // For non-closeable tags, check the span element
84
+ const tagElement = tag.querySelector('span') || tag.querySelector('button')
85
+ expect(tagElement).toHaveClass(`pkt-tag--${size}`)
86
+ }
87
+ })
88
+ })
89
+
90
+ describe('Type Variations', () => {
91
+ test('sets correct type attribute', async () => {
92
+ for (const type of VALID_TYPES) {
93
+ const { tag } = await createTagTest({ type })
94
+ expect(tag.type).toBe(type)
95
+ }
96
+ })
97
+ })
98
+
99
+ describe('Icon Functionality', () => {
100
+ test('renders icon when iconName provided', async () => {
101
+ const { tag } = await createTagTest({ iconName: 'arrow-right' })
102
+ const icon = tag.querySelector('pkt-icon')
103
+ expect(icon).toBeInTheDocument()
104
+ expect(icon?.getAttribute('name')).toBe('arrow-right')
105
+ })
106
+
107
+ test('does not render icon when iconName not provided', async () => {
108
+ const { tag } = await createTagTest()
109
+ const icon = tag.querySelector('pkt-icon')
110
+ expect(icon).not.toBeInTheDocument()
111
+ })
112
+ })
113
+
114
+ describe('Close Functionality', () => {
115
+ test('renders close button when closeTag is true', async () => {
116
+ const { tag } = await createTagTest({ closeTag: true })
117
+ const closeIcon = tag.querySelector('.pkt-tag__close-btn')
118
+ expect(closeIcon).toBeInTheDocument()
119
+ })
120
+
121
+ test('does not render close button when closeTag is false', async () => {
122
+ const { tag } = await createTagTest({ closeTag: false })
123
+ const closeIcon = tag.querySelector('.pkt-tag__close-btn')
124
+ expect(closeIcon).not.toBeInTheDocument()
125
+ })
126
+
127
+ test('dispatches close event when close button is clicked', async () => {
128
+ const { tag } = await createTagTest({ closeTag: true })
129
+ const closeSpy = vi.fn()
130
+ tag.addEventListener('close', closeSpy)
131
+
132
+ const button = tag.querySelector('button') as HTMLButtonElement
133
+ fireEvent.click(button)
134
+
135
+ expect(closeSpy).toHaveBeenCalled()
136
+ })
137
+
138
+ test('hides tag when closed', async () => {
139
+ const { tag } = await createTagTest({ closeTag: true })
140
+ const button = tag.querySelector('button') as HTMLButtonElement
141
+
142
+ fireEvent.click(button)
143
+ await tag.updateComplete
144
+
145
+ expect(button).toHaveClass('pkt-hide')
146
+ })
147
+ })
148
+
149
+ describe('Text Style', () => {
150
+ test('applies text style class when provided', async () => {
151
+ const { tag } = await createTagTest({ textStyle: 'thin-text' })
152
+ const tagElement = tag.querySelector('span') || tag.querySelector('button')
153
+ expect(tagElement).toHaveClass('pkt-tag--thin-text')
154
+ })
155
+ })
156
+
157
+ describe('Accessibility', () => {
158
+ test('applies aria-label when provided', async () => {
159
+ const { tag } = await createTagTest({ closeTag: true, ariaLabel: 'Close tag' })
160
+ const button = tag.querySelector('button')
161
+ expect(button?.getAttribute('aria-label')).toBe('Close tag')
162
+ })
163
+
164
+ test('tag is accessible', async () => {
165
+ const { tag } = await createTagTest({
166
+ content: 'Accessible Tag',
167
+ closeTag: true,
168
+ ariaLabel: 'Close tag',
169
+ })
170
+
171
+ const results = await axe(tag)
172
+ expect(results).toHaveNoViolations()
173
+ })
174
+ })
175
+
176
+ describe('Complex Configurations', () => {
177
+ test('renders with all properties set', async () => {
178
+ const config: TagTestConfig = {
179
+ content: 'Complete Tag',
180
+ closeTag: true,
181
+ size: 'large',
182
+ skin: 'green',
183
+ iconName: 'check',
184
+ type: 'submit',
185
+ textStyle: 'thin-text',
186
+ ariaLabel: 'Complete tag',
187
+ }
188
+
189
+ const { tag } = await createTagTest(config)
190
+
191
+ expect(tag.textContent?.trim()).toBe(config.content)
192
+ expect(tag.closeTag).toBe(config.closeTag)
193
+ expect(tag.size).toBe(config.size)
194
+ expect(tag.skin).toBe(config.skin)
195
+ expect(tag.iconName).toBe(config.iconName)
196
+ expect(tag.type).toBe(config.type)
197
+ expect(tag.textStyle).toBe(config.textStyle)
198
+ expect(tag.ariaLabel).toBe(config.ariaLabel)
199
+
200
+ const button = tag.querySelector('button')
201
+ expect(button).toHaveClass(`pkt-tag--${config.size}`)
202
+ expect(button).toHaveClass(`pkt-tag--${config.skin}`)
203
+ expect(button).toHaveClass(`pkt-tag--${config.textStyle}`)
204
+
205
+ const icon = tag.querySelector('pkt-icon')
206
+ expect(icon?.getAttribute('name')).toBe(config.iconName)
207
+
208
+ const closeIcon = tag.querySelector('.pkt-tag__close-btn')
209
+ expect(closeIcon).toBeInTheDocument()
210
+ })
211
+ })
212
+ })