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 :
- 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. - L'identifiant de votre inbox, les huit caractères qui précèdent
.inboxdans son adresse de réception. Il vautj3k9x2mqdans 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.