J 2 — Jest : les bases

describe, it, expect — tester comme un pro

Bootcode IWA-S04 — Semaine 15, Jour 2

Objectifs de la leçon

1. Écrire des tests complets

Pour un service métier avec describe et it

2. Injecter un InMemoryRepository

Tester sans base de données

3. Tester les cas d'erreur

Avec toThrow pour les exceptions

4. Organiser avec beforeEach

Chaque test repart de zéro

Plan du cours

1

La syntaxe Jest : describe, it, expect

Structurer ses tests comme des phrases

2

Les matchers essentiels

toBe, toEqual, toThrow, toContain

3

toBe vs toEqual

Primitifs vs objets — l'erreur classique

4

beforeEach : préparer les données

Chaque test repart de zéro

5

Tester les erreurs avec toThrow

Attention à la syntaxe — passer une fonction

Module 1

La syntaxe Jest

describe, it, expect — structurer ses tests

La philosophie de Jest

Un test = une phrase lisible par un humain

describe('UserService', () => {

it('should create a user with a valid email', () => {

const user = createUser('[email protected]');

expect(user.email).toBe('[email protected]');

});

});

💡 Lit la phrase à voix haute :

"UserService should create a user with a valid email" — ça a du sens !

describe — grouper ses tests

// describe = un bloc, un "sujet" de test

describe('UserService', () => {

// tous les tests liés à UserService

it('should create a user', () => { ... });

it('should delete a user', () => { ... });

it('should throw on invalid email', () => { ... });

});

describe

Le "sujet"

it

Le "comportement"

expect

L'"assertion"

💡 On peut imbriquer des describe pour organiser : describe('UserService') → describe('create()')

it — un cas de test

it('should add two numbers', () => {

// 1ïžâƒŁ Arrange — prĂ©parer

const a = 2, b = 3;

// 2ïžâƒŁ Act — exĂ©cuter

const result = add(a, b);

// 3ïžâƒŁ Assert — vĂ©rifier

expect(result).toBe(5);

});

📋 Le pattern AAA : Arrange, Act, Assert

Chaque it suit ce schĂ©ma — un seul comportement testĂ© par it

💡 Le nom du it commence par "should" — lisible comme une phrase en anglais

expect — l'assertion

// expect(valeur) .matcher(valeurAttendue)

expect(add(2, 3)).toBe(5);

// expect reçoit la valeur réelle, le matcher reçoit l'attendu

expect(user.email).toBe('[email protected]');

expect(valeur)

La valeur réelle produite par ton code

.matcher(attendu)

La comparaison + la valeur qu'on espĂšre

💡 On peut enchaĂźner plusieurs expect dans un mĂȘme it, mais un seul comportement testĂ©

Module 2

Les matchers essentiels

toBe, toEqual, toContain, toThrow

toBe — l'Ă©galitĂ© stricte

// toBe = === (strict equality)

expect(1 + 1).toBe(2);

expect('hello').toBe('hello');

expect(true).toBe(true);

// Pour les primitifs : number, string, boolean

toBe compare la valeur ET le type — comme === en JavaScript

⚠ toBe sur un objet = compare la RÉFÉRENCE

Deux objets identiques mais séparés ne sont pas toBe !

toEqual — la comparaison profonde

// toEqual compare le CONTENU, pas la référence

const a = { nom: 'Alice' };

const b = { nom: 'Alice' };

expect(a).toBe(b); // ❌ rĂ©fĂ©rences diffĂ©rentes

expect(a).toEqual(b); // ✅ mĂȘme contenu

toBe

Référence (identité)

a === b ?

toEqual

Contenu (valeur)

MĂȘmes clĂ©s/valeurs ?

💡 Rùgle d'or : toBe pour les primitifs, toEqual pour les objets et tableaux

toContain — vĂ©rifier une inclusion

// Dans un tableau

expect(['Alice', 'Bob']).toContain('Alice');

// Dans une chaĂźne

expect('Hello World').toContain('World');

Tableaux

L'élément est-il présent ?

ChaĂźnes

La sous-chaßne est-elle présente ?

💡 Pratique pour vĂ©rifier qu'un utilisateur est dans une liste, ou qu'un message d'erreur contient un mot-clĂ©

Module 3

toBe vs toEqual

Primitifs vs objets — l'erreur classique

toBe vs toEqual — l'erreur classique

❌ toBe sur un objet

const user1 = { nom: 'Alice' };

const user2 = { nom: 'Alice' };

expect(user1).toBe(user2);

// ❌ ÉCHEC !

// Deux objets distincts

// Pas la mĂȘme rĂ©fĂ©rence

✅ toEqual sur un objet

const user1 = { nom: 'Alice' };

const user2 = { nom: 'Alice' };

expect(user1).toEqual(user2);

// ✅ SUCCÈS !

// MĂȘme contenu

// Comparaison profonde

🔑 toBe = === (mĂȘme rĂ©fĂ©rence) · toEqual = comparaison profonde du contenu

Et pour les primitifs ?

// Pour les primitifs, toBe et toEqual sont équivalents

expect(42).toBe(42); // ✅

expect(42).toEqual(42); // ✅

// Mais pour les objets, ça change tout !

expect({ a: 1 }).toBe({ a: 1 }); // ❌

expect({ a: 1 }).toEqual({ a: 1 }); // ✅

📋 Convention de l'Ă©cosystĂšme :

  • ‱ toBe pour number, string, boolean
  • ‱ toEqual pour object, array
  • ‱ toBeNull, toBeUndefined, toBeTruthy pour les cas spĂ©ciaux

Module 4

beforeEach

PrĂ©parer les donnĂ©es — chaque test repart de zĂ©ro

Le problĂšme sans beforeEach

describe('UserService', () => {

let repo, service;

it('should add Alice', () => {

repo = new InMemoryRepo();

service = new UserService(repo);

service.create('Alice');

expect(repo.count()).toBe(1);

});

it('should add Bob', () => {

// đŸ˜± Il faut tout recrĂ©er Ă  chaque fois !

repo = new InMemoryRepo();

service = new UserService(repo);

service.create('Bob');

expect(repo.count()).toBe(1);

});

});

⚠ Code dupliquĂ© Ă  chaque test — et si un test modifie l'Ă©tat, le suivant hĂ©rite du dĂ©sordre !

beforeEach — la solution

describe('UserService', () => {

let repo, service;

beforeEach(() => {

// Exécuté AVANT chaque it

repo = new InMemoryRepo();

service = new UserService(repo);

});

it('should add Alice', () => {

service.create('Alice');

expect(repo.count()).toBe(1);

});

it('should add Bob', () => {

service.create('Bob');

expect(repo.count()).toBe(1); // ✅ repart de zĂ©ro

});

});

✅ Chaque it dĂ©marre avec un Ă©tat frais — indĂ©pendance garantie !

Module 5

Tester les erreurs avec toThrow

Attention à la syntaxe — passer une fonction !

toThrow — le piùge de la syntaxe

❌ Mauvaise syntaxe

// La fonction est exécutée

// AVANT que expect la voie

expect(createUser(''))

.toThrow('Invalid email');

// ❌ L'erreur est lancĂ©e

// AVANT le expect !

// Le test crash au lieu de passer

✅ Bonne syntaxe

// On passe une FONCTION

// Jest l'appelle lui-mĂȘme

expect(() => createUser(''))

.toThrow('Invalid email');

// ✅ Jest capture l'erreur

// et vérifie le message

🔑 expect(() => fn()).toThrow() — toujours passer une FONCTION, pas le rĂ©sultat

toThrow — les variations

// Vérifier qu'une erreur est lancée (sans message)

expect(() => createUser('')).toThrow();

// Vérifier le message exact

expect(() => createUser('')).toThrow('Invalid email');

// Vérifier avec une RegExp

expect(() => createUser('')).toThrow(/invalid/i);

// Vérifier le type d'erreur

expect(() => createUser('')).toThrow(ValidationError);

💡 toThrow sans argument = juste vĂ©rifier qu'une erreur est lancĂ©e. Avec argument = vĂ©rifier le message ou le type.

Exemple complet — tester un service

describe('UserService', () => {

let repo, service;

beforeEach(() => {

repo = new InMemoryRepo();

service = new UserService(repo);

});

describe('create()', () => {

it('should create a user with valid email', () => {

const user = service.create('[email protected]');

expect(user.email).toBe('[email protected]');

expect(user.id).toBeDefined();

});

it('should throw on empty email', () => {

expect(() => service.create('')).toThrow('Invalid email');

});

});

});

1ïžâƒŁ beforeEach

État frais

2ïžâƒŁ Cas de succĂšs

toBe / toEqual

3ïžâƒŁ Cas d'erreur

toThrow

⚠ PiĂšges courants Ă  Ă©viter

❌ toBe pour comparer des objets

Ça compare les rĂ©fĂ©rences, pas le contenu → utiliser toEqual

❌ expect(fn()).toThrow()

La fonction s'exĂ©cute avant le expect → utiliser expect(() => fn()).toThrow()

❌ Tests qui dĂ©pendent de l'ordre

Un test modifie l'Ă©tat, le suivant en dĂ©pend → toujours utiliser beforeEach

❌ Plusieurs comportements par it

Un it = un comportement — sinon les erreurs sont difficiles à diagnostiquer

À retenir !

📝

describe / it / expect

Sujet · comportement · assertion

⚖

toBe vs toEqual

Primitifs (===) vs objets (profond)

🎯

toThrow = une fonction

expect(() => fn()).toThrow()

🔄

beforeEach = indépendance

Chaque test repart de zéro

Questions ?

Tester, c'est coder en confiance

Prochaine étape : tester une vraie API avec mocks et spies