import type { Page } from '@playwright/test' import { expect } from '@playwright/test' // Swedish labels from src/i18n/sv/calendar.ts — the suite pins // `locale: 'sv-SE'` in playwright.config.ts so these are stable. const MONTH_SELECT_LABEL = 'Välj månad' const YEAR_SELECT_LABEL = 'Välj år' /** Navigate the Calendar page to the month containing `date` (UTC). */ export async function goToCalendarMonth(page: Page, date: Date): Promise { await page.goto('/calendar') await expect(page.getByTestId('calendar')).toBeVisible() await page.getByLabel(YEAR_SELECT_LABEL).selectOption(String(date.getUTCFullYear())) await page.getByLabel(MONTH_SELECT_LABEL).selectOption(String(date.getUTCMonth())) } /** The exact `data-testid="calendar-day"` cell for an ISO date, wherever it * falls in the currently-displayed grid (including a leading/trailing day * from an adjacent month). */ export function calendarDayCell(page: Page, isoDate: string) { return page.locator(`[data-testid="calendar-day"][aria-label^="${isoDate}"]`) } /** * Drives a real drag-select across the given ISO dates (in order), the way * `Calendar.tsx` expects it: `CalendarDay` wires plain `onPointerDown`/ * `onPointerEnter` handlers (see `CalendarWeek.tsx`), and the page only * treats the gesture as a multi-day drag if `pointerenter` actually fired * for every intermediate cell before `pointerup` — see the `dates.length * === 1` branch in `Calendar.tsx`'s `pointerup` handler, which opens the * single-day modal instead of creating a period. * * A single fast `mouse.move` (or Playwright's default `hover()`/`dragTo()`) * can collapse into one native pointer event and skip the intermediate * cells entirely, which reads as a click on the anchor date. Moving in * several steps per cell, with a short pause between cells, is what * reliably fires a `pointerenter` on each one. */ export async function dragSelectDates(page: Page, isoDates: string[]): Promise { if (isoDates.length < 2) { throw new Error('dragSelectDates needs at least two dates to actually drag across') } const centerOf = async (isoDate: string): Promise<{ x: number; y: number }> => { const box = await calendarDayCell(page, isoDate).boundingBox() if (!box) throw new Error(`calendar day cell not visible for ${isoDate} — is it in the current month view?`) return { x: box.x + box.width / 2, y: box.y + box.height / 2 } } const [firstDate, ...restDates] = isoDates if (!firstDate) throw new Error('dragSelectDates needs at least two dates to actually drag across') const start = await centerOf(firstDate) await page.mouse.move(start.x, start.y) await page.mouse.down() for (const isoDate of restDates) { const point = await centerOf(isoDate) await page.mouse.move(point.x, point.y, { steps: 10 }) await page.waitForTimeout(50) } await page.mouse.up() }