The virtual-authenticator setup and registerUser were copy-pasted into six spec files and had drifted: the auth spec's copy lost the final URL assertion, and the settings spec's variant skipped hydration and the Terms checkbox entirely. Seed-route boilerplate and hardcoded localhost URLs were repeated across three more files. - helpers/auth.ts: setup/removeVirtualAuthenticator, submitRegistration (no outcome assertion, for expected-failure attempts), registerUser (asserts the signed-in redirect), registerFreshUser, logout - helpers/journal.ts: JOURNAL/PLANNER base URLs, seedRoute, routeHasGeom, seedKomootConnection - nine spec files now import the helpers instead of re-deriving them Found while consolidating: settings.test.ts, explore.test.ts, and social.test.ts are not matched by any playwright project and have never run — which is how the settings spec's broken register helper survived. Registering them (and fixing whatever has rotted) is a follow-up; the config now carries a warning so the trap is at least documented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
84 lines
3.2 KiB
TypeScript
84 lines
3.2 KiB
TypeScript
// Shared auth helpers for journal specs. These were previously
|
|
// copy-pasted per spec file and had already drifted (the auth spec's
|
|
// registerUser lost the final URL assertion the other copies had, and
|
|
// the settings spec's variant skipped hydration and the Terms
|
|
// checkbox). One canonical copy lives here.
|
|
|
|
import { expect, waitForHydration, type CDPSession, type Page } from "../fixtures/test";
|
|
|
|
export async function setupVirtualAuthenticator(cdp: CDPSession): Promise<string> {
|
|
await cdp.send("WebAuthn.enable");
|
|
const { authenticatorId } = await cdp.send("WebAuthn.addVirtualAuthenticator", {
|
|
options: {
|
|
protocol: "ctap2",
|
|
transport: "internal",
|
|
hasResidentKey: true,
|
|
hasUserVerification: true,
|
|
isUserVerified: true,
|
|
},
|
|
});
|
|
return authenticatorId;
|
|
}
|
|
|
|
export async function removeVirtualAuthenticator(
|
|
cdp: CDPSession,
|
|
authenticatorId: string,
|
|
): Promise<void> {
|
|
await cdp.send("WebAuthn.removeVirtualAuthenticator", { authenticatorId });
|
|
await cdp.send("WebAuthn.disable");
|
|
}
|
|
|
|
/**
|
|
* Fill and submit the registration form (passkey + Terms acceptance).
|
|
* Makes no assertion about the outcome — use this directly for
|
|
* expected-failure attempts (duplicate email/username), and
|
|
* registerUser for the success path.
|
|
*/
|
|
export async function submitRegistration(
|
|
page: Page,
|
|
email: string,
|
|
username: string,
|
|
): Promise<void> {
|
|
await page.goto("/auth/register");
|
|
await expect(page.getByRole("heading", { name: "Register" })).toBeVisible();
|
|
await waitForHydration(page);
|
|
await page.getByLabel("Email").click();
|
|
await page.getByLabel("Email").fill(email);
|
|
await page.getByLabel("Username").click();
|
|
await page.getByLabel("Username").fill(username);
|
|
// Verify both fields retained values before submitting
|
|
await expect(page.getByLabel("Email")).toHaveValue(email);
|
|
await expect(page.getByLabel("Username")).toHaveValue(username);
|
|
// Accept the Terms of Service (required)
|
|
await page.getByRole("checkbox").check();
|
|
await page.getByRole("button", { name: /Register with Passkey/ }).click();
|
|
}
|
|
|
|
/** Register a user with a passkey and wait for the signed-in redirect. */
|
|
export async function registerUser(page: Page, email: string, username: string): Promise<void> {
|
|
await submitRegistration(page, email, username);
|
|
await expect(page).toHaveURL("/", { timeout: 10000 });
|
|
}
|
|
|
|
/** Register a throwaway user with unique credentials derived from `prefix`. */
|
|
export async function registerFreshUser(
|
|
page: Page,
|
|
prefix: string,
|
|
): Promise<{ email: string; username: string }> {
|
|
const email = `${prefix}-${Date.now()}@example.com`;
|
|
const username = `${prefix}${Date.now()}`;
|
|
await registerUser(page, email, username);
|
|
return { email, username };
|
|
}
|
|
|
|
export async function logout(page: Page, accountLabel: string): Promise<void> {
|
|
// The account cluster lives inside an avatar dropdown. Click the
|
|
// avatar (its aria-label is displayName || username), then click the
|
|
// Log Out menuitem inside the popup.
|
|
await waitForHydration(page);
|
|
await page.getByRole("navigation").getByRole("button", { name: accountLabel }).click();
|
|
await page.getByRole("menuitem", { name: "Log Out" }).click();
|
|
await expect(
|
|
page.getByRole("navigation").getByRole("link", { name: "Sign In" }),
|
|
).toBeVisible({ timeout: 5000 });
|
|
}
|