# 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.
> https://facteur.eu/aide/tests-cypress

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.

## Avant de commencer

Deux choses, et rien d'autre :

1. **Une clé d'API en lecture seule.** Créez-la dans
   [**Réglages → Clés d'API**](https://app.facteur.eu/settings/api-keys) et mettez-la
   dans les secrets de votre intégration continue, sous `FACTEUR_API_KEY`. Voir
   [Clés d'API](cles-api).
2. **L'identifiant de votre inbox**, les huit caractères affichés en haut de la vue
   inbox. Il vaut `j3k9x2mq` dans les exemples qui suivent.

## La configuration, où la clé peut rester

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

export default defineConfig({
  e2e: {
    setupNodeEvents(on) {
      on('task', {
        async attendreEmail({ sentTo }) {
          const response = await fetch('https://api.facteur.eu/v1/messages/search', {
            method: 'POST',
            headers: {
              authorization: 'Bearer ' + process.env.FACTEUR_API_KEY,
              'content-type': 'application/json',
            },
            body: JSON.stringify({ inbox: 'j3k9x2mq', sentTo, wait: 30000 }),
          });
          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

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

  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 un plan qui inclut une seule inbox,
c'est la différence entre une suite qui tourne et une suite qui bute sur un plafond.

## Installer le greffon Cypress

Le greffon tient la clé d'API hors du navigateur et rend des commandes chaînables, ce que
la version ci-dessus fait à la main en une trentaine de lignes.

1. Installez-le : `npm i -D cypress-facteur`.
2. Créez une clé dans **Réglages → Clés d'API**, et posez-la en `FACTEUR_API_KEY` dans
   l'environnement de votre chaîne d'intégration.
3. Dans `cypress.config.js`, passez `setupNodeEvents` à `facteurTasks`, importé depuis
   `cypress-facteur/plugin`.
4. Dans `cypress/support/e2e.js`, ajoutez `import 'cypress-facteur'`.

Vos tests disposent alors de `cy.facteurAddress()` et `cy.facteurWaitFor()`. La version
ci-dessus continue de fonctionner sans rien installer.

L'état de chaque intégration est sur la page [Intégrations](https://facteur.eu/integrations).
