@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
194 lines (145 loc) • 6.2 kB
text/typescript
import '@testing-library/jest-dom'
import { axe, toHaveNoViolations } from 'jest-axe'
import { fireEvent } from '@testing-library/dom'
expect.extend(toHaveNoViolations)
import './datepicker'
import '../calendar/calendar'
import { PktDatepicker } from './datepicker'
const waitForCustomElements = async () => {
await customElements.whenDefined('pkt-datepicker')
await customElements.whenDefined('pkt-calendar')
}
// Helper function to create datepicker markup
const createDatepicker = async (datepickerProps = '') => {
const container = document.createElement('div')
container.innerHTML = `
<pkt-datepicker ${datepickerProps}></pkt-datepicker>
`
document.body.appendChild(container)
await waitForCustomElements()
return container
}
// Cleanup after each test
afterEach(() => {
document.body.innerHTML = ''
})
describe('PktDatepicker', () => {
describe('Event handling', () => {
test('dispatches change event when value changes', async () => {
const container = await createDatepicker()
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
await datepicker.updateComplete
let changeEventFired = false
datepicker.addEventListener('change', () => {
changeEventFired = true
})
const input = datepicker.querySelector('input') as HTMLInputElement
fireEvent.change(input, { target: { value: '2024-06-15' } })
fireEvent.blur(input)
await datepicker.updateComplete
expect(changeEventFired).toBe(true)
})
test('dispatches input event during typing', async () => {
const container = await createDatepicker()
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
await datepicker.updateComplete
let inputEventFired = false
datepicker.addEventListener('input', () => {
inputEventFired = true
})
const input = datepicker.querySelector('input') as HTMLInputElement
fireEvent.input(input, { target: { value: '2024-06-15' } })
await datepicker.updateComplete
expect(inputEventFired).toBe(true)
})
test('dispatches focus and blur events', async () => {
const container = await createDatepicker()
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
await datepicker.updateComplete
let focusEventFired = false
let blurEventFired = false
datepicker.addEventListener('focus', () => {
focusEventFired = true
})
datepicker.addEventListener('blur', () => {
blurEventFired = true
})
const input = datepicker.querySelector('input') as HTMLInputElement
fireEvent.focus(input)
await datepicker.updateComplete
fireEvent.blur(input)
await datepicker.updateComplete
expect(focusEventFired).toBe(true)
expect(blurEventFired).toBe(true)
})
})
describe('Accessibility', () => {
test('has no accessibility violations', async () => {
const container = await createDatepicker(
'label="Test Datepicker" helptext="Select your date"',
)
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
await datepicker.updateComplete
const results = await axe(datepicker)
expect(results).toHaveNoViolations()
})
test('associates label with input correctly', async () => {
const container = await createDatepicker('id="test-datepicker" label="Test Label"')
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
await datepicker.updateComplete
const label = datepicker.querySelector('label')
const input = datepicker.querySelector('input')
expect(label).toHaveAttribute('for')
expect(input).toHaveAttribute('id')
expect(label?.getAttribute('for')).toBe(input?.getAttribute('id'))
})
test('has proper ARIA attributes for calendar button', async () => {
const container = await createDatepicker('label="Test Datepicker"')
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
await datepicker.updateComplete
const calendarButton = datepicker.querySelector('button[type="button"]')
expect(calendarButton).toBeInTheDocument()
// Check initial state
expect(datepicker.calendarOpen).toBe(false)
// Open calendar
fireEvent.click(calendarButton!)
await datepicker.updateComplete
expect(datepicker.calendarOpen).toBe(true)
})
test('provides proper screen reader announcements', async () => {
const container = await createDatepicker('label="Test Datepicker"')
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
await datepicker.updateComplete
const input = datepicker.querySelector('input')
expect(input).toHaveAttribute('aria-describedby')
})
test('handles focus management correctly', async () => {
const container = await createDatepicker()
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
await datepicker.updateComplete
const calendarButton = datepicker.querySelector('button[type="button"]') as HTMLElement
// Focus should be manageable
if (calendarButton) {
calendarButton.focus()
expect(document.activeElement).toBe(calendarButton)
}
})
test('supports keyboard-only interaction', async () => {
const container = await createDatepicker()
const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker
await datepicker.updateComplete
const calendarButton = datepicker.querySelector('button[type="button"]') as HTMLElement
// Should open with keyboard
if (calendarButton) {
calendarButton.focus()
fireEvent.keyDown(calendarButton, { key: 'Enter' })
await datepicker.updateComplete
expect(datepicker.calendarOpen).toBe(true)
}
// Should close with keyboard
fireEvent.keyDown(datepicker, { key: 'Escape' })
await datepicker.updateComplete
expect(datepicker.calendarOpen).toBe(false)
})
})
})