passkeys-firefox.spec.ts
1/**2 * passkeys-firefox.spec.ts — Firefox content-script proxy E2E suite.3 *4 * The MAIN-world monkey-patch only runs under Firefox with a real Gecko5 * credentials API to delegate to. Playwright's bundled chromium runner cannot6 * exercise it. To run this suite, build with `npm run build:firefox` and7 * launch via `web-ext run --target=firefox-desktop --source-dir=dist-firefox`,8 * then drive Firefox with playwright's `firefox` browser type plus the9 * preferences below to load the temporary add-on. Until that harness lands10 * in CI the suite is gated by PEACH_E2E_FIREFOX_PASSKEYS=1, so the default11 * `npx playwright test` run skips it cleanly.12 *13 * The list below is the verification matrix from the v2.12.0 spec. Each14 * item maps to a manual smoke-test step on a real RP (github.com,15 * webauthn.io, google.com account settings).16 */1718import { test } from "@playwright/test";1920const ENABLED = process.env.PEACH_E2E_FIREFOX_PASSKEYS === "1";21const skip = ENABLED ? test : test.skip;2223test.describe("Firefox passkey content-script proxy (MAIN world)", () => {24 // 1. navigator.credentials.create is replaced on document_start.25 skip("navigator.credentials.create is replaced on page load (MAIN world)", async () => {});2627 // 2. navigator.credentials.get is replaced on document_start.28 skip("navigator.credentials.get is replaced on page load (MAIN world)", async () => {});2930 // 3. Registration: approval UI appears, vault gets a passkey entry with31 // privateKeyJwk and browser:'firefox'.32 skip("registration: approval UI appears, passkey stored in vault", async () => {});3334 // 4. Authentication: approval UI appears, RP receives a valid assertion.35 skip("authentication: approval UI appears, assertion returned", async () => {});3637 // 5. clientDataJSON.origin equals the page origin in both responses.38 skip("clientDataJSON.origin equals the page origin in both responses", async () => {});3940 // 6. clientDataJSON.origin must NEVER contain `moz-extension://`.41 skip("clientDataJSON.origin does not contain moz-extension://", async () => {});4243 // 7. signCount strictly increments across two consecutive get ceremonies.44 skip("signCount increments between two authentication ceremonies", async () => {});4546 // 8. user_cancelled: page receives DOMException with name 'NotAllowedError'.47 skip("user_cancelled: DOMException with NotAllowedError name thrown", async () => {});4849 // 9. Non-publicKey credentials.create requests fall through to the50 // platform unchanged (PasswordCredential, FederatedCredential).51 skip("non-passkey credentials.create falls through to original", async () => {});5253 // 10. Non-publicKey credentials.get falls through.54 skip("non-passkey credentials.get falls through to original", async () => {});5556 // 11. No passkey for rpId: PASSKEY_HAS_CREDENTIALS returns false → fall57 // through to the platform authenticator. No Peach UI appears.58 skip("no passkey for rpId: falls through to platform authenticator", async () => {});5960 // 12. Free tier: pro_required fires; page-side dispatches61 // 'peach:passkey-pro-gate' event; ceremony falls through to platform.62 skip("free tier: pro gate fires, falls through to platform", async () => {});6364 // 13. Round-trip: register passkey → authenticate → vault entry's65 // signCount and lastUsedAt update.66 skip("round-trip: register passkey then authenticate updates vault entry", async () => {});67});