mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
Point the header, overscroll and timezone specs at the pages that hold those cards now, add the module pages and Preview features to the one-piece sweep, and add a 390 px journey through the grouped section sheet. Unit coverage for the Preview features card.
109 lines
3.7 KiB
TypeScript
109 lines
3.7 KiB
TypeScript
import { expect, test } from "./setup/test";
|
|
|
|
import { STORAGE_STATE_PATH } from "./setup/global-setup";
|
|
|
|
/**
|
|
* Issue #490 — client-rendered timestamps follow the PROFILE timezone.
|
|
*
|
|
* `/api/auth/me` is mocked with an `Asia/Manila` profile; the sessions
|
|
* card on /settings/security renders `lastActiveAt` through
|
|
* `useFormatters()`, which reads the localStorage timezone mirror that
|
|
* `fetchMe` fills from the mocked payload. A fixed UTC instant must
|
|
* therefore paint the MANILA wall clock (14:30), never the Berlin
|
|
* fallback (08:30) and never the browser zone (the Playwright context is
|
|
* pinned to Europe/Berlin precisely so this assertion is meaningful).
|
|
*
|
|
* Asserts against the stable `data-slot="security-session-row"` hook,
|
|
* not viewport-dependent text.
|
|
*/
|
|
|
|
// 06:30 UTC = 14:30 Asia/Manila (+8, no DST) = 08:30 Europe/Berlin (CEST).
|
|
const LAST_ACTIVE_UTC = "2026-07-14T06:30:00.000Z";
|
|
|
|
test.describe("profile-timezone display (#490)", () => {
|
|
test.use({ storageState: STORAGE_STATE_PATH });
|
|
|
|
test("sessions card renders lastActiveAt in the Manila profile zone", async ({
|
|
page,
|
|
}) => {
|
|
await page.route("**/api/auth/me", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
data: {
|
|
id: "user_e2e",
|
|
username: "e2e-tester",
|
|
email: "e2e@healthlog.test",
|
|
role: "USER",
|
|
heightCm: 180,
|
|
dateOfBirth: "1990-01-01",
|
|
gender: "MALE",
|
|
timezone: "Asia/Manila",
|
|
timeFormat: "H24",
|
|
dateFormat: "AUTO",
|
|
onboardingCompletedAt: "2025-01-01T00:00:00.000Z",
|
|
onboardingTourCompleted: true,
|
|
gravatarUrl: null,
|
|
glucoseUnit: "mg/dL",
|
|
},
|
|
error: null,
|
|
}),
|
|
}),
|
|
);
|
|
|
|
await page.route("**/api/auth/me/sessions", (route) =>
|
|
route.fulfill({
|
|
status: 200,
|
|
contentType: "application/json",
|
|
body: JSON.stringify({
|
|
data: {
|
|
sessions: [
|
|
{
|
|
id: "sess_e2e_current",
|
|
device: "Chrome on macOS",
|
|
ipMasked: "192.168.1.xxx",
|
|
location: null,
|
|
lastActiveAt: LAST_ACTIVE_UTC,
|
|
createdAt: LAST_ACTIVE_UTC,
|
|
isCurrent: true,
|
|
},
|
|
],
|
|
},
|
|
error: null,
|
|
}),
|
|
}),
|
|
);
|
|
|
|
await page.goto("/settings/security", { waitUntil: "domcontentloaded" });
|
|
|
|
// The sessions card is collapsed by default — expand it first. The
|
|
// toggle's onClick can be dropped if Playwright clicks before React has
|
|
// hydrated the handler, leaving the region `hidden` for the whole wait.
|
|
// Retry the click until `aria-expanded` actually flips.
|
|
const toggle = page.locator(
|
|
'[data-slot="settings-security-sessions-toggle"]',
|
|
);
|
|
await expect(toggle).toBeVisible({ timeout: 10_000 });
|
|
await expect(async () => {
|
|
await toggle.click();
|
|
await expect(toggle).toHaveAttribute("aria-expanded", "true", {
|
|
timeout: 2_000,
|
|
});
|
|
}).toPass({ timeout: 15_000 });
|
|
|
|
const row = page.locator('[data-slot="security-session-row"]').first();
|
|
await expect(row).toBeVisible({ timeout: 10_000 });
|
|
|
|
// Manila wall clock (H24). The mirror write from the mocked /me may
|
|
// land after the first paint of the sessions row — the poll absorbs
|
|
// the re-render.
|
|
await expect(row).toContainText("14:30", { timeout: 10_000 });
|
|
// Never the Berlin fallback for this instant…
|
|
await expect(row).not.toContainText("08:30");
|
|
// …and never a 12-hour rendering (the H24 preference rides the same
|
|
// mirror pipeline).
|
|
await expect(row).not.toContainText("PM");
|
|
});
|
|
});
|