Files
babymonitor/frontend/tests/e2e/timetable_timezone.spec.ts
T
2026-05-28 09:31:20 +02:00

99 lines
4.6 KiB
TypeScript

/* 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');
}
});
});