- M package.json — added typecheck, test:e2e, verify scripts; added @playwright/test devDep - M pnpm-lock.yaml - M .gitignore — Playwright artifacts - M tsconfig.json — auto-modified by Next.js include path - ?? e2e/ — config + fixtures + 3 specs - ?? playwright.config.ts - ?? scripts/verify.sh, scripts/db-test-truncate.sql
35 lines
1.3 KiB
TypeScript
35 lines
1.3 KiB
TypeScript
import { expect, type Page } from "@playwright/test";
|
|
import { clearMailpit, waitForMagicLink } from "./mailpit";
|
|
|
|
export const ROLE_EMAIL = {
|
|
admin: "admin@touchbase.local",
|
|
therapist: "mei@touchbase.local",
|
|
customer: "alex@example.com",
|
|
} as const;
|
|
|
|
export type RoleKey = keyof typeof ROLE_EMAIL;
|
|
|
|
export async function signInAs(page: Page, role: RoleKey, callbackUrl = "/"): Promise<void> {
|
|
await clearMailpit();
|
|
const email = ROLE_EMAIL[role];
|
|
|
|
await page.goto(`/login?callbackUrl=${encodeURIComponent(callbackUrl)}`);
|
|
await page.getByLabel("Email").fill(email);
|
|
// Auth.js v5 server-action signIn() redirects to either our /login/check-email
|
|
// page or its internal /api/auth/verify-request. Either is fine — the email
|
|
// is sent regardless. Just wait for any nav off /login.
|
|
await Promise.all([
|
|
page.waitForURL((url) => !/\/login(\?|$)/.test(url.pathname + url.search)),
|
|
page.getByRole("button", { name: /send sign-in link/i }).click(),
|
|
]);
|
|
|
|
const link = await waitForMagicLink(email);
|
|
await page.goto(link);
|
|
|
|
// After callback, NextAuth redirects to callbackUrl. Verify session cookie present.
|
|
await expect.poll(async () => {
|
|
const cookies = await page.context().cookies();
|
|
return cookies.some((c) => /authjs.*session-token/i.test(c.name) || /next-auth.*session-token/i.test(c.name));
|
|
}).toBeTruthy();
|
|
}
|