Skip to content
Learni
View all tutorials
Tests logiciels

Comment écrire des tests unitaires avec Jest en 2026

Introduction

Les tests unitaires sont essentiels pour garantir la fiabilité de votre code JavaScript. Imaginez votre application comme un puzzle : un test unitaire vérifie qu'une seule pièce (une fonction) fonctionne parfaitement, isolée des autres. En 2026, avec Jest – le runner de tests le plus populaire –, vous gagnez en vitesse et simplicité grâce à ses zero-config, snapshots et mocks intégrés.

Ce tutoriel beginner vous emmène des bases à des tests avancés. Pourquoi c'est crucial ? Un bug non détecté coûte 100x plus cher en prod qu'en dev. Vous apprendrez à tester des fonctions sync/async, simuler des dépendances et mesurer la couverture. À la fin, votre code sera testé à 80%+ sans effort superflu. Prêt à bookmarker ce guide ? Allons-y étape par étape.

Prérequis

  • Node.js 20+ installé
  • Connaissances de base en JavaScript (fonctions, objets)
  • Un éditeur comme VS Code
  • Terminal (bash ou PowerShell)

Initialiser le projet

terminal
mkdir tests-unitaires-jest
cd tests-unitaires-jest
npm init -y
npm install --save-dev jest @types/jest

Cette commande crée un dossier projet, initialise package.json et installe Jest en devDependency. L'option --save-dev évite d'inclure les outils de test en prod. @types/jest ajoute le typage pour un meilleur autocomplétion dans VS Code.

Configurer Jest dans package.json

package.json
{
  "name": "tests-unitaires-jest",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage"
  },
  "devDependencies": {
    "jest": "^29.7.0",
    "@types/jest": "^29.5.12"
  }
}

On active ES modules avec "type": "module" pour l'import moderne. Les scripts permettent npm test pour lancer tous les tests, --watch pour re-tester auto sur changements, et --coverage pour un rapport de couverture code. Copiez-collez ce package.json complet.

Créer une fonction à tester

math.js
export function add(a, b) {
  if (typeof a !== 'number' || typeof b !== 'number') {
    throw new Error('Les arguments doivent être des nombres');
  }
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}

export async function fetchUser(id) {
  // Simulation API
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ id, name: `User ${id}` });
    }, 100);
  });
}

Ces fonctions illustrent des cas réels : add avec validation d'erreur, multiply simple, fetchUser async simulant une API. Exportées pour modularité. Testez-les isolément pour isoler les bugs sans dépendances externes.

Premier test unitaire simple

math.test.js
import { add, multiply } from './math.js';

describe('Math Utils', () => {
  test('add devrait sommer deux nombres', () => {
    expect(add(2, 3)).toBe(5);
    expect(add(0, 0)).toBe(0);
    expect(add(-1, 1)).toBe(0);
  });

  test('multiply devrait multiplier deux nombres', () => {
    expect(multiply(2, 3)).toBe(6);
    expect(multiply(0, 5)).toBe(0);
  });

  test('add devrait throw si arguments invalides', () => {
    expect(() => add('a', 2)).toThrow('Les arguments doivent être des nombres');
  });
});

Premier test avec describe pour grouper, test pour cas. expect().toBe() vérifie égalité stricte, toThrow() les erreurs. Lancez npm test : tous passent. Analogie : comme un checklist avant vol, chaque expect valide un scénario.

Test asynchrone avec mocks

user.test.js
import { fetchUser } from './math.js';

const mockFetchUser = jest.fn();

// Mock global pour simuler
jest.mock('./math.js', () => ({
  fetchUser: mockFetchUser
}));

beforeEach(() => {
  mockFetchUser.mockClear();
});

describe('User Fetch', () => {
  test('fetchUser devrait retourner un user async', async () => {
    const mockUser = { id: 1, name: 'John' };
    mockFetchUser.mockResolvedValue(mockUser);

    const user = await fetchUser(1);
    expect(user).toEqual(mockUser);
    expect(mockFetchUser).toHaveBeenCalledTimes(1);
    expect(mockFetchUser).toHaveBeenCalledWith(1);
  });

  test('fetchUser avec rejet', async () => {
    mockFetchUser.mockRejectedValue(new Error('API down'));
    await expect(fetchUser(1)).rejects.toThrow('API down');
  });
});

Pour async, utilisez async/await dans test et mockResolvedValue. jest.mock remplace la vraie fonction. beforeEach nettoie mocks entre tests. Vérifiez appels avec toHaveBeenCalledWith. Idéal pour APIs sans appels réels, évitant flaky tests.

Exécuter les tests et voir la couverture

terminal
npm test
npm run test:watch
npm run test:coverage

Premier npm test lance et valide. --watch surveille fichiers pour re-run auto (dev idéal). --coverage génère rapport HTML dans coverage/ : visez 80%+ lignes. Ouvre coverage/lcov-report/index.html pour visualiser lignes non couvertes.

Bonnes pratiques

  • Un test = un assert principal : Évitez 10 expect par test ; divisez en tests atomiques pour debug facile.
  • Nommez clairement : test('devrait calculer TVA à 20%', ...) > test('TVA').
  • Mockez les externalities : APIs, DB, timers avec jest.useFakeTimers().
  • Couverture > 80% : Intégrez CI/CD pour enforcer.
  • Tests fast-first : <100ms total, pas d'I/O réel.

Erreurs courantes à éviter

  • Oublier async/await : expect(promise).resolves.toBe() sans await cause timeouts.
  • Ne pas cleaner mocks : beforeEach(mockClear()) évite pollution entre tests.
  • Tests dépendants de l'ordre : describe isole ; sinon flaky.
  • Comparer objets : toBe shallow ; utilisez toEqual ou snapshots toMatchSnapshot().

Pour aller plus loin

Passez aux tests d'intégration avec Supertest ou E2E avec Playwright. Explorez Vitest pour Vite/Next.js (plus rapide). Rejoignez nos formations Learni Dev pour master TDD en React/Node. Docs officielles : Jest.