Playwrightbeginner

TypeScript SDK + Playwright E2E Test

Test OTP verification with Plop TypeScript SDK and Playwright

TypeScript SDK + Playwright E2E Test (typescript)typescript
import { test, expect } from '@playwright/test';
import { Plop } from '@plop-email/sdk';

const plop = new Plop({ apiKey: process.env.PLOP_API_KEY });

test.describe('OTP Verification', () => {
  test('login with OTP code', async ({ page }) => {
    const tag = `otp-${Date.now()}`;
    const testEmail = `qa+${tag}@in.plop.email`;

    // Start login flow
    await page.goto('/login');
    await page.fill('[name="email"]', testEmail);
    await page.click('button[type="submit"]');

    // Wait for OTP email — replaces manual polling
    const message = await plop.waitFor({
      mailbox: 'qa',
      tag,
      timeout: 15_000,
    });

    // Extract 6-digit OTP code
    const otp = message.textContent?.match(/\b\d{6}\b/)?.[0];
    expect(otp).toBeTruthy();

    // Enter OTP and verify login
    await page.fill('[data-testid="otp-input"]', otp!);
    await page.click('button[type="submit"]');
    await expect(page.locator('text=Dashboard')).toBeVisible();
  });

  test('magic link authentication', async ({ page }) => {
    const tag = `magic-${Date.now()}`;
    const testEmail = `qa+${tag}@in.plop.email`;

    // Request magic link
    await page.goto('/login');
    await page.fill('[name="email"]', testEmail);
    await page.click('text=Send Magic Link');

    // Wait for magic link email
    const message = await plop.waitFor({
      mailbox: 'qa',
      tag,
      timeout: 15_000,
    });

    // Extract and navigate to magic link
    const linkMatch = message.htmlContent?.match(/href="([^"]*magic[^"]*)"/);
    expect(linkMatch).toBeTruthy();

    await page.goto(linkMatch![1]);
    await expect(page.locator('text=Dashboard')).toBeVisible();
  });
});

How It Works

1

SDK vs Raw API

The Plop SDK replaces manual fetch + polling loops with a single waitFor() call. No need to write retry logic or handle HTTP headers.

2

Tag-based Isolation

Each test uses a unique tag with Date.now() so tests can run in parallel without interfering with each other.

3

Typed Responses

The SDK returns typed Message objects with autocomplete for subject, textContent, htmlContent, and other fields.

4

Timeout Handling

waitFor() throws a clear error if the email does not arrive within the timeout, making test failures easy to diagnose.

Try This Example

Get a free API key and test this example in minutes.