Comment tester la vérification d'email dans Playwright (Guide complet 2026)
End-to-end tests that involve email verification are notoriously fragile. You click "Register," an email gets sent, and now your test has to somehow read that email, extract a 6-digit code, and type it into a form — all in an automated, reproducible way. If you've tried to solve this before, you know the pain.
According to the 2024 World Quality Report by Capgemini, 41% of QA teams cite end-to-end test automation as their top challenge — with email verification flows ranked among the most frequently skipped tests in CI pipelines.
Source: Capgemini / Sogeti, World Quality Report 2024
Teams that skip email verification tests catch authentication regressions in production, where fixes cost 6× more.
Le problème des approches traditionnelles
Most teams encounter one of these dead ends when testing email flows:
- Shared test accounts (Gmail): Works locally, breaks in CI because Google detects bot logins. You also get OTP codes mixed across parallel test runs.
- Mailinator free plan: Public inboxes with no API access on the free tier. Any bot can read your test emails. Some services (including Amazon and Stripe) actively block Mailinator domains.
- Self-hosted MailHog / MailDev: Requires SMTP configuration changes in your app, doesn't work for third-party auth flows (OAuth providers send real emails), and adds infra overhead.
- Mocking the email entirely: You miss real template rendering bugs, broken links, and character encoding issues that only appear in actual emails.
- Ephemeral email services: No stable API, rate-limited, and domains change unpredictably — a recipe for flaky tests.
What you actually need is a private, API-accessible mailbox that you own, can create programmatically, and can poll reliably in test code.
A 2023 Sauce Labs testing survey found that 62% of development teams experience at least one CI/CD pipeline failure per week caused by flaky tests — email-dependent tests being disproportionately represented.
Source: Sauce Labs, State of Digital Quality Report 2023
Section 1 : Utiliser une vraie API de boîte mail pour les tests
The cleanest solution is to provision dedicated test mailboxes through an API before each test suite runs, use them during the test, and optionally clean them up afterward. GridInbox provides exactly this: a REST API to create mailboxes, list messages, and extract parsed OTP codes from incoming emails.
The key advantages over alternatives:
- Each test gets its own isolated inbox — no cross-contamination between parallel runs
- Inboxes are private (not publicly accessible like Mailinator)
- OTP codes are parsed server-side and returned in a structured JSON field
- Works with any email provider — the receiving infrastructure is real SMTP/SES
- Custom domains are supported — use your own
@test.yourdomain.com
Section 2 : Exemple Playwright complet
Let's walk through a full end-to-end test: register a new user, receive the verification email, extract the OTP, submit it, and assert the account is verified.
Étape 1 : Créer une boîte de réception de test via l'API
// helpers/email.ts
const API_BASE = 'https://api.gridinbox.com/api/v1';
const API_KEY = process.env.GRIDINBOX_API_KEY!;
export async function createTestInbox(label: string) {
const res = await fetch(`${API_BASE}/mailboxes`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': API_KEY,
},
body: JSON.stringify({ name: label }),
});
const data = await res.json();
// Returns { id, address, name, ... }
return data as { id: string; address: string };
}
Étape 2 : Interroger pour l'email OTP
export async function waitForOtp(
mailboxId: string,
options = { timeoutMs: 30_000, intervalMs: 2_000 }
): Promise<string> {
const deadline = Date.now() + options.timeoutMs;
while (Date.now() < deadline) {
const res = await fetch(`${API_BASE}/mailboxes/${mailboxId}/messages?limit=1`, {
headers: { 'X-API-Key': API_KEY },
});
const { messages } = await res.json();
if (messages?.length > 0) {
const msg = messages[0];
// GridInbox parses OTPs server-side
if (msg.otp) return msg.otp as string;
// Fallback: regex extraction from subject/text
const match = (msg.subject + ' ' + msg.text_body).match(/\b(\d{4,8})\b/);
if (match) return match[1];
}
await new Promise(r => setTimeout(r, options.intervalMs));
}
throw new Error(`OTP not received within ${options.timeoutMs}ms`);
}
Étape 3 : Test Playwright complet
// tests/auth/email-verification.spec.ts
import { test, expect } from '@playwright/test';
import { createTestInbox, waitForOtp } from '../helpers/email';
test('user can verify email after registration', async ({ page }) => {
// 1. Create a unique test inbox for this run
const inbox = await createTestInbox(`pw-test-${Date.now()}`);
const testEmail = inbox.address;
// 2. Register with the test email
await page.goto('/register');
await page.fill('[name="email"]', testEmail);
await page.fill('[name="password"]', 'TestPass123!');
await page.click('[type="submit"]');
// 3. Assert we're on the verification step
await expect(page.locator('text=Check your email')).toBeVisible();
// 4. Fetch the OTP from GridInbox API
const otp = await waitForOtp(inbox.id);
// 5. Fill in the OTP form
await page.fill('[name="otp"]', otp);
await page.click('[type="submit"]');
// 6. Assert success
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('text=Welcome')).toBeVisible();
});
Section 3 : Exécution en CI/CD
Add your API key as a repository secret in GitHub Actions and reference it in your workflow:
# .github/workflows/e2e.yml
name: E2E Tests
on: [push, pull_request]
jobs:
playwright:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npx playwright install --with-deps
- name: Run E2E tests
env:
GRIDINBOX_API_KEY: ${{ secrets.GRIDINBOX_API_KEY }}
run: npx playwright test
Because each test creates its own isolated inbox, parallel test execution works perfectly. Playwright's built-in sharding (--shard=1/4) will distribute tests across runners without any inbox collisions.
Section 4 : Bonnes pratiques
"The single most reliable pattern for email-dependent E2E tests is owning the inbox. Any solution that involves shared accounts, public disposable addresses, or mocking the SMTP layer will eventually create flaky tests that erode team confidence in the entire test suite."
- Name inboxes semantically: Use a prefix like
pw-{testName}-{timestamp}so you can identify which test a mailbox belongs to when debugging. - Set a polling timeout appropriate for your SES delivery speed: AWS SES typically delivers within 2–5 seconds. A 30-second timeout gives plenty of buffer. For slower SMTP relays, increase to 60 seconds.
- Clean up after yourself: Add a
test.afterAllhook that deletes test inboxes via the API. This keeps your GridInbox dashboard clean and avoids storage accumulation. - Use fixture-based inbox provisioning: Playwright fixtures let you share a single inbox across multiple tests in a file without re-creating it each time — a good pattern for "login once, test multiple pages" scenarios.
- Don't hardcode email addresses: Always generate unique addresses per run. Hardcoded addresses lead to race conditions when tests run concurrently in a CI matrix.
Conclusion
Email verification testing doesn't have to be the flaky, manual-intervention-required nightmare that most teams experience. With a real mailbox API, you can make email flows a first-class part of your Playwright test suite — deterministic, parallel-safe, and CI-ready.
The pattern described here — create inbox → trigger email → poll API → extract OTP → assert — works for any email-based flow: verification, password reset, magic links, notification emails, and more.
Commencez à tester les flux email dès aujourd'hui
Obtenez un compte GridInbox gratuit et commencez à créer des boîtes de réception de test isolées via l'API en quelques minutes. Aucune carte bancaire requise.
Créer un compte gratuit →