Les tests "end-to-end" sont un peu l'arlésienne des tests... En théorie, le principe est surpuissant. Dans la pratique, les outils existants sont souvent lourds, les tests lents et leur écriture complexe et difficile à maintenir. Dans cet article, nous allons expliquer à quoi correspondent les tests E2E, un peu d'historique mais surtout aborder les avantages de Playwright qui révolutionne le marché.
Tests End-to-End (ou E2E) : à quoi servent-ils ?
En opposition aux tests unitaires, qui visent à s'assurer que le code préalablement écrit en backend est toujours conforme et que le "nouveau" code ne crée pas de régression, il s'agit pour les tests E2E de parcours des chemins critiques en utilisant un navigateur comme un vrai utilisateur le ferait.
Par ce biais, il est possible de détecter des erreurs tant en backend (une valeur inattendue nous est retournée par l'API par exemple) qu'en frontend (une erreur qui s'affiche alors qu'elle ne devrait pas par exemple) et ce, sur tout un parcours pré-défini.
Mieux : il est possible de faire des captures d'écran et vidéo, analyser le code généré et les performances, et ce, à de chacune des étapes. En plus, il est possible de lancer plusieurs tests en même temps, sur des navigateurs différents.
Chez Web^ID, nous préconisons de mettre en place les tests end-to-end notamment dans le cadre de reprise de projet (qui sont malheureusement souvent développés sans tests... du tout). En effet, ils constituent un moyen simple de s'assurer a minima que les parcours critiques fonctionnent toujours correctement, sur un code que nous n'avons pas créé.
L'histoire des tests end-to-end
Il fut un temps où nous utilisions une armée de testeurs pour effectuer des tests manuels en permanence. Évidemment, c'est non seulement extrêmement couteux, mais aussi très peu fiables puisqu'il est impossible de reproduire tous les parcours (et sur tous les navigateurs...). Les interfaces et applications se complexifiant sans cesse, c'était difficilement tenable.
Selenium : le premier outil Open Source à rendre les tests end-to-end une réalité
Selenium est certes un élément chimique, mais aussi le premier outil de tests "end-to-end" digne de ce nom. Il peut être utilisé avec un grand nombre de langages et prend en charge la plupart des navigateurs. Cependant, il souffre d'une complexité d'écriture des tests et de leur maintenance. En plus, les tests sont lents et il n'est pas réellement possible de les mettre en place dans le cadre de déploiements continus.
Puppeteer : dans la vibe du JS
Google a lancé Puppeteer avec objectif d'utiliser JavaScript pour guider les navigateurs (seulement sur Chromium... super !). On comprend bien le jeu de mots à base de "Puppet". Par contre, en termes de performance, on n'y est pas. Puppeteer fait tourner un navigateur en arrière-plan, ce qui implique quelques effets de bord sur la scalabilité de la solution. Ceci dit, nous l'utilisons parfois pour générer des PDF à partir de pages HTML simple (c'est une utilisation détournée de Puppeteer). Nous l'utilisons aussi pour aider les robots d'indexation à avoir une page HTML statique pour l'analyse, ce qui est un équivalent du SSR sur une codebase qui ne le supporte pas initialement.
Cypress : l'outil le plus avancé (jusque-là !)
Cypress a apporté une vraie différence en termes de performance, mais aussi de simplicité d'écriture des tests et de leur maintenance. Mais là encore, il souffre d'un défaut de taille : il ne fonctionne que sous Chromium. Fichtre.
Playwright : des atouts qui font la différence.
Vous l'aurez deviné, Playwright permet des tests E2E sur la plupart des navigateurs (Chrome, Firefox, Safari et Edge). Et ça, c'est beau. Comme un "vrai" utilisateurs, il peut se connecter à un compte, ouvrir différents onglets et naviguer dans un environnement qui lui est dédié.
En plus, Playwright donne la possibilité de faire des tests en "multi thread" et donc en parallèle les uns des autres. Un vrai gain de temps en performance !
Cerise sur le gâteau : Playwright gère très bien les attentes d'action pour interagir sur les éléments d'interactions, comme le ferait un utilisateur humain de façon intuitive (on dit qu'il est moins "Flaky").
Il vient avec un système de persistance de session entre les différents scenarios de test qui rend son utilisation beaucoup plus simple est rapide. Là, où tous ses concurrents n'avaient pas anticipé la problématique et ne propose que des contournements.
L'installation est très simple, la syntaxe est simple, le code est en TypeScript... la phase d'apprentissage est très rapide.
De plus, il vient avec un outil de "codegen". Son but est d'ouvrir un navigateur sur une url précise, de faire son scenario en tant qu'humain et il génère tout le code pour reproduire le scénario à l'identique. Il ne manque plus que quelques assertions et le test est terminé.
Enfin, avec Playwright le debugging est facilité puisqu'il est capable de remonter dans le temps, de connaître l'état du DOM à une étape clé et même générer des vidéos du parcours testé. Take my money. En fait non, puisque Playwright est Open Source (ok, ça ne veut pas dire "gratuit", mais c'est un autre débat) et maintenu par Microsoft... ce qui lui permet aussi une intégration native dans la Github CI (détenue aussi par Microsoft).
Plongeon dans un test Playwright
Rien de mieux que la vidéo de notre Bento Session dédiée au sujet, animée par Yoann (CTO de Web^ID) qui nous explique son utilisateur de Playwright.
Côté code
Nous allons reprendre l'exemple utilisé dans la Bento : React For Dummies dispo ici : https://github.com/web-id-fr/react-for-dummies
L'objectif de ce petit test est simplement de calculer la moyenne d'âge des personnes sélectionnées.
Installation de playwright
On commence donc par cloner le dépôt React For Dummies puis on installe playwright.
Pour cet exemple, on va choisir "JavaScript" puis "tests" comme dossier de destination pour les fichiers de test (malin !) lorsque le prompt vous le demandera au setup de playwright.
À noter que vous pouvez générer un workflow Github si vous le souhaitez.
Pensez à bien installer les "playwright browsers" quand on vous le demandera au moment de l'install.
# récupération du dépôt
git clone -b 'v1.0' git@github.com:web-id-fr/react-for-dummies.git
cd react-for-dummies
# setup de playwright
npm init playwright@latest
# installation / run de vite
yarn
yarn dev
Côté JavaScript
Pour plus de simplicité pour cet exemple, on fait évoluer le composant "Average" (dispo sur src/compoments/Average.jsx) afin de mieux cibler le résultat de la moyenne via les tests en ajoutant des attributs "data-test-id".
const Average = () => {
const { result, feedback } = useAverage()
return (
Âge moyen des personnes sélectionnées
{result && (
{result} ans
)}
{feedback && (
{feedback}
)}
);
};
Génération d'un test à partir d'un playwright codegen
Playwright intègre un petit outil permettant de générer les tests via l'interface. Ce n'est sans doute pas utilisable en tant que tel pour de la prod, mais cela permet sans doute de réduire le temps de rédaction pour affiner ensuite.
Pour cela, rien de plus simple en lançant la commande suivante :
npx playwright codegen http://localhost:5173
Le browser se lance sur l'url donnée en paramètre et vous permet de générer l'écriture d'un test via de simple clics :
On ajoute quelques assertions avec expect
// import de la librairie de test Playwright
import { test, expect } from '@playwright/test';
// on se rend sur la page à tester
test.beforeEach(async ({ page }) => {
await page.goto('http://localhost:5173/');
});
// on vérifie que tout est ok et que le conteu de la page est bien celui attendu
test('Page render correctly', async ({ page }) => {
await expect(page).toHaveTitle(/Average age calculator/);
await expect(page.locator('h1')).toHaveText(/Average age calculator/);
});
// on sélectionne les utilisateurs choisis et on vérifie le résultat
test('Can select users', async ({ page }) => {
await page.pause()
await page.getByText('Robinet Jimpson').click();
await page.getByText('Fonzie Meekins').click();
await page.getByText('Artur Fishlee').click();
await page.waitForLoadState('networkidle')
await expect(page.locator('[data-test-id="average-result"]')).toHaveText(/26 ans/);
});
// vérification du message d'erreur en cas d'âge manquant sur une personne
test('Can select last user and render feedback', async ({ page }) => {
await page.getByText('Jecho Thompson').click();
await page.locator('[data-test-id="average-feedback"]').click();
await expect(page.locator('[data-test-id="average-feedback"]')).toHaveText(/Il manque l'âge de/);
});
On lance les tests ?
Pour lancer les tests, une petite commande suffit. Jetez vous à l'eau, ça va bien se passer :)
# let's test!
npx playwright test
Pour la suite
On l'aura compris, Playwright constitue une excellente alternative pour se lancer sur les tests end-to-end. Il fait un quasi sans faute sur toute la ligne : facile à prendre en main et à maintenir, traitement rapide et sur l'ensemble de browsers du marché.
Bref, nous sommes convaincus et l'utilisons désormais sur nos projets... notamment sur du "legacy" qui n'a souvent aucun test. Cela permet de s'assurer, à moindre coût, que les modifications apportées n'impactent pas les parcours clés.