Dans le chapitre précédent, votre tech lead vous a demandé de tester les composants React de l'application de gestion de tâches. Grâce à React Testing Library, vous avez vérifié que les utilisateurs pouvaient interagir correctement avec l'interface et que les composants transmettaient les bonnes informations au reste de l'application.
À ce stade, vous avez déjà exploré trois niveaux de test complémentaires. Vous avez commencé par les tests unitaires pour sécuriser des fonctions isolées. Vous avez ensuite testé les routes API avec Vitest afin de valider les comportements du backend. Enfin, vous avez vérifié les composants React dans un environnement contrôlé grâce à React Testing Library.
Une dernière étape reste à franchir : tester l'application dans les conditions les plus proches possibles de son utilisation réelle. C'est précisément le rôle des tests end-to-end, souvent abrégés E2E.
Dans ce chapitre de clôture, vous allez découvrir Playwright, l'outil de référence pour les tests E2E dans l'écosystème Next.js moderne. Vous apprendrez à reproduire un parcours utilisateur complet dans un véritable navigateur, à écrire des scénarios fiables et à analyser efficacement les échecs grâce au Trace Viewer.
Depuis le début de cette partie, chaque niveau de test vous a permis d'élargir progressivement votre champ d'observation. Les tests unitaires vérifiaient une fonction isolée. Les tests d'intégration contrôlaient le comportement d'une route API. Les tests de composants validaient l'affichage et les interactions d'un composant React.
Les tests end-to-end vont encore plus loin.
Cette fois, nous lançons l'application complète dans un véritable navigateur. Le test reproduit les actions d'un utilisateur réel : navigation entre les pages, remplissage de formulaires, clics sur les boutons et vérification des résultats affichés à l'écran. L'objectif n'est plus de tester une partie du système, mais de vérifier que l'ensemble fonctionne correctement lorsque toutes les briques collaborent.
Dans notre application de gestion de tâches, le scénario principal sera le suivant :
Un utilisateur se connecte.
Il accède à son espace de travail.
Il crée une nouvelle tâche.
Il vérifie que cette tâche apparaît dans sa liste.
Vous pouvez considérer ce niveau comme la dernière étape de notre progression pédagogique. Les quatre niveaux de test sont désormais actifs :
Niveau | Élément testé |
Test unitaire | Fonction isolée |
Intégration back | Route API |
Test de composant | Composant React |
Test E2E | Parcours utilisateur complet |
Ce qui ne change pas par rapport aux chapitres précédents, c'est la philosophie générale : nous continuons à tester l'application du point de vue de l'utilisateur. Ce qui change, en revanche, c'est l'environnement d'exécution. Nous quittons le DOM virtuel de React Testing Library pour travailler dans un véritable navigateur.
Votre tech lead souhaite maintenant automatiser le parcours utilisateur principal de l'application. Avant d’écrire votre premier scénario E2E, observez dans ce screencast comment installer Playwright, créer un test de connexion, puis automatiser le parcours complet jusqu’à la création d’une tâche visible dans la liste.
À vous maintenant de reproduire ce parcours dans un vrai navigateur, en utilisant des locators sémantiques et des assertions fiables.
La première étape consiste à installer Playwright :
npm init playwright@latestCette commande crée plusieurs éléments de configuration, notamment le fichierplaywright.config.ts, le dossiertests/et la configuration des différents navigateurs supportés.
Avant d’écrire le moindre scénario, nous devons compléter playwright.config.ts. Deux réglages sont indispensables. D’une part, baseURL indique l’adresse de l’application : grâce à elle, nous pouvons écrire des URL relatives comme /login au lieu de l’adresse complète. D’autre part, webServer demande à Playwright de démarrer l’application avant les tests, ce qui évite de lancer npm run dev à la main. Nous en profitons pour pointer testDir vers notre dossier e2e :
import { defineConfig, devices } from "@playwright/test"
export default defineConfig({
testDir: "./e2e",
use: {
baseURL: "http://localhost:3000",
trace: "on-first-retry",
},
projects: [
{ name: "chromium", use: { ...devices["Desktop Chrome"] } },
],
webServer: {
command: "npm run dev",
url: "http://localhost:3000",
reuseExistingServer: !process.env.CI,
timeout: 120_000,
},
})Une fois l'installation terminée, nous pouvons créer notre premier scénario E2E.
import { test, expect } from "@playwright/test";Le scénario suit le parcours déjà utilisé dans les chapitres précédents :
test("un utilisateur crée une tâche", async ({ page }) => {
await page.goto("/login");
await page
.getByLabel("Email")
.fill("test@example.com");
await page
.getByLabel("Mot de passe")
.fill("secret");
await page
.getByRole("button", {
name: /se connecter/i
})
.click();
await expect(page)
.toHaveURL("/tasks");
// Le formulaire d'ajout est masqué par défaut : on l'ouvre d'abord.
await page
.getByRole("button", {
name: /nouvelle tâche/i
})
.click();
await page
.getByLabel("Titre")
.fill("Tâche E2E unique");
await page
.getByRole("button", {
name: /ajouter la tâche/i
})
.click();
await expect(
page.getByText("Tâche E2E unique")
).toBeVisible();
});Ce scénario reproduit le parcours d'un utilisateur réel, à un détail près qu'il faut connaître : le formulaire d'ajout est masqué par défaut. Avant de remplir le champ « Titre », il faut d'abord cliquer sur le bouton « Nouvelle tâche » pour afficher le formulaire. Notez aussi le choix d'un titre unique : si l'on réutilisait un titre déjà présent au démarrage (comme « Acheter du pain »), l'assertion finale réussirait même si la création avait échoué.
Pour exécuter le test, vous pouvez utiliser :
npx playwright test --uiLe mode UI constitue l'un des grands atouts de Playwright. Il permet de visualiser les scénarios, de relancer individuellement les tests et d'inspecter leur déroulement étape par étape.
Cette capacité à rejouer un test visuellement devient particulièrement précieuse lorsqu'un scénario complexe échoue.
Lorsque l'on découvre les tests E2E, il est fréquent d'écrire des scénarios qui fonctionnent sur sa machine mais deviennent instables au fil du temps. Playwright propose plusieurs mécanismes pour éviter ce problème.
La première bonne pratique consiste à utiliser les web-first assertions. Au lieu de vérifier immédiatement qu'un élément est visible, Playwright réessaie automatiquement pendant un certain temps avant de déclarer un échec.
Par exemple :
await expect(
page.getByText("Acheter du pain")
).toBeVisible();Cette assertion est plus robuste qu'une vérification instantanée car elle tient compte du temps nécessaire au chargement de l'interface.
La deuxième bonne pratique concerne les locators. Comme avec React Testing Library, privilégiez les sélecteurs sémantiques :
page.getByRole();
page.getByLabel();
page.getByText();Ces locators reflètent la manière dont les utilisateurs interagissent avec l'interface et rendent les tests plus résistants aux changements de structure HTML.
À l'inverse, un test fragile pourrait ressembler à ceci :
await page.locator(
".btn-primary"
).click();
await page.waitForTimeout(2000);Ce code présente deux problèmes. D'abord, le sélecteur CSS dépend fortement de l'implémentation. Ensuite,waitForTimeout()introduit un délai arbitraire qui peut ralentir ou rendre instables les tests.
La version recommandée est :
await page
.getByRole("button", {
name: /ajouter la tâche/i
})
.click();
await expect(
page.getByText("Tâche E2E unique")
).toBeVisible();Même avec de bonnes pratiques, les échecs restent inévitables. La différence entre un développeur débutant et un développeur expérimenté réside souvent dans sa capacité à diagnostiquer rapidement la cause du problème.
Avec Playwright, le meilleur outil de débogage est le Trace Viewer.
Lorsqu'un test échoue et que la capture de trace est activée dansplaywright.config.ts(optiontrace), Playwright enregistre un fichier de trace. Vous pouvez alors l'ouvrir en lui passant son chemin :
npx playwright show-trace trace.zipOu relancer directement le scénario en mode UI. Le Trace Viewer permet de rejouer le test image par image. Vous pouvez observer la chronologie complète des actions, l'état du DOM à chaque étape, les requêtes réseau et les messages d'erreur associés.
Dans la pratique, quatre causes d'échec reviennent fréquemment.
La première concerne les locators. Un élément peut ne pas être trouvé ou plusieurs éléments peuvent correspondre au même locator. Playwright indique alors précisément quel sélecteur pose problème.
La deuxième cause concerne la logique applicative. Le scénario est correct mais le comportement attendu n'est pas produit par l'application.
La troisième concerne les données. Par exemple, les données de départ n'ont pas été correctement initialisées, ou un titre déjà présent au démarrage fausse une assertion.
Enfin, la quatrième cause est liée à l'intégration. Une API indisponible ou une route mal configurée peut empêcher le parcours utilisateur d'aboutir.

Après avoir testé les routes API puis les composants React, votre tech lead souhaite finaliser la stratégie de test de l'application de gestion de tâches.
L'équipe dispose déjà d'un scénario E2E permettant de vérifier la connexion et la création d'une tâche. Vous devez maintenant automatiser le parcours de déconnexion afin de compléter le cycle de vie principal d'un utilisateur authentifié.
Écrivez un scénario Playwright couvrant le parcours « connexion → déconnexion ».
Vérifiez qu'au moins un état intermédiaire est visible à l'écran grâce à une web-first assertion.
Utilisez uniquement des locators sémantiques (getByRole,getByLabel,getByText).
Vérifiez que l'utilisateur est redirigé vers/loginaprès sa déconnexion.
Provoquez volontairement un échec.
Analysez la cause grâce au Trace Viewer.
Playwright exécute les tests dans un véritable navigateur et permet de reproduire des parcours utilisateur complets de bout en bout.
Un scénario E2E s'appuie principalement surpage.goto(), les locators sémantiques et les web-first assertions.
Les locatorsgetByRole(),getByLabel()etgetByText()doivent être privilégiés avant les sélecteurs CSS ou lesdata-testid.
Les web-first assertions rendent les tests plus fiables grâce à leurs mécanismes de réessai automatiques.
En cas d'échec, le Trace Viewer constitue l'outil de référence pour comprendre rapidement l'origine du problème.
Félicitations ! Vous avez maintenant découvert les quatre grands niveaux de test utilisés dans les applications web modernes. Vous êtes capable de sécuriser une application Next.js depuis une fonction isolée jusqu'au parcours utilisateur complet exécuté dans un véritable navigateur. Il ne vous reste qu'à tester vos connaissances avec le quiz. Bonne chance !