Skip to content

Playwright

Setup

Install the MailOven client:

sh
npm install -D @mailoven/client
sh
yarn add -D @mailoven/client
sh
pnpm add -D @mailoven/client
sh
bun add -D @mailoven/client
sh
deno add -D npm:@mailoven/client

Example: using the client in the tests

typescript
// tests/password-reset.spec.ts
import { test, expect } from "@playwright/test";
import { MailOvenClient } from "@mailoven/client";

const mailoven = new MailOvenClient({
  apiKey: process.env.MAILOVEN_API_KEY!,
  slug: "acme",
});

test("password reset sends email with reset link", async ({ page }) => {
  const inbox = "reset-test";
  await mailoven.deleteInbox(inbox);

  await page.goto("/forgot-password");
  await page.locator('input[name="email"]').fill(mailoven.getEmailAddress(inbox));
  await page.getByRole("button", { name: "Send reset link" }).click();

  const email = await mailoven.waitForEmail({
    to: inbox,
    filter: { subject: "Reset your password" },
  });

  const resetLink = email.bodyText?.match(/https?:\/\/\S*reset\S*/)?.[0];
  expect(resetLink).toBeTruthy();

  await page.goto(resetLink!);
  await expect(page.locator("h1")).toContainText("Reset");
});

Example: screenshot an email in the MailOven UI

The MailOven web UI supports API key authentication via the Authorization header, so you can open any email's rendered view directly in Playwright and take a screenshot — useful for visual regression tests on email templates.

typescript
// tests/email-screenshot.spec.ts
import { test, expect } from "@playwright/test";
import { MailOvenClient } from "@mailoven/client";

const API_KEY = process.env.MAILOVEN_API_KEY!;

const mailoven = new MailOvenClient({ apiKey: API_KEY, slug: "acme" });

test("welcome email matches screenshot", async ({ browser }) => {
  const inbox = "screenshot-test";
  await mailoven.deleteInbox(inbox);

  // Trigger your app to send the email
  await fetch("http://localhost:3000/api/signup", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email: mailoven.getEmailAddress(inbox) }),
  });

  const email = await mailoven.waitForEmail({
    to: inbox,
    filter: { subject: "Welcome" },
  });

  // Open a browser context with the API key header
  const context = await browser.newContext({
    extraHTTPHeaders: {
      Authorization: `Bearer ${API_KEY}`,
    },
  });
  const page = await context.newPage();

  await page.goto(`${mailoven.getInboxEndpoint(inbox)}/${email.id}`);

  await expect(page).toHaveScreenshot("welcome-email.png");

  await context.close();
});
bash
MAILOVEN_API_KEY=mo_your_api_key

Fixture-based approach

For cleaner tests, wrap the client in a Playwright fixture:

typescript
// tests/fixtures.ts
import { test as base } from "@playwright/test";
import { MailOvenClient } from "@mailoven/client";

type MailOvenFixtures = {
  mailoven: {
    client: MailOvenClient;
    uniqueInbox: () => string;
  };
};

export const test = base.extend<MailOvenFixtures>({
  mailoven: async ({}, use) => {
    const client = new MailOvenClient({
      apiKey: process.env.MAILOVEN_API_KEY!,
      slug: "acme",
    });
    const inboxes: string[] = [];

    const uniqueInbox = () => {
      const name = `test-${crypto.randomUUID().slice(0, 8)}`;
      inboxes.push(name);
      return name;
    };

    await use({ client, uniqueInbox });

    // Clean up all inboxes used in the test
    await Promise.all(inboxes.map((inbox) => client.deleteInbox(inbox)));
  },
});

export { expect } from "@playwright/test";
typescript
// tests/example.spec.ts
import { test, expect } from "./fixtures";

test("signup sends verification email", async ({ page, mailoven }) => {
  const inbox = mailoven.uniqueInbox();

  await page.goto("/signup");
  await page.locator('input[name="email"]').fill(mailoven.client.getEmailAddress(inbox));
  // ... rest of test

  const email = await mailoven.client.waitForEmail({
    to: inbox,
    filter: { subject: "Verify" },
  });
  expect(email.subject).toContain("Verify");
});

Disposable email inboxes for every teams