import { expect } from "@playwright/test"; import { test } from "../fixtures"; import { registerAndLogin } from "../helpers"; /** * Enables a virtual WebAuthn authenticator on the given context so the browser * can complete passkey ceremonies without a real device. */ async function enableVirtualAuthenticator(context: any) { const cdp = await context.newCDPSession(context.pages()[0]); await cdp.send("WebAuthn.enable", { enableUI: false }); await cdp.send("WebAuthn.addVirtualAuthenticator", { options: { protocol: "ctap2", transport: "internal", hasResidentKey: true, hasUserVerification: true, isUserVerified: true, }, }); } test("a user can register a passkey and sign in with it", async ({ page, browser, server }) => { const context = await browser.newContext({ baseURL: server.baseURL }); const p = await context.newPage(); await enableVirtualAuthenticator(context); // Register with a password first. await registerAndLogin(p, "alice@example.com"); // Add a passkey from the account page. await p.goto("/account"); await p.click("#add-passkey"); await expect(p.locator(".passkey-row")).toHaveCount(1); // Log out. await p.click('button:has-text("Sign out")'); await expect(p).toHaveURL(/\/login/); // Sign in with the passkey. await p.fill("#email", "alice@example.com"); await p.click("#passkey-login"); await expect(p).toHaveURL(/\/lists/); await context.close(); });