otpbox

OTPBox / Guides / Playwright

Playwright

Vérification d'e-mail avec Playwright

Un flux d'inscription qui se termine par "consultez votre e-mail pour le code" est difficile à tester de bout en bout, car le test a besoin d'une boîte de réception qui existe vraiment et reçoit vraiment du courrier. OTPBox donne à Playwright une adresse jetable réelle et un moyen d'attendre le code qu'elle reçoit — sans simuler le fournisseur d'e-mail, sans compte de test partagé sur lequel d'autres exécutions se percutent.

Le principe

Chaque approche ci-dessous suit les quatre mêmes étapes : créer une vraie boîte, utiliser son adresse dans le formulaire d'inscription, bloquer jusqu'à l'arrivée de l'OTP ou du lien de vérification, puis terminer le flux et nettoyer. Seule la quantité de code répétitif que vous écrivez vous-même change.

Option 1 : REST simple avec fetch

Aucune dépendance en dehors de Playwright. Générez une clé gratuite une fois (200 requêtes/mois, ou utilisez une clé d'organisation pour la CI — voir Obtenir une clé), puis appelez l'API directement dans le test :

import { test, expect } from '@playwright/test';

test('sign up with a real OTP', async ({ page }) => {
  const key = process.env.OTPBOX_KEY!;

  const inboxRes = await fetch('https://otpbox.io/api/v1/inboxes', {
    method: 'POST',
    headers: { authorization: `Bearer ${key}`, 'content-type': 'application/json' },
    body: '{}',
  });
  const inbox = await inboxRes.json(); // { id, address, domain, expiresAt, token }

  await page.goto('https://your-app.example.com/signup');
  await page.fill('[name="email"]', inbox.address);
  await page.click('button[type="submit"]');

  // Poll for the code (a real production test should back off / cap retries)
  let code: string | null = null;
  for (let i = 0; i < 15 && !code; i++) {
    await new Promise((r) => setTimeout(r, 1500));
    const msgs = await fetch(`https://otpbox.io/api/v1/inboxes/${inbox.id}/messages`, {
      headers: { authorization: `Bearer ${key}` },
    }).then((r) => r.json());
    code = msgs.messages[0]?.code ?? null;
  }

  await page.fill('[name="otp"]', code!);
  await page.click('button[type="submit"]');
  await expect(page.locator('text=Welcome')).toBeVisible();

  await fetch(`https://otpbox.io/api/v1/inboxes/${inbox.id}`, {
    method: 'DELETE',
    headers: { authorization: `Bearer ${key}` },
  });
});

Option 2 : otpbox-sdk (recommandé)

otpbox-sdk est le client TypeScript officiel, publié sur npm, qui supprime la boucle de polling manuelle grâce à waitForOtp() :

npm install otpbox-sdk
import { test, expect } from '@playwright/test';
import { OTPBox } from 'otpbox-sdk';

test('sign up with a real OTP', async ({ page }) => {
  const client = new OTPBox({ apiKey: process.env.OTPBOX_KEY! });
  const inbox = await client.createInbox();

  try {
    await page.goto('https://your-app.example.com/signup');
    await page.fill('[name="email"]', inbox.address);
    await page.click('button[type="submit"]');

    const code = await client.waitForOtp(inbox.id, { timeoutMs: 20_000 });
    await page.fill('[name="otp"]', code!);
    await page.click('button[type="submit"]');
    await expect(page.locator('text=Welcome')).toBeVisible();
  } finally {
    await client.deleteInbox(inbox.id);
  }
});

waitForOtp() interroge getMessages() jusqu'à ce qu'un message reçu après le début de l'appel ait un code extrait, ou jusqu'à expiration du délai (renvoie null en cas de timeout — code! ci-dessus convient une fois que vous l'avez vérifié dans votre propre test, mais vérifiez null en conditions réelles). Il existe aussi waitForEmail() pour récupérer le message entier, et getUsage() si une suite veut s'assurer qu'elle n'a pas épuisé son quota.

Option 3 : fixture otpbox-playwright (en cours)

Un package Playwright dédié, otpbox-playwright, enveloppe otpbox-sdk dans une fixture test personnalisée, si bien qu'une spec n'a même pas à appeler elle-même createInbox()/deleteInbox() :

import { test, expect } from 'otpbox-playwright';

test('sign up with a real OTP', async ({ page, otpboxInbox }) => {
  await page.goto('https://your-app.example.com/signup');
  await page.fill('[name="email"]', otpboxInbox.address);
  await page.click('button[type="submit"]');

  const code = await otpboxInbox.waitForOtp();
  await page.fill('[name="otp"]', code);
  await page.click('button[type="submit"]');
  await expect(page.locator('text=Welcome')).toBeVisible();
  // no inbox.delete() to write - the fixture tears it down for you
});
Statut : otpbox-playwright n'est pas encore publié sur npm. C'est du code réel et fonctionnel dans le même monorepo que otpbox-sdk, mais tant qu'il n'est pas publié comme package, vous l'installeriez via npm link sur un clone du dépôt plutôt que via npm install otpbox-playwright. En attendant, l'option 2 (otpbox-sdk directement) est la voie prise en charge et offre le même comportement waitForOtp()/waitForVerificationLink() avec quelques lignes de configuration en plus.

Vérifier via un lien plutôt qu'un code

Certains flux d'inscription envoient un lien de confirmation plutôt qu'un code à 6 chiffres. La même boîte fonctionne — utilisez waitForEmail() et lisez message.link (ou, avec otpbox-sdk, récupérez le message complet via getMessage(messageId) pour obtenir link.url) :

const message = await client.waitForEmail(inbox.id, { timeoutMs: 20_000 });
const full = await client.getMessage(message!.id);
await page.goto(full.link!.url);
await expect(page.locator('text=Verified')).toBeVisible();

Notes pour la CI

Étapes suivantes

Prêt à l'essayer sur votre propre application ? Créer un compte gratuit

← Retour à OTPBox