Aller au contenu
Facteur

Tapez au moins deux caractères.

Recevoir un email dans un test Cypress

Une tâche Node qui garde la clé hors du navigateur, et un test qui attend l'email au lieu de patienter un nombre de secondes fixe. Le plugin Cypress n'est pas encore publié.

Cypress exécute votre test dans le navigateur, ce qui pose deux problèmes pour lire un email : votre clé d'API n'a rien à faire dans une page, et l'appel réseau répond à l'origine du site testé. Une tâche Node règle les deux d'un coup.

Cette page appelle l'API directement. Le plugin Cypress de Facteur n'est pas encore publié : il n'y a aucun paquet à installer.

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. 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. Il vaut j3k9x2mq dans les exemples qui suivent.

La configuration, où la clé peut rester

// cypress.config.js
import { defineConfig } from 'cypress';

export default defineConfig({
  e2e: {
    setupNodeEvents(on) {
      on('task', {
        async attendreEmail({ sentTo }) {
          const search = new URLSearchParams({ inbox: 'j3k9x2mq', sentTo, wait: '30000' });
          const response = await fetch('https://api.facteur.eu/v1/messages?' + search, {
            headers: { authorization: 'Bearer ' + process.env.FACTEUR_API_KEY },
          });
          if (!response.ok) throw new Error('Facteur a répondu ' + response.status);

          const { messages } = await response.json();
          return messages[0] ?? null;
        },
      });
    },
  },
});

Ce fichier tourne dans le processus Cypress, pas dans la page. La clé y est lue depuis l'environnement et n'atteint jamais le navigateur.

Le test

it('le code arrive par email', () => {
  const tag = 'inscription-a' + (Cypress.currentRetry ?? 0) + '-' + Date.now();

  // Le parcours d'inscription de VOTRE application.
  cy.visit('/inscription');
  cy.get('[name=email]').type(tag + '@j3k9x2mq.inbox.facteur.eu');
  cy.contains('button', 'Créer mon compte').click();

  cy.task('attendreEmail', { sentTo: tag }, { timeout: 40000 }).should((message) => {
    expect(message, "aucun email n'est arrivé").to.not.be.null;
    expect(message.otp).to.match(/^[0-9]{6}$/);
  });
});

Pourquoi il n'y a pas de cy.wait

L'attente se fait chez nous : la requête reste ouverte jusqu'à l'arrivée du message, avec un délai maximum que vous fixez. Une pause fixe est soit trop courte sur une machine chargée, soit du temps perdu à chaque exécution.

Le timeout passé à cy.task doit rester au-dessus du wait envoyé à l'API : quarante secondes pour une attente de trente, faute de quoi Cypress abandonne la tâche avant que la réponse n'arrive, et l'échec accuse le mauvais coupable.

Le numéro de tentative dans l'adresse

Cypress.currentRetry vaut 0 au premier essai. Sans lui, 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.

Une inbox suffit pour toute la suite

Toute adresse finissant par le domaine de l'inbox y arrive, sans rien créer. Chaque test reçoit donc à son adresse dans la même inbox. Sur une offre qui n'inclut qu'une inbox, c'est la différence entre une suite qui tourne et une suite qui bute sur un plafond.

Le plugin Cypress

Un plugin est prévu : il garderait la clé hors du navigateur et rendrait des commandes chaînables, ce que la configuration ci-dessus fait à la main. Il n'est pas encore publié et nous n'annonçons pas de date. Cette configuration continuera de fonctionner le jour où il sortira.