UNPKG

@oslokommune/punkt-elements

Version:

Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo

269 lines (202 loc) 9.67 kB
import '@testing-library/jest-dom' import { fireEvent } from '@testing-library/dom' 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('Date input validation and formatting', () => { test('validates date input format', async () => { const container = await createDatepicker('label="Test"') const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete const input = datepicker.querySelector('input') as HTMLInputElement // Test invalid date input - HTML5 date inputs will reject invalid formats // For date inputs, we test boundary validation instead fireEvent.change(input, { target: { value: '2024-02-30' } }) // Invalid date (Feb 30th) fireEvent.blur(input) await datepicker.updateComplete // Should show validation error or handle gracefully // For HTML5 date inputs, this might not trigger hasError, so we test that it doesn't crash expect(datepicker).toBeInTheDocument() }) test('formats dates according to dateformat property', async () => { const container = await createDatepicker('dateformat="yyyy-MM-dd" value="2024-06-15"') const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete const input = datepicker.querySelector('input') as HTMLInputElement expect(input.value).toBe('2024-06-15') }) test('handles different date formats', async () => { const testCases = [ { format: 'dd.MM.yyyy', expected: /\d{2}\.\d{2}\.\d{4}/ }, { format: 'MM/dd/yyyy', expected: /\d{2}\/\d{2}\/\d{4}/ }, { format: 'yyyy-MM-dd', expected: /\d{4}-\d{2}-\d{2}/ }, ] for (const testCase of testCases) { const container = await createDatepicker( `dateformat="${testCase.format}" value="2024-06-15" multiple`, ) const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete // Multiple mode input should be empty (for new input) const input = datepicker.querySelector('input') as HTMLInputElement expect(input.value).toBe('') // Selected dates should show in tags with custom format const tag = datepicker.querySelector('pkt-tag time') expect(tag).toBeInTheDocument() if (tag) { expect(tag.textContent).toMatch(testCase.expected) } // Cleanup container.remove() } }) test('handles leap year dates correctly', async () => { const leapYearDate = '2024-02-29' const container = await createDatepicker(`value="${leapYearDate}"`) const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete expect(datepicker.value).toBe(leapYearDate) expect(datepicker.hasError).toBe(false) }) test('validates February 29 in non-leap years', async () => { const invalidLeapDate = '2023-02-29' const container = await createDatepicker(`value="${invalidLeapDate}"`) const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete // Should handle gracefully or show error expect(datepicker).toBeInTheDocument() }) test('handles edge case dates', async () => { const edgeDates = ['1900-01-01', '2000-01-01', '2100-12-31', '1999-12-31'] for (const date of edgeDates) { const container = await createDatepicker(`value="${date}"`) const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete expect(datepicker.value).toBe(date) container.remove() } }) }) describe('Input field behavior', () => { test('allows manual date entry', async () => { const container = await createDatepicker('dateformat="yyyy-MM-dd"') const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete const input = datepicker.querySelector('input') as HTMLInputElement fireEvent.change(input, { target: { value: '2024-06-15' } }) fireEvent.blur(input) await datepicker.updateComplete expect(datepicker.value).toBe('2024-06-15') }) test('validates manual date entry', async () => { const container = await createDatepicker() const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete const input = datepicker.querySelector('input') as HTMLInputElement // HTML5 date inputs reject invalid formats, so we test that the component handles this gracefully fireEvent.change(input, { target: { value: 'invalid-date' } }) fireEvent.blur(input) await datepicker.updateComplete // HTML5 date input will reject invalid dates, component should handle gracefully expect(datepicker).toBeInTheDocument() expect(input.value).toBe('') // Invalid dates become empty }) test('shows placeholder text correctly', async () => { const placeholderText = 'Select a date' const container = await createDatepicker(`placeholder="${placeholderText}"`) const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete const input = datepicker.querySelector('input') as HTMLInputElement expect(input.placeholder).toBe(placeholderText) }) test('shows help text correctly', async () => { const helpText = 'Choose your preferred date' const container = await createDatepicker(`helptext="${helpText}"`) const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete const helpTextElement = datepicker.querySelector('pkt-helptext') expect(helpTextElement?.textContent).toContain(helpText) }) test('handles readonly state correctly', async () => { const container = await createDatepicker('readonly') const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete const input = datepicker.querySelector('input') as HTMLInputElement expect(input.readOnly).toBe(true) // Calendar should still be accessible const calendarButton = datepicker.querySelector('button[type="button"]') as HTMLButtonElement expect(calendarButton.disabled).toBe(false) }) }) describe('Keyboard navigation and interaction', () => { test('opens calendar with Enter key on calendar button', 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 if (calendarButton) { calendarButton.focus() fireEvent.keyDown(calendarButton, { key: 'Enter' }) await datepicker.updateComplete expect(datepicker.calendarOpen).toBe(true) } }) test('opens calendar with Space key on calendar button', 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 if (calendarButton) { calendarButton.focus() fireEvent.keyDown(calendarButton, { key: ' ' }) await datepicker.updateComplete expect(datepicker.calendarOpen).toBe(true) } }) test('closes calendar with Escape key', async () => { const container = await createDatepicker() const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete // Open calendar const calendarButton = datepicker.querySelector('button[type="button"]') fireEvent.click(calendarButton!) await datepicker.updateComplete // Press Escape fireEvent.keyDown(datepicker, { key: 'Escape' }) await datepicker.updateComplete expect(datepicker.calendarOpen).toBe(false) }) test('navigates between tags with arrow keys in multiple mode', async () => { const multipleDates = '2024-06-15,2024-06-20,2024-06-25' const container = await createDatepicker(`value="${multipleDates}" multiple`) const datepicker = container.querySelector('pkt-datepicker') as PktDatepicker await datepicker.updateComplete const tags = datepicker.querySelectorAll('pkt-tag') const firstTag = tags[0] as HTMLElement firstTag.focus() fireEvent.keyDown(firstTag, { key: 'ArrowRight' }) await datepicker.updateComplete // Focus should move to next tag expect(document.activeElement).toBeTruthy() }) }) })