FR
Leçon 5.1

Tests, tests, tests : TSC, linting, Vitest, Playwright et CI/CD

Protéger votre projet avec des type checks, du linting, des tests unitaires et end-to-end, câblés dans CI/CD

28 minQualité, sécurité et le business agent-firstDisponible

Ce que tu apprends

  • Pourquoi les agents rendent les tests plus importants, pas moins, et le quality gate à quatre couches
  • Écrire des tests unitaires Vitest et des tests end-to-end Playwright qui survivent aux refactors
  • Faire tourner toute la suite automatiquement avec un pre-push hook et GitHub Actions

Vue d'ensemble

Il y a le mythe que l'IA écrit le code, donc vous n'avez plus besoin de tests. C'est le contraire qui est vrai. Un agent réécrit joyeusement une fonction qui marchait à 2 h du matin parce que vous avez demandé un changement sans rapport, et il n'a aucun souvenir de pourquoi l'ancien comportement importait. Les tests sont la façon dont vous dites aux futurs agents ce qui ne doit pas casser. Cette leçon bâtit le quality gate à quatre couches - types, lint, unitaires, end-to-end - et le câble dans un pre-push hook et une pipeline CI, pour que la qualité soit imposée par la machine, pas par votre discipline.

Ce que vous allez apprendre

Vous allez apprendre ce que chaque couche du stack qualité attrape, comment écrire un test unitaire Vitest et un test end-to-end Playwright qui continuent de fonctionner après un refactor, comment bloquer un mauvais push avec un git hook et comment faire tourner toute la suite automatiquement à chaque push avec GitHub Actions. À la fin, vous pouvez donner à un agent les mains libres dans un repo et faire confiance au gate pour attraper ses erreurs.

Prérequis

Un projet TypeScript fonctionnel des cours précédents et la leçon sur les hooks du Cours 2, car CI/CD n'est que la version à l'échelle de l'équipe d'un gate pre-push. Vous n'avez pas besoin d'être expert en tests. Le but de cette leçon est de faire des tests une habitude que votre agent fait pour vous, pas une discipline dont vous devez vous souvenir.

Le problème

Quand vous faites tourner un agent dur, il touche beaucoup de code vite. Un changement dans un fichier casse silencieusement un autre. L'agent signale un succès, parce que le fichier qu'il a modifié a l'air correct, et vous ne découvrez la régression que quand une page est vide en production. Le test manuel ne passe pas à l'échelle du rythme d'un agent - vous ne pouvez pas cliquer à travers chaque flux après chaque changement. Sans gate automatique, chaque session d'agent est un petit pari sur votre produit live. La solution est de faire de « ça marche encore ? » une question à laquelle la machine répond en secondes.

Le quality gate à quatre couches

Chaque couche attrape une classe différente de bugs, et elles deviennent plus lentes et plus approfondies à mesure que vous descendez. Faites tourner les rapides sans cesse et les lentes avant la livraison. Ensemble, elles forment un filet assez serré pour que les changements rapides, pilotés par agent, restent sûrs.

  • Type check (tsc --noEmit) : attrape les erreurs de forme - une fonction appelée avec les mauvais arguments, une propriété qui n'existe pas, un null que vous avez oublié de gérer. Instantané et gratuit.
  • Lint (ESLint) : attrape les patterns sujets aux erreurs et la dérive de style - variables inutilisées, awaits manquants, console.logs accidentels. Garde le code écrit par l'agent cohérent avec le vôtre.
  • Tests unitaires (Vitest) : vérifient que votre logique est effectivement correcte - un calcul de prix, une règle de validation, un formateur de date. Rapides, à faire tourner à chaque sauvegarde.
  • Tests end-to-end (Playwright) : pilotent un vrai navigateur à travers des parcours utilisateur entiers - se connecter, mettre au panier, checkout. Lents, mais ils prouvent que la vraie chose fonctionne.

Écrire un test unitaire Vitest

Les tests unitaires sont petits et rapides. Vous donnez un input à une fonction et vérifiez l'output. L'astuce qui les fait survivre aux refactors d'agent : testez le comportement, pas l'implémentation. Vérifiez ce que la fonction doit produire pour une utilisatrice, jamais les étapes privées qu'elle parcourt pour y arriver. Alors l'agent peut réécrire les internes librement et le test garde quand même le contrat.

import { describe, it, expect } from 'vitest'
import { yearlyPricePerMonth } from './pricing'

describe('yearlyPricePerMonth', () => {
  it('shows the discounted monthly figure for a yearly plan', () => {
    // Monthly is 17% above yearly, so yearly-per-month is monthly / 1.17.
    expect(yearlyPricePerMonth({ monthly: 117 })).toBe(100)
  })

  it('never returns a negative price', () => {
    expect(yearlyPricePerMonth({ monthly: 0 })).toBeGreaterThanOrEqual(0)
  })
})
Un test Vitest qui verrouille le comportement, pas l'implémentation - faites-le tourner avec bun run test

Quand vous demandez à un agent d'ajouter une fonctionnalité, ajoutez une ligne à votre spec : « écris un test Vitest pour ça ». Maintenant l'agent laisse un fil-piège qui protège la fonctionnalité du prochain agent, y compris une future version de lui-même.

Écrire un test end-to-end Playwright

Playwright lance un vrai navigateur, visite votre app et clique comme une utilisatrice. Il attrape les bugs que les tests unitaires ne peuvent pas : une route cassée, un bouton qui ne fait rien, un formulaire qui ne s'envoie jamais. Écrivez les tests end-to-end d'abord pour vos chemins d'argent - la poignée de flux où une casse vous coûte un client. Choisissez les éléments par ce que l'utilisatrice voit, ou par des test IDs stables, jamais par du CSS fragile, pour qu'un redesign ne casse pas chaque test.

import { test, expect } from '@playwright/test'

test('a visitor can reach the pricing page from the hero CTA', async ({
  page,
}) => {
  await page.goto('/')
  await page.getByRole('link', { name: 'See pricing' }).click()
  await expect(page).toHaveURL(/\/pricing/)
  await expect(
    page.getByRole('heading', { name: 'Pricing' }),
  ).toBeVisible()
})
Un test Playwright pour un vrai parcours utilisateur - faites-le tourner avec bun run test:e2e

Le pre-push hook : votre gate local

Le premier endroit pour imposer le gate est votre propre machine, à l'instant avant que le code ne la quitte. Un git pre-push hook fait tourner vos vérifications et refuse le push si l'une échoue, pour que le code cassé n'atteigne jamais le repo. C'est la même idée que vous avez rencontrée au Cours 2, désormais dirigée sur la suite complète. Gardez le hook local rapide - types, lint et tests unitaires - et laissez la suite end-to-end plus lente tourner en CI.

#!/usr/bin/env sh
# .husky/pre-push - bloque le push si une vérification échoue

bun run typecheck || exit 1
bun run lint || exit 1
bun run test || exit 1

echo "All checks passed - pushing."
Un pre-push hook qui fait tourner les couches rapides avant que le code ne quitte votre machine

Un hook que vous pouvez sauter avec --no-verify est une suggestion, pas un gate. Le hook est votre feedback rapide ; la CI est le gate que personne ne peut contourner. Vous voulez les deux.

GitHub Actions : le gate que personne ne peut sauter

L'intégration continue fait tourner toute votre suite sur les serveurs de GitHub à chaque push et pull request, peu importe ce que quelqu'un a fait tourner localement. Un fichier de workflow dans .github/workflows dit à GitHub quoi faire. L'exemple ci-dessous installe les dépendances puis fait tourner les quatre couches, y compris les tests end-to-end. Réglez votre branch pour que cette vérification doive passer avant tout merge, et une régression ne peut simplement pas atteindre votre branch main.

name: Quality gate

on:
  push:
    branches: [main]
  pull_request:

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - run: bun install --frozen-lockfile
      - run: bun run typecheck
      - run: bun run lint
      - run: bun run test
      - run: bunx playwright install --with-deps
      - run: bun run test:e2e
.github/workflows/quality.yml - le gate complet, fait tourner automatiquement à chaque push

Erreurs fréquentes

Les grosses : écrire zéro test parce que « l'agent l'a déjà vérifié » (il ne peut pas voir votre app live) ; tester des détails d'implémentation, si bien que chaque refactor met la suite au rouge et que vous commencez à l'ignorer ; rendre le hook local si lent que vous le contournez avec --no-verify ; et avoir la CI mais ne pas exiger qu'elle passe avant le merge, si bien qu'elle devient décorative. Testez le comportement, gardez le gate local rapide et rendez la CI obligatoire.

ROI business

Une régression qui atteint un client vous coûte la confiance, un ticket de support et un fix d'urgence, souvent au pire moment imaginable. Un test qui l'attrape coûte les quelques secondes qu'il met à tourner. Une fois le gate en place, vous pouvez laisser les agents travailler bien plus agressivement, parce que le coût d'une erreur passe de « a cassé la production » à « la pipeline est passée au rouge, corrige avant le merge ». C'est la vraie libération : les tests ne sont pas un overhead sur le development agentique, ils sont ce qui rend le development agentique agressif sûr.

Checklist

Vous êtes prêt à avancer quand chacun de ces points est vrai pour un vrai projet, pas seulement en théorie.

  • Vous savez expliquer ce que chacune des quatre couches attrape que les autres ratent.
  • Au moins un test Vitest et un test Playwright passent dans votre projet.
  • Un pre-push hook fait tourner les couches rapides et bloque un push en échec.
  • Un workflow GitHub Actions fait tourner la suite complète et est requis avant le merge.

Ressources

Gardez en favoris les docs officielles Vitest et Playwright pour les matchers et sélecteurs et les docs GitHub Actions pour la syntaxe de workflow, car elles évoluent. Ajoutez « écris un test pour ça » à vos contraintes de spec-sheet standard, pour que chaque tâche d'agent laisse un fil-piège. La leçon sur les hooks du Cours 2 vaut une relecture, maintenant que vous câblez la suite complète.

Votre mission

Ajoutez un test Vitest et un test Playwright à un vrai projet, puis ajoutez le pre-push hook et le workflow GitHub Actions ci-dessus. Cassez délibérément quelque chose qu'un agent pourrait casser - renommez une route, changez l'output d'une fonction - et confirmez que le gate passe au rouge. Ce rouge est tout l'intérêt : il a attrapé l'erreur avant qu'un utilisateur ne le fasse.

Prochaine leçon

La qualité couverte, la prochaine leçon durcit la sécurité : rate limits sur chaque endpoint public, headers CSP, chiffrer les credentials stockées et l'audit pré-public qui empêche un secret de fuiter quand vous passez un repo en public.

Commentaires

Chargement des commentaires.

Poster un commentaire
CommentairesSuivant
Étape suivante

Prêt à mettre l’IA au service d’un véritable workflow ?

Commencez par le cours de base, conservez vos progrès localement et synchronisez tout sur votre compte gratuit quand vous le souhaitez.