Du code sans tests est cassé par défaut. Vous ne le savez simplement pas encore. Les tests vous donnent la confiance nécessaire pour refactoriser, livrer des fonctionnalités plus vite et dormir sur vos deux oreilles en sachant qu'un déploiement à 2 heures du matin ne fera pas tomber la production. Ce guide couvre tout ce qu'il faut pour commencer à tester efficacement votre JavaScript.

Les types de tests

  • Tests unitaires : Testent des fonctions ou des modules individuels de manière isolée. Rapides, peu coûteux : il faut en avoir beaucoup.
  • Tests d'intégration : Vérifient comment plusieurs unités fonctionnent ensemble — routes d'API, requêtes en base de données, interactions entre composants.
  • Tests de bout en bout (E2E) : Testent l'application complète du point de vue de l'utilisateur — cliquer sur des boutons, remplir des formulaires, naviguer entre les pages.
La pyramide des tests
         /   Tests E2E    \        ← Peu nombreux (lents, coûteux)
        / Tests d'intégration \    ← En quantité modérée
       /    Tests unitaires     \  ← Nombreux (rapides, peu coûteux)

Premiers pas avec Jest

Installation
# Installer Jest
npm install -D jest

# Pour TypeScript
npm install -D jest ts-jest @types/jest

# Ajouter les scripts de test au package.json
"scripts": {
  "test": "jest",
  "test:watch": "jest --watch",
  "test:coverage": "jest --coverage"
}

Écrire votre premier test

math.js
export function add(a, b) {
  return a + b;
}

export function divide(a, b) {
  if (b === 0) throw new Error('Cannot divide by zero');
  return a / b;
}
math.test.js
import { add, divide } from './math';

describe('add', () => {
  test('additionne deux nombres positifs', () => {
    expect(add(2, 3)).toBe(5);
  });

  test('gère les nombres négatifs', () => {
    expect(add(-1, -1)).toBe(-2);
  });

  test('gère le zéro', () => {
    expect(add(0, 5)).toBe(5);
  });
});

describe('divide', () => {
  test('divise deux nombres', () => {
    expect(divide(10, 2)).toBe(5);
  });

  test('lève une erreur en cas de division par zéro', () => {
    expect(() => divide(10, 0)).toThrow('Cannot divide by zero');
  });
});

Les matchers les plus courants

Matchers Jest
// Égalité
expect(value).toBe(42);              // Égalité stricte (===)
expect(obj).toEqual({ a: 1, b: 2 }); // Égalité profonde

// Valeurs vraies/fausses
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();

// Nombres
expect(value).toBeGreaterThan(3);
expect(value).toBeLessThanOrEqual(10);
expect(0.1 + 0.2).toBeCloseTo(0.3);  // Virgule flottante

// Chaînes de caractères
expect(str).toMatch(/regex/);
expect(str).toContain('substring');

// Tableaux
expect(arr).toContain('item');
expect(arr).toHaveLength(3);

// Objets
expect(obj).toHaveProperty('name');
expect(obj).toMatchObject({ name: 'Alice' });

Les mocks

Simuler des fonctions et des modules
// Simuler une fonction
const mockFn = jest.fn();
mockFn.mockReturnValue(42);
mockFn.mockResolvedValue({ id: 1 }); // Pour l'asynchrone

// Vérifier les appels
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2');
expect(mockFn).toHaveBeenCalledTimes(3);

// Simuler un module
jest.mock('./database', () => ({
  getUser: jest.fn().mockResolvedValue({ id: 1, name: 'Alice' }),
  saveUser: jest.fn().mockResolvedValue(true),
}));

Tester du code asynchrone

Tests asynchrones
// async/await (recommandé)
test('récupère les données utilisateur', async () => {
  const user = await getUser(1);
  expect(user.name).toBe('Alice');
});

// Tester les promesses rejetées
test('lève une erreur pour un ID invalide', async () => {
  await expect(getUser(-1)).rejects.toThrow('Invalid ID');
});

Le développement piloté par les tests (TDD)

  • Rouge : Écrivez d'abord un test qui échoue
  • Vert : Écrivez le minimum de code pour le faire passer
  • Refactoring : Améliorez le code tout en gardant les tests au vert

Le TDD vous oblige à réfléchir à l'interface avant l'implémentation. Le résultat : un code intrinsèquement testable et bien conçu.

Bonnes pratiques

  • Testez le comportement, pas l'implémentation. Si vous refactorisez le fonctionnement interne, les tests ne devraient pas casser.
  • Une assertion par concept testé. Un test ne doit échouer que pour une seule raison.
  • Utilisez des noms de tests descriptifs. "devrait renvoyer 404 quand l'utilisateur est introuvable" vaut mieux que "test getUser".
  • Visez plus de 80 % de couverture de code, mais ne courez pas après les 100 % — les rendements sont décroissants.
  • Exécutez les tests en CI. Chaque pull request doit passer tous les tests avant d'être fusionnée.
  • Gardez des tests rapides. Les tests lents ne sont jamais exécutés. Simulez les dépendances externes.

Essayez nos outils JavaScript gratuits

Minifiez et embellissez vos fichiers de tests JavaScript.