ITSkillsCenter
Développement Web

Tests modernes en JavaScript en 2026 : Vitest, Playwright et CI parallélisée

17 min de lecture

Pourquoi remettre les tests au centre en 2026

Dans une équipe qui livre vite, les tests automatisés ne sont pas un luxe. Ils sont la seule barrière pratique entre une feature qui marche et une feature qui se casse en silence chez l’utilisateur. Quand le code grossit, la mémoire de l’auteur s’efface, l’équipe tourne, les dépendances bougent : sans tests, chaque modification devient un pari. Avec un harnais de tests bien construit, on déploie le vendredi soir sans angoisse parce que la machine dit oui ou non en quelques minutes.

L’écosystème JavaScript a beaucoup mûri. La génération précédente — Jest pour l’unitaire, Cypress ou Selenium pour le bout-en-bout — a été remplacée par une génération plus rapide, mieux intégrée à Vite et plus honnête sur ce qu’elle teste réellement. Vitest s’est imposé comme la suite par défaut côté unitaire et intégration, Playwright comme la référence pour les tests bout-en-bout, l’API et le visuel. Mock Service Worker (MSW) joue le rôle de mocking universel entre les deux.

Cet article fait le tour stratégique. Il pose le vocabulaire, donne les critères pour choisir l’outil par couche, présente l’architecture cible d’un projet de taille moyenne, et renvoie vers les tutoriels pas-à-pas pour chaque pièce. L’objectif est qu’à la fin de la lecture, vous sachiez quoi tester, avec quoi, et dans quel ordre attaquer le chantier.

La pyramide de tests, version 2026

La métaphore classique reste valide : beaucoup de petits tests rapides à la base, quelques tests d’intégration au milieu, un nombre limité de tests bout-en-bout au sommet. Ce qui a changé, ce sont les frontières. Avec MSW, un test unitaire peut interroger un vrai client HTTP qui parle à un faux serveur — on est techniquement encore en unitaire, mais on couvre un comportement qu’on devait simuler grossièrement avant. Avec Playwright, un test bout-en-bout démarre en moins de deux secondes et tourne en parallèle sur plusieurs navigateurs — on peut donc en écrire plus qu’avant sans exploser le temps de CI.

Concrètement, voici la répartition qui marche pour un projet web moderne. Soixante à soixante-dix pour cent des tests sont des unitaires Vitest : fonctions pures, composants isolés, hooks, utilitaires. Vingt à trente pour cent sont des tests d’intégration : un composant avec son store, un module qui parle à un service mocké, un endpoint d’API testé en isolation. Cinq à quinze pour cent sont des tests bout-en-bout Playwright : parcours métier critiques, paiement, inscription, panier. Le reste, quelques pour cent, ce sont les tests visuels et les contrats d’API.

La règle implicite : plus on monte dans la pyramide, plus chaque test coûte cher en temps de CI et en maintenance. Un test unitaire qui casse pointe la ligne fautive. Un test bout-en-bout qui casse vous demande dix minutes pour comprendre où ça a déraillé. Donc on ne monte que pour ce qui le mérite — les chemins qui mènent à de l’argent ou à de la perte de données.

Vitest comme socle unitaire

Vitest est un runner construit pour Vite, ce qui veut dire qu’il partagé le même pipeline de transformation que votre application : pas de configuration TypeScript en doublon, pas de Babel à entretenir, le même tsconfig pour le code et les tests. C’est un gain de temps quotidien que les anciens utilisateurs de Jest mesurent dès la première semaine.

L’API publique est volontairement très proche de Jest : describe, it, expect, vi.fn(), vi.mock(). Une migration depuis Jest se fait souvent en deux jours sur un projet moyen. Mais Vitest apporte quelques différences que l’on apprécie vite : exécution en parallèle par défaut, watch mode quasi instantané, mode UI dans le navigateur pour debugger, support natif de TypeScript et de ESM, et surtout le browser mode qui permet de faire tourner les mêmes tests dans un vrai navigateur via Playwright ou WebdriverIO.

Le réflexe à prendre : un test unitaire Vitest doit s’exécuter en moins de cinquante millisecondes. S’il dépasse, c’est qu’il fait trop de choses, qu’il accède au système de fichiers, ou qu’il monte un composant trop lourd. Dans ce cas, on isole, on mocke, ou on déplace le test au niveau intégration. Le tutoriel pas-à-pas dédié couvre l’installation, la première suite de tests, les matchers utiles, le mocking et le coverage.

Playwright pour le bout-en-bout, l’API et le visuel

Playwright est devenu le couteau suisse des tests d’interaction. Initialement positionné comme remplaçant de Selenium et concurrent de Cypress, il a ajouté au fil des versions un module request pour les tests d’API sans navigateur, un système de snapshots visuels stable, un trace viewer qui rejoue le test pas-à-pas avec les screenshots et les requêtes réseau, et un mode component testing pour Vue, React, Svelte et autres.

Sur le bout-en-bout, l’argument clé est l’auto-attente intelligente. Au lieu de saupoudrer des sleep aléatoires, Playwright attend automatiquement qu’un élément soit visible, cliquable et stable avant d’agir dessus. Les tests deviennent moins flaky d’un ordre de grandeur, ce qui réduit le coût de maintenance — qui est, sur le long terme, le principal poste de coût d’une suite E2E.

Sur l’API, Playwright permet d’écrire en TypeScript des tests qui ressemblent beaucoup à du code de production : on instancie un client, on envoie une requête, on assert sur le statut et le corps. Comparé à Postman ou à un outil dédié, l’avantage est que les tests vivent dans le même dépôt que le code, dans la même CI, avec les mêmes types. La fixture request de Playwright gère même l’authentification persistée pour ne pas se relogger à chaque test.

Sur le visuel, le module toHaveScreenshot capture le rendu d’une page ou d’un composant, le compare à une image de référence stockée dans le dépôt, et signalé les différences au pixel près. C’est le seul moyen pratique de détecter les régressions de style — un padding qui change, une couleur qui se décale après une mise à jour de Tailwind, un overlay qui se positionne mal après un changement de viewport. Les tutoriels associés détaillent chacun de ces trois usages.

MSW pour mocker les API réseau

Mock Service Worker intercepte les requêtes HTTP au niveau réseau, dans le navigateur via le Service Worker API et dans Node via un patch de fetch et http. La conséquence pratique est que votre code ne sait pas qu’il parle à un mock — il fait un vrai fetch, qui produit une vraie Response, qui passe par votre vraie couche de désérialisation.

L’intérêt par rapport aux mocks classiques (vi.mock, stubs manuels) est double. Premièrement, on teste le bon niveau : la couche réseau, pas la couche d’abstraction. Si vous changez votre client HTTP demain — passer de axios à fetch, par exemple — les mocks MSW continuent de marcher sans modification. Deuxièmement, le même handler MSW peut être partagé entre les tests Vitest, le mode développement local (Storybook ou un mode démo), et même les tests Playwright si vous voulez les faire tourner sans backend.

La version 2 de MSW utilisé une API plus claire que la version 1 : http.get, http.post au lieu de rest.get, et HttpResponse.json() pour produire les réponses. Le tutoriel dédié explique l’installation, la création des handlers, l’usage en Vitest et l’organisation des fixtures pour rester maintenable au-delà de cinquante endpoints.

Tests visuels, sans tomber dans le piège

Les tests visuels ont mauvaise réputation parce que la première implémentation naïve produit des centaines de faux positifs — un anti-aliasing qui change entre deux machines, une animation qui n’a pas fini, une police qui se charge avec un demi-pas de retard. Playwright a beaucoup investi pour réduire ces sources de bruit : désactivation des animations, masquage des zones dynamiques, comparaison avec une tolérance configurable, et surtout exécution dans un environnement Docker reproductible pour la CI.

La bonne pratique consiste à ne tester visuellement que les composants stables et critiques : la page d’accueil, le formulaire de checkout, le composant de tableau, les états vides et d’erreur. Pas la liste produits qui change tous les jours. Pas le dashboard qui dépend des données. On vise la régression de style, pas le contenu.

Le coût caché est la mise à jour des screenshots. Quand vous changez volontairement le design, il faut accepter les nouvelles images, ce qui demande une revue humaine sérieuse parce qu’un mauvais commit peut figer un bug graphique. Le workflow recommandé : générer les screenshots en CI, les téléverser comme artefact, et les valider manuellement avant de les committer comme nouveau référent.

CI parallélisée, le multiplicateur d’efficacité

Une suite de tests qui prend quinze minutes en CI est une suite que personne ne lance localement avant de pousser. Une suite qui prend trois minutes change le rapport au code : on lance avant chaque commit, on attrape les régressions tôt, on garde un main toujours vert. Le levier principal pour passer de quinze à trois minutes est la parallélisation.

Vitest parallélise par défaut sur les cœurs disponibles. Playwright supporte le sharding natif via --shard : on découpe la suite en N parts égales, on les fait tourner sur N runners GitHub Actions différents, et on agrège les rapports. Avec quatre shards, une suite de douze minutes passe à environ trois minutes plus le temps d’amorçage de chaque runner.

Le piège classique est de paralléliser sans isoler les ressources partagées. Si tous vos shards écrivent dans la même base de données de test, ils vont se marcher dessus. La solution est soit d’avoir une base par shard (Docker rend ça facile), soit de scoper les données par préfixe (un suffixe aléatoire sur les emails de test, par exemple). Le tutoriel pas-à-pas sur la CI parallélisée GitHub Actions couvre la configuration matrix, la fusion des rapports HTML, le cache des navigateurs Playwright, et les budgets de temps.

Architecture cible d’un projet

Voici à quoi ressemble une organisation de tests qui passe à l’échelle. Au niveau du dépôt, les tests vivent à côté du code : src/foo/foo.ts a son src/foo/foo.test.ts. Les tests d’intégration vont dans tests/intégration/ car ils touchent plusieurs modules. Les tests bout-en-bout dans tests/e2e/ car ils dépendent du serveur démarré. Les fixtures partagées (handlers MSW, données de seed) dans tests/fixtures/.

Côté configuration, on a un vitest.config.ts qui pointe vers les fichiers *.test.ts du src et un playwright.config.ts qui pointe vers tests/e2e/. Les deux outils ne se croisent pas — Vitest ne trouve pas les tests E2E et inversement. Cette séparation rend la commande mentale claire : npm run test pour le rapide, npm run test:e2e pour le lent.

Côté CI, on a deux jobs distincts. Le job unit-int tourne sur Node Active LTS (Node 24 Krypton en 2026), exécute Vitest, génère le coverage, et finit en moins de deux minutes. Le job e2e tourne en matrice de quatre shards, sur Node 24 également, démarre le serveur, exécute Playwright, et fusionne les rapports en un blob HTML téléchargeable. Sur une PR, les deux jobs se lancent en parallèle ; sur main, on ajouté un job de tests visuels qui n’échoue pas mais signalé via un commentaire automatique.

Erreurs fréquentes à éviter

Beaucoup d’équipes échouent sur trois écueils. Premièrement, vouloir tout tester. Une couverture à cent pour cent ne dit rien sur la qualité — elle dit que le code est exécuté, pas qu’il est correct. La règle saine : tester ce qui peut casser et ce qui coûte cher quand ça casse. Une fonction utilitaire sans branche conditionnelle ne mérite pas un test ; un calcul de remise oui, et de plusieurs façons.

Deuxièmement, mocker trop. Un test qui mocke tout ne teste plus que les mocks. Quand un module mocké change de comportement réel, le test ne le voit pas et la régression file en production. La règle : mocker à la frontière du système (réseau, base de données, horloge), pas à l’intérieur. MSW au niveau réseau, vi.useFakeTimers() pour l’horloge, et le moins possible ailleurs.

Troisièmement, laisser les tests flaky vivre. Un test qui échoue une fois sur dix érode la confiance en toute la suite. Les développeurs apprennent à relancer en boucle, et le jour où un vrai bug apparaît, personne n’y croit. Il faut traiter chaque flake comme un bug critique : reproduire, comprendre, corriger ou désactiver. La règle d’or : un test fiable à zéro flake vaut mieux que dix tests flaky.

Suivi de la qualite dans la duree

Mettre en place une suite de tests est un projet ; la maintenir est un mode de vie. Trois indicateurs simples suffisent a savoir si la suite vit ou meurt. Le premier est le temps moyen d exécution sur main, mesure sur les 50 dernières exécutions ; s’il croit lineairement sans qu’on ajouté de tests, c’est qu un test spécifique se met a ralentir et il faut l identifier. Le second est le taux de flakes, défini comme le ratio entre les tests qui ont réussi en deuxieme tentative et le total. Au-dela de 1 %, la confiance s erode rapidement. Le troisieme est la couverture sur les modules critiques, pas la couverture globale qui est un mauvais indicateur. Une règle interne saine : ces trois indicateurs sont publies en commentaire sur chaque PR par un job CI, ce qui rend invisible le drift de qualite impossible.

L observabilité des tests, longtemps negligee, s’est professionnalisee. Datadog Test Visibility, Buildkite Test Analytics et même la nouvelle vue Tests de GitHub Actions agregent les rapports JUnit pour montrer l évolution dans le temps. Sur un projet qui exporte ce format depuis Vitest et Playwright, on voit en quelques clics quels tests sont les plus lents, lesquels flakent le plus, et lesquels n’ont pas tourne depuis des semaines. Cette dernière catégorie est souvent revelatrice : un test désactivé avec un it.skip il y a six mois pour debugger plus tard a probablement perdu sa pertinence.

Cohabitation entre Vitest, Playwright et le legacy

Beaucoup d équipes héritent de tests Jest existants. La cohabitation est tout a fait possible : on garde Jest pour les modules déjà couverts, on ajouté Vitest pour le code nouveau, et on migre progressivement quand un module est touche. Les deux runners cohabitent dans le même depot avec des configurations distinctes. Ce qui complique vite le tableau, c’est d avoir trois couches de mocks : Jest mocks, Vitest mocks, MSW. Pour éviter le chaos, la règle a fixer tôt’est : tout ce qui est réseau passe par MSW, tout le reste utilisé les mocks du runner concerne. Cette règle simplifie les revues de code et évite les conflits subtils entre couches.

Une autre cohabitation a anticiper est celle entre les tests E2E qui parlent au backend et les tests Vitest qui mockent le même backend. Si les contrats divergent, on peut avoir un test Vitest qui passe (le mock est bon) et un test E2E qui échoue (le vrai serveur ne répond pas comme le mock). Pour éviter ce problème, on peut generer les types TypeScript depuis le schema OpenAPI ou GraphQL du backend, et faire en sorte que les handlers MSW utilisent ces types — ainsi un changement de contrat coupe le typage et alerte tôt.

Ressources officielles à garder sous la main

Tutoriels associés

Cette série couvre chaque pièce du puzzle, en mode pas-à-pas avec installation, premier test et bonnes pratiques :

Questions fréquentes

Vitest ou Jest en 2026 ?
Vitest si le projet utilisé Vite (Vue, Svelte, projets Vite vanilla, certaines configurations React). Jest reste défendable dans des projets Next.js historiques ou des monorepos legacy, mais Vitest a comblé tous les écarts fonctionnels et offre une vitesse supérieure. Pour un nouveau projet, le choix par défaut est Vitest.

Playwright ou Cypress ?
Playwright pour les nouveaux projets. Il couvre plus de navigateurs (Chromium, Firefox, WebKit), tourne nativement sans patch dans le navigateur, supporte les iframes et les onglets multiples, et inclut un trace viewer plus puissant. Cypress reste populaire mais a perdu son avancé technique.

Faut-il vraiment écrire des tests E2E ?
Oui pour les parcours qui font perdre de l’argent ou de la confiance s’ils cassent : inscription, connexion, paiement, soumission de formulaire critique. Non pour la majorité des écrans CRUD basiques, qui sont mieux servis par des tests d’intégration moins coûteux.

Combien de temps pour mettre en place tout ça sur un projet existant ?
Une à deux semaines pour un développeur seul sur un projet moyen — quelques jours pour la configuration et la première suite, le reste pour rattraper la couverture critique. Le retour sur investissement se mesure en semaines, pas en mois.

MSW est-il compatible avec les tests Playwright ?
Partiellement. MSW marche très bien côté serveur (Node) et côté navigateur en mode développement. En tests Playwright, l’usage classique est plutôt d’utiliser page.route() de Playwright pour intercepter les requêtes — c’est l’API native qui s’intègre mieux aux fixtures.

Faut-il un environnement de pré-production pour les tests E2E ?
Non, sauf cas particulier. La pratique recommandée est de démarrer l’application en local dans le job CI (webServer dans playwright.config.ts), avec une base SQLite ou Postgres jetable, et de seeder les données nécessaires au test. C’est plus rapide et plus fiable qu’un environnement partagé.

Par où commencer

Si vous partez de zéro sur un projet existant sans tests, l’ordre conseillé est le suivant. D’abord, installer Vitest et écrire trois tests unitaires sur la fonction métier la plus critique. Ensuite, ajouter Playwright et coder le parcours bout-en-bout le plus important — souvent la connexion ou le checkout. Puis MSW pour stabiliser les tests qui dépendent d’API externes. Tests visuels et CI parallélisée arrivent en dernier, quand la suite a déjà mille tests et qu’on cherche à grappiller du temps. Chaque tutoriel pas-à-pas associé prend deux à quatre heures à mettre en place sur un projet réel.

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité