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