Playwright
This guide walks a Playwright test through a signup that sends a verification email, then a login that asks for a two-factor code.
npm install --save-dev @mailcatchr/sdkPut the key and mailbox id in the environment. Never in the test file.
export MAILCATCHR_API_KEY=mc_live_…export MAILCATCHR_MAILBOX_ID=01J…A helper module
Section titled “A helper module”import { createClient } from "@mailcatchr/sdk";
export const mc = createClient({ apiKey: process.env.MAILCATCHR_API_KEY! });export const mailboxId = process.env.MAILCATCHR_MAILBOX_ID!;
/** A fresh address for this test run so parallel tests never see each other's mail. */export function uniqueAddress(label: string): string { return `${label}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}@acme-ci.mailcatchr.com`;}
/** Waits for a message to `to`, then returns the full message. */export async function waitForMail(to: string, subject?: string) { const summary = await mc.messages.await(mailboxId, { to, subject, timeoutSeconds: 30 }); if (!summary) throw new Error(`No email to ${to} within 30 s`); return mc.messages.get(mailboxId, summary.id);}Signup with email verification
Section titled “Signup with email verification”import { expect, test } from "@playwright/test";import { uniqueAddress, waitForMail } from "./helpers/mail";
test("signup sends a verification link that works", async ({ page }) => { const email = uniqueAddress("signup");
await page.goto("/signup"); await page.fill('input[name="email"]', email); await page.fill('input[name="password"]', "correct horse battery staple"); await page.click('button[type="submit"]');
const message = await waitForMail(email, "Verify your email"); const link = message.textBody?.match(/https:\/\/\S+\/verify\?token=\S+/)?.[0]; expect(link, "verification link in the email body").toBeTruthy();
await page.goto(link!); await expect(page.getByText("Email verified")).toBeVisible();});Login with a two-factor code
Section titled “Login with a two-factor code”Register the account’s authenticator once under Tools → Authenticators and put its id in MAILCATCHR_TOTP_ID.
test("login completes with a TOTP code", async ({ page }) => { await page.goto("/login"); await page.fill('input[name="email"]', "2fa-user@acme-ci.mailcatchr.com"); await page.fill('input[name="password"]', process.env.TEST_USER_PASSWORD!); await page.click('button[type="submit"]');
const totp = await mc.totps.code(process.env.MAILCATCHR_TOTP_ID!); await page.fill('input[name="otp"]', totp.code); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/dashboard/);});- Filter on
towith a unique address rather than on subject alone. Parallel workers then never pick up each other’s mail. - Keep
timeoutSecondsat 30. If the email regularly takes longer, the thing to fix is the sender. - Playwright’s own
expect.pollis not needed;awaitalready blocks server-side.