- SessionExpiryBanner: live countdown, warn 15min early, one-shot toast, Extend button - countdown.ts: pure countdown helpers (timeUntilExpiry, sessionExpiryPhase, formatCountdown) - useSessionExpired: added unlock handler for SESSION_EXTENDED_EVENT - useGameTick: exported SESSION_EXTENDED_EVENT for session extension - unit tests: 14/14 pass for countdown helpers - e2e test: banner renders with countdown + extend button
53 lines
1.7 KiB
JavaScript
53 lines
1.7 KiB
JavaScript
import { test, expect } from "@playwright/test";
|
|
|
|
test("banner shows countdown + extend button", async ({ page, context }) => {
|
|
// Craft near-expiry token and set it as cookie
|
|
const { SignJWT } = await import("jose");
|
|
const SECRET = "f80003be79c28ca283c2cbfde2984356";
|
|
const key = new TextEncoder().encode(SECRET);
|
|
|
|
// Login to get a real sid
|
|
const loginRes = await fetch("http://localhost:3000/api/users/login", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ username: "dev", password: "Test123" }),
|
|
});
|
|
const data = await loginRes.json();
|
|
const payload = JSON.parse(Buffer.from(data.token.split(".")[1], "base64url").toString());
|
|
|
|
const now = Math.floor(Date.now() / 1000);
|
|
const near = await new SignJWT({
|
|
id: 23, collection: "users", email: payload.email, sid: payload.sid, iat: now, exp: now + 600,
|
|
})
|
|
.setProtectedHeader({ alg: "HS256", typ: "JWT" })
|
|
.setIssuedAt(now)
|
|
.setExpirationTime(now + 600)
|
|
.sign(key);
|
|
|
|
// Set cookie
|
|
await context.addCookies([{
|
|
name: "payload-token",
|
|
value: near,
|
|
domain: "localhost",
|
|
path: "/",
|
|
expires: now + 600,
|
|
}]);
|
|
|
|
// Navigate to home
|
|
await page.goto("http://localhost:3000/");
|
|
await page.waitForSelector("role=status", { timeout: 10000 });
|
|
|
|
// Check banner is visible
|
|
const banner = page.locator("role=status").first();
|
|
await expect(banner).toBeVisible();
|
|
|
|
// Check countdown
|
|
const countdown = banner.locator(".font-mono.tabular-nums").first();
|
|
await expect(countdown).toHaveText(/0\d:\d{2}/); // should show ~10:00
|
|
|
|
// Check extend button
|
|
const extendBtn = banner.locator("button:has-text('Extend')");
|
|
await expect(extendBtn).toBeVisible();
|
|
|
|
console.log("Banner check PASSED");
|
|
});
|