Files
CapaKraken/apps/web/e2e/dev-system/helpers.ts
T
Hartmut 8429bd86d4 test(e2e): fix dev-system test suite — storageState + strict-mode + signout
Fixes 8 failures from the first test run:

1. Rate limiter exhaustion (5/8 failures)
   Admin was logged in 9× across the suite, hitting the 5/15min auth
   limit. Fix: global-setup.ts logs in once per role and saves storage
   state; all non-login tests use storageState so they skip the form.
   Total admin logins per suite run: 3 (global setup + 2 explicit tests).

2. Strict-mode violations (2/8 failures)
   toBeVisible() matched 3 email cells / 2 permission-error nodes.
   Fix: .first() on both locators.

3. Auth.js v5 signout confirmation page (1/8 failures)
   GET /auth/signout renders a confirm form rather than immediately
   redirecting. Fix: signOut() helper clicks the submit button.

Note: running the suite right after a previous run may fail if the
in-memory rate limit hasn't reset (15-min window). Restart the dev
server, or add E2E_TEST_MODE=true to apps/web/.env.local to bypass.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-01 19:09:49 +02:00

51 lines
1.8 KiB
TypeScript

import { expect, type Page } from "@playwright/test";
/** Dev-system credentials — these exist in the planarchy.dev seed data */
export const DEV_USERS = {
admin: { email: "admin@planarchy.dev", password: "admin123" },
manager: { email: "manager@planarchy.dev", password: "manager123" },
viewer: { email: "viewer@planarchy.dev", password: "viewer123" },
} as const;
export async function signIn(page: Page, email: string, password: string) {
await page.goto("/auth/signin");
await page.fill('input[type="email"]', email);
await page.fill('input[type="password"]', password);
await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/, { timeout: 15000 });
}
export async function signOut(page: Page) {
await page.goto("/auth/signout");
// Auth.js v5 renders a confirmation page at /auth/signout before signing out.
// Click the submit button if a form is present.
const confirmBtn = page.locator('button[type="submit"]').first();
if (await confirmBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
await confirmBtn.click();
}
await page.waitForURL(/\/auth\/signin/, { timeout: 10000 });
}
/**
* Intercept all tRPC batch responses and assert none return HTTP 401.
* Returns a list of intercepted tRPC paths that were called.
*/
export async function assertNoTrpc401s(page: Page, action: () => Promise<void>) {
const failures: string[] = [];
page.on("response", (response) => {
if (response.url().includes("/api/trpc/") && response.status() === 401) {
const url = new URL(response.url());
failures.push(url.pathname + url.search.slice(0, 80));
}
});
await action();
if (failures.length > 0) {
throw new Error(
`tRPC 401 responses detected (session registry / auth broken):\n${failures.join("\n")}`,
);
}
}