UNPKG

@oslokommune/punkt-elements

Version:

Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo

368 lines (280 loc) 13.1 kB
import '@testing-library/jest-dom' import { fireEvent } from '@testing-library/dom' import { parseISODateString } from 'shared-utils/date-utils' import './calendar' import { PktCalendar } from './calendar' const waitForCustomElements = async () => { await customElements.whenDefined('pkt-calendar') } // Helper function to create calendar markup const createCalendar = async (calendarProps = '') => { const container = document.createElement('div') container.innerHTML = ` <pkt-calendar ${calendarProps}></pkt-calendar> ` document.body.appendChild(container) await waitForCustomElements() return container } // Cleanup after each test afterEach(() => { document.body.innerHTML = '' }) describe('PktCalendar', () => { describe('Rendering and basic functionality', () => { test('renders without errors', async () => { const container = await createCalendar() const calendar = container.querySelector('pkt-calendar') as PktCalendar expect(calendar).toBeInTheDocument() await calendar.updateComplete expect(calendar).toBeTruthy() }) test('renders with correct structure', async () => { const container = await createCalendar() const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete const calendarElement = calendar.querySelector('.pkt-calendar') const calendarTable = calendar.querySelector('.pkt-cal-days') const monthNav = calendar.querySelector('.pkt-cal-month-nav') expect(calendarElement).toBeInTheDocument() expect(calendarTable).toBeInTheDocument() expect(monthNav).toBeInTheDocument() }) test('renders month picker when withcontrols is true', async () => { const container = await createCalendar('withcontrols') const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete // Navigation buttons should always be present const prevButton = calendar.querySelector('.pkt-calendar__prev-month') const nextButton = calendar.querySelector('.pkt-calendar__next-month') expect(prevButton).toBeInTheDocument() expect(nextButton).toBeInTheDocument() // Should show month picker controls, not static title const monthPicker = calendar.querySelector('.pkt-cal-month-picker') const monthTitle = calendar.querySelector('.pkt-calendar__month-title') expect(monthPicker).toBeInTheDocument() expect(monthTitle).not.toBeInTheDocument() // Should have month and year inputs const monthSelect = monthPicker?.querySelector('select') const yearInput = monthPicker?.querySelector('input[type="number"]') expect(monthSelect).toBeInTheDocument() expect(yearInput).toBeInTheDocument() }) test('renders static month title when withcontrols is false', async () => { const container = await createCalendar() const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete // Navigation buttons should always be present const prevButton = calendar.querySelector('.pkt-calendar__prev-month') const nextButton = calendar.querySelector('.pkt-calendar__next-month') expect(prevButton).toBeInTheDocument() expect(nextButton).toBeInTheDocument() // Should show static month title, not controls const monthTitle = calendar.querySelector('.pkt-calendar__month-title') const monthPicker = calendar.querySelector('.pkt-cal-month-picker') expect(monthTitle).toBeInTheDocument() expect(monthPicker).not.toBeInTheDocument() }) }) describe('Properties and attributes', () => { test('applies default properties correctly', async () => { const container = await createCalendar() const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete expect(calendar.multiple).toBe(false) expect(calendar.range).toBe(false) expect(calendar.weeknumbers).toBe(false) expect(calendar.withcontrols).toBe(false) expect(calendar.selected).toEqual([]) expect(calendar.earliest).toBe(null) expect(calendar.latest).toBe(null) }) test('handles multiple property correctly', async () => { const container = await createCalendar('multiple') const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete expect(calendar.multiple).toBe(true) }) test('handles range property correctly', async () => { const container = await createCalendar('range') const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete expect(calendar.range).toBe(true) }) test('handles weeknumbers property correctly', async () => { const container = await createCalendar('weeknumbers') const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete expect(calendar.weeknumbers).toBe(true) const weekNumbers = calendar.querySelectorAll('.pkt-calendar__week-number') expect(weekNumbers.length).toBeGreaterThan(0) }) test('handles maxMultiple property correctly', async () => { const container = await createCalendar('multiple max-multiple="3"') const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete expect(calendar.maxMultiple).toBe(3) }) test('handles currentmonth property correctly', async () => { const testDate = '2024-03-15' const container = await createCalendar(`currentmonth="${testDate}"`) const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete expect(calendar.currentmonth).toEqual(parseISODateString(testDate)) }) }) describe('Month navigation', () => { it('should navigate to previous month when clicking previous button', async () => { const calendar = document.createElement('pkt-calendar') as PktCalendar document.body.appendChild(calendar) await waitForCustomElements() const navElement = calendar.querySelector('.pkt-cal-month-nav') const prevButton = navElement?.querySelector('button') expect(prevButton).toBeInTheDocument() const initialMonth = calendar.currentmonth!.getMonth() const initialYear = calendar.currentmonth!.getFullYear() fireEvent.click(prevButton!) await calendar.updateComplete // Should go to previous month (or December of previous year if we're in January) if (initialMonth === 0) { expect(calendar.currentmonth!.getMonth()).toBe(11) expect(calendar.currentmonth!.getFullYear()).toBe(initialYear - 1) } else { expect(calendar.currentmonth!.getMonth()).toBe(initialMonth - 1) expect(calendar.currentmonth!.getFullYear()).toBe(initialYear) } document.body.removeChild(calendar) }) it('should navigate to next month when clicking next button', async () => { const calendar = document.createElement('pkt-calendar') as PktCalendar document.body.appendChild(calendar) await waitForCustomElements() const navElement = calendar.querySelector('.pkt-cal-month-nav') const buttons = navElement?.querySelectorAll('button') const nextButton = buttons?.[1] // Second button is next expect(nextButton).toBeInTheDocument() const initialMonth = calendar.currentmonth!.getMonth() const initialYear = calendar.currentmonth!.getFullYear() fireEvent.click(nextButton!) await calendar.updateComplete // Should go to next month (or January of next year if we're in December) if (initialMonth === 11) { expect(calendar.currentmonth!.getMonth()).toBe(0) expect(calendar.currentmonth!.getFullYear()).toBe(initialYear + 1) } else { expect(calendar.currentmonth!.getMonth()).toBe(initialMonth + 1) expect(calendar.currentmonth!.getFullYear()).toBe(initialYear) } document.body.removeChild(calendar) }) test('navigates to next month', async () => { const container = await createCalendar('withcontrols currentmonth="2024-06-15"') const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete const nextButton = calendar.querySelector('.pkt-calendar__next-month') expect(nextButton).toBeInTheDocument() // With controls=true, check the month select dropdown instead of title const monthSelect = calendar.querySelector( '.pkt-cal-month-picker select', ) as HTMLSelectElement const initialMonth = monthSelect?.value fireEvent.click(nextButton!) await calendar.updateComplete const newMonth = monthSelect?.value expect(newMonth).not.toBe(initialMonth) }) test('month navigation updates visible dates', async () => { const container = await createCalendar('withcontrols currentmonth="2024-06-15"') const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete const initialDates = Array.from(calendar.querySelectorAll('.pkt-calendar__date')).map( (el) => el.textContent, ) const nextButton = calendar.querySelector('.pkt-calendar__next-month') fireEvent.click(nextButton!) await calendar.updateComplete const newDates = Array.from(calendar.querySelectorAll('.pkt-calendar__date')).map( (el) => el.textContent, ) expect(newDates).not.toEqual(initialDates) }) }) describe('Date formatting and localization', () => { test('displays day names correctly', async () => { const container = await createCalendar() const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete const dayHeaders = calendar.querySelectorAll('.pkt-calendar__day-name') expect(dayHeaders.length).toBe(7) // Check that day names are displayed dayHeaders.forEach((header) => { expect(header.textContent).toBeTruthy() expect(header.textContent!.length).toBeGreaterThan(0) }) }) test('displays month names correctly', async () => { const container = await createCalendar('currentmonth="2024-06-15"') const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete const monthTitle = calendar.querySelector('.pkt-calendar__month-title') expect(monthTitle).toBeInTheDocument() expect(monthTitle?.textContent).toBeTruthy() }) test('handles custom day strings', async () => { const container = await createCalendar() const calendar = container.querySelector('pkt-calendar') as PktCalendar // Set custom day strings calendar.dayStrings = ['S', 'M', 'T', 'W', 'T', 'F', 'S'] await calendar.updateComplete const dayHeaders = calendar.querySelectorAll('.pkt-calendar__day-name') expect(dayHeaders[0].textContent?.trim()).toBe('S') expect(dayHeaders[1].textContent?.trim()).toBe('M') }) test('handles custom month strings', async () => { const container = await createCalendar('withcontrols') const calendar = container.querySelector('pkt-calendar') as PktCalendar // Set custom month strings calendar.monthStrings = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', ] await calendar.updateComplete // When withcontrols=true, check the month select dropdown instead of title const monthSelect = calendar.querySelector('.pkt-cal-month-picker select') expect(monthSelect).toBeInTheDocument() // Check that the custom month string appears in the dropdown options const options = monthSelect?.querySelectorAll('option') expect(options?.[0]?.textContent).toContain('Jan') }) }) describe('Today highlighting', () => { test('highlights today date', async () => { const container = await createCalendar() const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete const todayDate = calendar.querySelector('.pkt-calendar__date--today') expect(todayDate).toBeInTheDocument() }) test('today date is selectable unless excluded', async () => { const container = await createCalendar() const calendar = container.querySelector('pkt-calendar') as PktCalendar await calendar.updateComplete const todayDate = calendar.querySelector('.pkt-calendar__date--today') if (todayDate && !todayDate.classList.contains('pkt-calendar__date--disabled')) { fireEvent.click(todayDate) await calendar.updateComplete expect(todayDate).toHaveClass('pkt-calendar__date--selected') } }) }) })