Aller au contenu
Facteur

Tapez au moins deux caractères.

Recevoir un email dans un test Playwright

Le test complet qui attend un email, lit le code qu'il contient et poursuit le parcours, sans sleep. Le plugin Playwright n'est pas encore publié.

Un parcours d'inscription se termine dans une boîte mail, et votre test doit lire ce qui y arrive. Voici le fichier entier. Il appelle l'API directement avec une clé : le plugin Playwright de Facteur n'est pas encore publié, donc il n'y a aucun paquet à installer, et celui-ci n'en a pas besoin.

Avant de commencer

Deux choses, et rien d'autre :

  1. Une clé d'API en lecture seule. Créez-la dans Paramètres → Clés d'API et mettez-la dans les secrets de votre intégration continue, sous FACTEUR_API_KEY. Le test ci-dessous ne crée rien : il lit. Voir Clés d'API.
  2. L'identifiant de votre inbox, les huit caractères qui précèdent .inbox dans son adresse de réception.
import { expect, test } from '@playwright/test';

const KEY = process.env.FACTEUR_API_KEY!;
const INBOX = 'j3k9x2mq';

/** Reste ouvert jusqu'à l'arrivée du message, vingt secondes au plus. */
const attendre = async (sentTo: string) => {
  const search = new URLSearchParams({ inbox: INBOX, sentTo, wait: '20000' });
  const response = await fetch(`https://api.facteur.eu/v1/messages?${search}`, {
    headers: { authorization: `Bearer ${KEY}` },
  });
  if (!response.ok) throw new Error(`Facteur a répondu ${response.status}`);

  return response.json();
};

test('le lien de vérification active le compte', async ({ page }) => {
  const tag = `run-${Date.now()}`;

  // Lancée avant le clic : elle répond dès que l'email arrive.
  const arrive = attendre(`inscription+${tag}`);

  // Le parcours d'inscription de VOTRE application.
  await page.goto('/inscription');
  await page.getByLabel('Email').fill(`inscription+${tag}@${INBOX}.inbox.facteur.eu`);
  await page.getByRole('button', { name: 'Créer mon compte' }).click();

  const { messages } = await arrive;
  expect(messages[0].status).toBe('parsed');
  await page.goto(messages[0].links[0]);

  await expect(page.getByText('Compte vérifié')).toBeVisible();
});

Lancez l'attente avant l'action

C'est la seule ligne dont l'ordre compte. La requête part avant le clic, reste ouverte, et répond à l'instant où l'email arrive. Lancée après, elle courrait après un message peut-être déjà traité, et vous verriez ce défaut le jour où votre intégration continue devient lente.

Une adresse par test, sans rien créer

Toute adresse qui finit par le domaine de votre inbox y arrive. Vous n'avez donc pas d'appel à faire pour créer inscription+run-1734@j3k9x2mq.inbox.facteur.eu : il suffit de l'écrire. C'est ce qui permet à seize tests parallèles de partager une inbox sans se voler leurs emails. Une organisation peut garder vingt attentes ouvertes à la fois : au-delà, la réponse est 429 TOO_MANY_WAITS.

Mettez le nom du test et le numéro de tentative dans l'étiquette. Sans le numéro, un test rejoué relit l'email de sa première tentative et passe pour une mauvaise raison, précisément quand quelque chose est déjà instable.

Lisez status avant tout le reste

Un email accepté existe avant d'être analysé. Pendant quelques millisecondes il n'a ni sujet, ni code, ni liens. Le champ status sépare « il n'y a pas de code dans ce message » de « le code n'est pas encore extrait ». La recherche ne rend que des messages analysés par défaut, donc le cas ne se présente que si vous demandez status: any.

Le code est déjà sorti du message

messages[0].otp porte le code à usage unique, extrait à la réception. Vous n'écrivez aucune expression régulière, et vous n'avez rien à corriger le jour où le gabarit d'email change.

Les liens sont là aussi : messages[0].links en porte la liste, dans l'ordre où ils apparaissent, chacun sous forme de texte. Passez-en un directement à page.goto().

Le plugin Playwright

Un plugin est prévu : il écrirait à votre place l'adresse de chaque test et l'attente du message. Il n'est pas encore publié et nous n'annonçons pas de date. Le test ci-dessus continuera de fonctionner le jour où il sortira.