tests/auth-guard.spec.ts
Rama main · réplica de lectura del repositorio original.
import { expect, type Page } from "@playwright/test";
import { loggedTest } from "./logged-test";
import { seedTest } from "./seed-test";
/**
* Routes wrapped in `AuthGuard`, which redirects to `/login` when there is no
* viewer.
*
* The app renders before `me` resolves, so the guard has to distinguish "nobody
* is logged in" from "we do not know yet". When it did not, every one of these
* bounced a signed-in user through `/login` — landing them somewhere other than
* the page they asked for, which is how the staff specs started failing.
*/
const GUARDED_PATHS = ["/", "/new", "/teams/new", "/staff/teams"];
/**
* Records every main-frame navigation, so a bounce stays visible even when the
* chain recovers and ends somewhere plausible.
*/
function trackNavigations(page: Page): string[] {
const paths: string[] = [];
page.on("framenavigated", (frame) => {
if (frame === page.mainFrame()) {
paths.push(new URL(frame.url()).pathname);
}
});
return paths;
}
for (const path of GUARDED_PATHS) {
loggedTest(
`does not bounce a signed-in user via /login: ${path}`,
async ({ page }) => {
const navigations = trackNavigations(page);
await page.goto(path);
// The bug redirected on the first render, so a bounce is immediate — but
// settle the network so `me` has certainly had time to land.
await page.waitForLoadState("networkidle");
// Asserted on the whole chain rather than the final URL: the old
// behaviour still ended on a real page, because `/login` forwarded the
// user to their account. Only the intermediate hop reveals it.
expect(navigations.filter((navigated) => navigated === "/login")).toEqual(
[],
);
},
);
}
seedTest("sends a signed-out visitor to /login", async ({ page }) => {
// The other half of the guard: with no session at all it must still redirect.
await page.goto("/staff/teams");
await page.waitForURL(/\/login/);
expect(new URL(page.url()).pathname).toBe("/login");
});