Mailwurf

Playwright

Create an inbox, let the app send normally, wait, then follow the link.

Playwright consumes @mailwurf/e2e. It is not a dependency of the client.

The app under test keeps its production sender. The test only sets the recipient to inbox.address.

import { expect, test } from "@playwright/test";
import { createClient } from "@mailwurf/e2e";

const mailwurf = createClient(); // MAILWURF_API_KEY, API at https://api.mailwurf.io

test("confirms signup from the inbox", async ({ page }) => {
  const inbox = await mailwurf.createInbox();

  await page.goto(process.env.APP_URL ?? "http://localhost:3000/signup");
  await page.getByLabel("Email").fill(inbox.address);
  await page.getByRole("button", { name: "Sign up" }).click();

  const mail = await inbox.waitFor({ subject: "Confirm", timeout: 15_000 });
  const link = mail.links[0];
  expect(link).toBeTruthy();
  if (!link) {
    throw new Error("confirm mail had no link");
  }

  await page.goto(link);
  await expect(page.getByText("confirmed")).toBeVisible();
});

CI needs MAILWURF_API_KEY and the app origin. Set MAILWURF_URL only for a Mailwurf origin other than https://api.mailwurf.io. Optional: await inbox.delete() when the test finishes. Temporary inboxes also expire on their own.