Complete Playwright examples for email testing with Mailoverse. Learn to test signup flows, email verification, password reset, and MFA with custom fixtures and helper functions.

Playwright

Complete examples for testing email flows with Playwright, including signup verification, password reset, and custom fixtures.

Helper Functions

Create a helper file to generate test emails and wait for them to arrive:

// tests/helpers/mailoverse.ts
import { Page } from '@playwright/test';

const MAILOVERSE_API_KEY = process.env.MAILOVERSE_API_KEY!;
const MAILOVERSE_DOMAIN = process.env.MAILOVERSE_DOMAIN!;

export function generateTestEmail(prefix = 'test') {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2)}@${MAILOVERSE_DOMAIN}`;
}

export async function waitForEmail(
  page: Page,
  address: string,
  options: { timeout?: number; interval?: number } = {}
) {
  const { timeout = 30000, interval = 1000 } = options;
  const startTime = Date.now();

  while (Date.now() - startTime < timeout) {
    const response = await page.request.get(
      `https://api.mailoverse.com/email?address=${encodeURIComponent(address)}`,
      {
        headers: { 'Authorization': `Bearer ${MAILOVERSE_API_KEY}` },
      }
    );

    const data = await response.json();
    if (data.email) {
      return data.email;
    }

    await page.waitForTimeout(interval);
  }

  throw new Error(`Timeout waiting for email to ${address}`);
}

Signup Test

Using the helper in a signup flow test:

// tests/signup.spec.ts
import { test, expect } from '@playwright/test';
import { generateTestEmail, waitForEmail } from './helpers/mailoverse';

test('user can sign up and verify email', async ({ page }) => {
  const testEmail = generateTestEmail('signup');

  // Complete signup flow
  await page.goto('/signup');
  await page.fill('[name="email"]', testEmail);
  await page.fill('[name="password"]', 'SecurePass123!');
  await page.click('button[type="submit"]');

  // Wait for verification email
  const email = await waitForEmail(page, testEmail);

  expect(email.subject).toContain('Verify');
  expect(email.parsedHtml.links).toHaveLength(1);

  // Click the verification link
  const verifyLink = email.parsedHtml.links.find(
    (link: { href: string }) => link.href.includes('/verify')
  );
  expect(verifyLink).toBeDefined();

  await page.goto(verifyLink.href);
  await expect(page.locator('h1')).toContainText('Email Verified');
});

Password Reset Test

Testing a complete password reset flow:

test('user can reset password', async ({ page }) => {
  const testEmail = generateTestEmail('reset');

  // Create account first
  await page.goto('/signup');
  await page.fill('[name="email"]', testEmail);
  await page.fill('[name="password"]', 'OldPassword123!');
  await page.click('button[type="submit"]');

  // Wait for signup email and verify
  const signupEmail = await waitForEmail(page, testEmail);
  const verifyLink = signupEmail.parsedHtml.links[0];
  await page.goto(verifyLink.href);

  // Now request password reset
  await page.goto('/forgot-password');
  await page.fill('[name="email"]', testEmail);
  await page.click('button[type="submit"]');

  // Wait for reset email
  const resetEmail = await waitForEmail(page, testEmail);
  expect(resetEmail.subject).toContain('Reset');

  const resetLink = resetEmail.parsedHtml.links.find(
    (link: { href: string }) => link.href.includes('/reset-password')
  );

  // Complete password reset
  await page.goto(resetLink.href);
  await page.fill('[name="password"]', 'NewPassword456!');
  await page.fill('[name="confirmPassword"]', 'NewPassword456!');
  await page.click('button[type="submit"]');

  await expect(page.locator('h1')).toContainText('Password Updated');
});

Custom Fixtures

For cleaner tests, create custom Playwright fixtures:

// tests/fixtures.ts
import { test as base } from '@playwright/test';
import { generateTestEmail, waitForEmail } from './helpers/mailoverse';

type MailoverseFixtures = {
  testEmail: string;
  getEmail: () => Promise<any>;
};

export const test = base.extend<MailoverseFixtures>({
  testEmail: async ({}, use) => {
    const email = generateTestEmail();
    await use(email);
  },
  getEmail: async ({ page, testEmail }, use) => {
    await use(async () => {
      return await waitForEmail(page, testEmail);
    });
  },
});

export { expect } from '@playwright/test';

// Usage in tests:
// tests/signup.spec.ts
import { test, expect } from './fixtures';

test('signup flow', async ({ page, testEmail, getEmail }) => {
  await page.goto('/signup');
  await page.fill('[name="email"]', testEmail);
  await page.fill('[name="password"]', 'Test123!');
  await page.click('button[type="submit"]');

  const email = await getEmail();
  expect(email.subject).toContain('Verify');
});

See Also