@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
213 lines (180 loc) • 6.8 kB
text/typescript
import '@testing-library/jest-dom'
import { axe, toHaveNoViolations } from 'jest-axe'
import { fireEvent } from '@testing-library/dom'
import { vi } from 'vitest'
import { createElementTest, BaseTestConfig } from '../../tests/test-framework'
import { CustomElementFor } from '../../tests/component-registry'
import { type IPktTag } from './tag'
import './tag'
export interface TagTestConfig extends Partial<IPktTag>, BaseTestConfig {}
// Use shared framework
export const createTagTest = async (config: TagTestConfig = {}) => {
const { container, element } = await createElementTest<
CustomElementFor<'pkt-tag'>,
TagTestConfig
>('pkt-tag', config)
return {
container,
tag: element,
}
}
expect.extend(toHaveNoViolations)
// Test data constants
const VALID_SKINS = [
'blue',
'blue-dark',
'blue-light',
'green',
'red',
'yellow',
'beige',
'gray',
'grey',
] as const
const VALID_SIZES = ['small', 'medium', 'large'] as const
const VALID_TYPES = ['button', 'reset', 'submit'] as const
afterEach(() => {
document.body.innerHTML = ''
})
describe('PktTag', () => {
describe('Basic Rendering', () => {
test('renders without errors', async () => {
const { tag } = await createTagTest()
expect(tag).toBeInTheDocument()
})
test('renders with default properties', async () => {
const { tag } = await createTagTest()
expect(tag.closeTag).toBe(false)
expect(tag.size).toBe('medium')
expect(tag.skin).toBe('blue')
expect(tag.type).toBe('button')
})
test('renders content in slot', async () => {
const content = 'Test Tag Content'
const { tag } = await createTagTest({ content })
expect(tag.textContent?.trim()).toBe(content)
})
})
describe('Skin Variations', () => {
test('applies different skin classes correctly', async () => {
for (const skin of VALID_SKINS) {
const { tag } = await createTagTest({ skin })
// For non-closeable tags, check the span element
const tagElement = tag.querySelector('span') || tag.querySelector('button')
expect(tagElement).toHaveClass(`pkt-tag--${skin}`)
}
})
})
describe('Size Variations', () => {
test('applies different size classes correctly', async () => {
for (const size of VALID_SIZES) {
const { tag } = await createTagTest({ size })
// For non-closeable tags, check the span element
const tagElement = tag.querySelector('span') || tag.querySelector('button')
expect(tagElement).toHaveClass(`pkt-tag--${size}`)
}
})
})
describe('Type Variations', () => {
test('sets correct type attribute', async () => {
for (const type of VALID_TYPES) {
const { tag } = await createTagTest({ type })
expect(tag.type).toBe(type)
}
})
})
describe('Icon Functionality', () => {
test('renders icon when iconName provided', async () => {
const { tag } = await createTagTest({ iconName: 'arrow-right' })
const icon = tag.querySelector('pkt-icon')
expect(icon).toBeInTheDocument()
expect(icon?.getAttribute('name')).toBe('arrow-right')
})
test('does not render icon when iconName not provided', async () => {
const { tag } = await createTagTest()
const icon = tag.querySelector('pkt-icon')
expect(icon).not.toBeInTheDocument()
})
})
describe('Close Functionality', () => {
test('renders close button when closeTag is true', async () => {
const { tag } = await createTagTest({ closeTag: true })
const closeIcon = tag.querySelector('.pkt-tag__close-btn')
expect(closeIcon).toBeInTheDocument()
})
test('does not render close button when closeTag is false', async () => {
const { tag } = await createTagTest({ closeTag: false })
const closeIcon = tag.querySelector('.pkt-tag__close-btn')
expect(closeIcon).not.toBeInTheDocument()
})
test('dispatches close event when close button is clicked', async () => {
const { tag } = await createTagTest({ closeTag: true })
const closeSpy = vi.fn()
tag.addEventListener('close', closeSpy)
const button = tag.querySelector('button') as HTMLButtonElement
fireEvent.click(button)
expect(closeSpy).toHaveBeenCalled()
})
test('hides tag when closed', async () => {
const { tag } = await createTagTest({ closeTag: true })
const button = tag.querySelector('button') as HTMLButtonElement
fireEvent.click(button)
await tag.updateComplete
expect(button).toHaveClass('pkt-hide')
})
})
describe('Text Style', () => {
test('applies text style class when provided', async () => {
const { tag } = await createTagTest({ textStyle: 'thin-text' })
const tagElement = tag.querySelector('span') || tag.querySelector('button')
expect(tagElement).toHaveClass('pkt-tag--thin-text')
})
})
describe('Accessibility', () => {
test('applies aria-label when provided', async () => {
const { tag } = await createTagTest({ closeTag: true, ariaLabel: 'Close tag' })
const button = tag.querySelector('button')
expect(button?.getAttribute('aria-label')).toBe('Close tag')
})
test('tag is accessible', async () => {
const { tag } = await createTagTest({
content: 'Accessible Tag',
closeTag: true,
ariaLabel: 'Close tag',
})
const results = await axe(tag)
expect(results).toHaveNoViolations()
})
})
describe('Complex Configurations', () => {
test('renders with all properties set', async () => {
const config: TagTestConfig = {
content: 'Complete Tag',
closeTag: true,
size: 'large',
skin: 'green',
iconName: 'check',
type: 'submit',
textStyle: 'thin-text',
ariaLabel: 'Complete tag',
}
const { tag } = await createTagTest(config)
expect(tag.textContent?.trim()).toBe(config.content)
expect(tag.closeTag).toBe(config.closeTag)
expect(tag.size).toBe(config.size)
expect(tag.skin).toBe(config.skin)
expect(tag.iconName).toBe(config.iconName)
expect(tag.type).toBe(config.type)
expect(tag.textStyle).toBe(config.textStyle)
expect(tag.ariaLabel).toBe(config.ariaLabel)
const button = tag.querySelector('button')
expect(button).toHaveClass(`pkt-tag--${config.size}`)
expect(button).toHaveClass(`pkt-tag--${config.skin}`)
expect(button).toHaveClass(`pkt-tag--${config.textStyle}`)
const icon = tag.querySelector('pkt-icon')
expect(icon?.getAttribute('name')).toBe(config.iconName)
const closeIcon = tag.querySelector('.pkt-tag__close-btn')
expect(closeIcon).toBeInTheDocument()
})
})
})