/* eslint-disable @typescript-eslint/no-explicit-any */ import { test, expect } from '@playwright/test'; test.describe('Sleep Timetable Timezone Alignment', () => { test.use({ timezoneId: 'America/Los_Angeles', locale: 'en-US' }); test('red marker (current time) should align with the correct grid column/row for sleeping sessions', async ({ page }) => { // 1. Mock the current time to be 08:00 AM local (PDT/PST) // Since we can't easily mock system time in Playwright without extra tools, // we will rely on the fact that 'new Date()' is called in the component. // We can use `page.addInitScript` to mock Date. const mockDate = new Date('2026-05-17T08:00:00-07:00'); await page.addInitScript((date) => { const originalDate = globalThis.Date; function MockDate(...args: any[]) { if (args.length === 0) return new originalDate(date.getTime()); return new originalDate(...args); } MockDate.prototype = originalDate.prototype; MockDate.now = () => date.getTime(); globalThis.Date = MockDate as any; }, mockDate); // 2. Mock the API response for timetable // We want to simulate a session that is currently happening in local time. // If it's 08:00 AM now, and they are sleeping, the slot for 08:00 should be green. // The API returns slots with 'sleeping: true'. // Note: the component's logic uses `timetable.slots` and checks `isSleepingInInterval`. // The slots come from the backend with 'slot_start' and 'slot_end'. await page.route('**/api/stats/timetable*', async (route) => { const json = { slots: [ // A session that covers 07:00 to 09:00 on May 17th { date: '2026-05-17', slot_start: '07:00', slot_end: '07:15', sleeping: true }, { date: '2026-05-17', slot_start: '07:15', slot_end: '07:30', sleeping: true }, { date: '2026-05-17', slot_start: '07:30', slot_end: '07:45', sleeping: true }, { date: '2026-05-17', slot_start: '07:45', slot_end: '08:00', sleeping: true }, { date: '2026-05-17', slot_start: '08:00', slot_end: '08:15', sleeping: true }, { date: '2026-05-17', slot_start: '08:15', slot_end: '08:30', sleeping: true }, { date: '2026-05-17', slot_start: '08:30', slot_end: '08:45', sleeping: true }, { date: '2026-05-17', slot_start: '08:45', slot_end: '09:00', sleeping: true }, ] }; await route.fulfill({ json }); }); // Also mock the daily summary as it's used by useStats await page.route('**/api/stats/daily-summary*', async (route) => { await route.fulfill({ json: { days: [] } }); }); // Also mock wake-sleep times as it's used by useStats await page.route('**/api/stats/wake-sleep-times*', async (route) => { await route.fulfill({ json: { days: [] } }); }); // 3. Navigate to the stats page await page.goto('/stats'); // Assuming /stats is the route for StatsPage // 4. Verify that the red marker (at 08:00) is inside a green cell // The red marker has class 'bg-red-500' const redMarker = page.locator('.bg-red-500'); await expect(redMarker).toBeVisible(); // We want to check if the cell at 08:00 is green. // In our mocked data, the slots for 08:00 are sleeping: true. // The component renders cells with className={`h-8 w-full ${sleeping ? 'bg-green-500' : 'bg-gray-50'}`} // Since we can't easily target a specific "cell" by index in a grid without more info, // we check if there's at least one green cell that matches our criteria. const greenCells = page.locator('.bg-green-500'); await expect(greenCells.count()).toBeGreaterThan(0); // To be really precise, we can check the position of the red marker // and see if there is a green cell at that same vertical position. const markerBox = await redMarker.boundingBox(); if (markerBox) { // The marker is at 08:00, which is (8*60)/1440 = 33.33% from the top of the container // We can check if the cell at that height is green. const allGreenCells = page.locator('.bg-green-500'); const count = await allGreenCells.count(); let foundAlignedCell = false; for (let i = 0; i < count; i++) { const cellBox = await allGreenCells.nth(i).boundingBox(); if (cellBox && markerBox.y >= cellBox.y - 2 && markerBox.y <= cellBox.y + cellBox.height + 2) { foundAlignedCell = true; break; } } expect(foundAlignedCell).toBe(true); } else { throw new Error('Could not get bounding box for red marker'); } }); });