Chapitre 430 minIntermédiaire
Tests unitaires en JavaScript avec Vitest (et Jest)
Par Josselyn C., prof de BTS SIO. Mis à jour le .
À la fin de ce chapitre, tu sauras
- installer Vitest et lancer les tests d'un projet Node.js ;
- choisir le bon matcher et tester une exception ou du code asynchrone ;
- écrire des tests paramétrés et contrôler la date avec les faux minuteurs ;
- lire un test qui échoue et passer d'un test Jest à un test Vitest.
4 exercices corrigés
Vitest est le framework de test JavaScript et TypeScript de l'écosystème Vite : il trouve les fichiers *.test.js, exécute les tests qu'ils contiennent et affiche un bilan, en quelques millisecondes et sans configuration pour un projet moderne en modules ES. Son API (describe, test, expect, vi.fn) reprend celle de Jest, l'outil historique que tu croiseras encore dans beaucoup de projets existants. Ce chapitre teste les règles de Prêt'Matos avec Vitest 5 et montre ce qui change avec Jest 30.
Vitest ou Jest ?
| Vitest 5 | Jest 30 | |
|---|---|---|
Modules ES (import) | Natifs, sans configuration | Expérimentaux : il faut lancer Node avec --experimental-vm-modules, ou rester en CommonJS (require) |
| TypeScript, JSX | Pris en charge directement (transformés par Vite) | Demande une configuration (Babel, ts-jest ou un autre transformateur) |
| Fonctions de test | Importées depuis vitest (ou globales avec l'option globals: true) | Globales : pas d'import |
| Doublures | vi.fn(), vi.spyOn(), vi.mock() | jest.fn(), jest.spyOn(), jest.mock() |
| Mode surveillance | Par défaut dans un terminal (vitest) | Avec l'option --watch |
| Où tu le croises | Projets Vite, React, Vue récents ; nouveaux projets Node.js | Projets existants, React Native, nombreux tutoriels |
Pour un nouveau projet, Vitest est le choix le plus simple en 2026. Si ton projet utilise déjà Jest, garde-le : les concepts sont identiques et les tests se ressemblent ligne pour ligne. Les cours Maintenance applicative et Intégration continue utilisent Jest, ce cours utilise Vitest : tu passeras de l'un à l'autre sans difficulté.
Installer Vitest et lancer les tests
Vitest 5 demande Node.js 22.12 ou plus (Node.js 24 LTS est le bon choix). Dans le projet Prêt'Matos, dont le package.json contient "type": "module" :
npm install --save-dev vitest
--save-dev range Vitest dans les devDependencies : il sert à développer, pas à faire tourner l'application en production. On ajoute ensuite des scripts dans package.json :
{
"type": "module",
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:couverture": "vitest run --coverage"
}
}
| Commande | Effet |
|---|---|
npm test | Lance tous les tests une fois et rend la main : c'est ce que fera la CI |
npm run test:watch | Lance les tests, puis les relance automatiquement à chaque enregistrement d'un fichier |
npx vitest run src/regles.test.js | Lance un seul fichier |
npx vitest run -t "16 jours" | Lance seulement les tests dont le nom contient « 16 jours » |
npm run test:couverture | Lance les tests et mesure la couverture de code (chapitre 12) |
Par défaut, Vitest cherche les fichiers dont le nom se termine par .test.js ou .spec.js (et leurs variantes .ts, .jsx, .tsx, .mjs…), partout dans le projet sauf dans node_modules. Deux organisations sont courantes : le fichier de test à côté du fichier testé (src/regles.js et src/regles.test.js), ou un dossier tests/ séparé. Ce cours range les tests à côté du code : on les voit, on les met à jour en même temps.
La suite de tests des règles de Prêt'Matos
Voici le fichier de test complet de src/regles.js. Lis-le en entier : il applique tout ce que dit le chapitre 3.
// src/regles.test.js
import { describe, test, expect } from 'vitest';
import { dureeEnJours, periodesSeChevauchent, verifierReservation, joursDeRetard } from './regles.js';
describe('dureeEnJours', () => {
test('compte le premier et le dernier jour', () => {
expect(dureeEnJours('2027-03-12', '2027-03-18')).toBe(7);
});
test('vaut 1 pour un prêt rendu le jour même', () => {
expect(dureeEnJours('2027-03-12', '2027-03-12')).toBe(1);
});
test('traverse la fin du mois de février', () => {
expect(dureeEnJours('2027-02-26', '2027-03-02')).toBe(5);
});
});
describe('periodesSeChevauchent', () => {
const pc07 = { debut: '2027-03-10', fin: '2027-03-14' };
test.each([
{ cas: 'commence pendant', debut: '2027-03-12', fin: '2027-03-18', attendu: true },
{ cas: 'finit le premier jour', debut: '2027-03-05', fin: '2027-03-10', attendu: true },
{ cas: 'englobe', debut: '2027-03-01', fin: '2027-03-31', attendu: true },
{ cas: 'commence le lendemain', debut: '2027-03-15', fin: '2027-03-20', attendu: false },
{ cas: 'finit la veille', debut: '2027-03-01', fin: '2027-03-09', attendu: false },
])('une période qui $cas → $attendu', ({ debut, fin, attendu }) => {
expect(periodesSeChevauchent(pc07, { debut, fin })).toBe(attendu);
});
});
describe('verifierReservation', () => {
const aujourdhui = '2027-03-08';
const reservations = [{ materiel: 'PC-07', debut: '2027-03-10', fin: '2027-03-14' }];
test('accepte un matériel libre sur toute la période', () => {
const demande = { materiel: 'PC-07', debut: '2027-03-15', fin: '2027-03-18' };
const resultat = verifierReservation(demande, reservations, aujourdhui);
expect(resultat).toEqual({ acceptee: true });
});
test('refuse un matériel déjà réservé sur une partie de la période', () => {
const demande = { materiel: 'PC-07', debut: '2027-03-12', fin: '2027-03-18' };
const resultat = verifierReservation(demande, reservations, aujourdhui);
expect(resultat.acceptee).toBe(false);
expect(resultat.motif).toBe('PC-07 est déjà réservé du 10/03/2027 au 14/03/2027.');
});
test('ignore les réservations des autres matériels', () => {
const demande = { materiel: 'VP-02', debut: '2027-03-12', fin: '2027-03-13' };
expect(verifierReservation(demande, reservations, aujourdhui).acceptee).toBe(true);
});
test("accepte une réservation qui commence aujourd'hui", () => {
const demande = { materiel: 'VP-02', debut: '2027-03-08', fin: '2027-03-09' };
expect(verifierReservation(demande, reservations, aujourdhui).acceptee).toBe(true);
});
test('refuse une date de début passée', () => {
const demande = { materiel: 'VP-02', debut: '2027-03-07', fin: '2027-03-09' };
expect(verifierReservation(demande, reservations, aujourdhui).motif).toBe('La date de début est déjà passée.');
});
test('accepte un prêt de 15 jours, la durée maximale', () => {
const demande = { materiel: 'VP-02', debut: '2027-03-15', fin: '2027-03-29' };
expect(verifierReservation(demande, reservations, aujourdhui).acceptee).toBe(true);
});
test('refuse un prêt de 16 jours', () => {
const demande = { materiel: 'VP-02', debut: '2027-03-15', fin: '2027-03-30' };
expect(verifierReservation(demande, reservations, aujourdhui).motif).toBe('Un prêt dure au plus 15 jours.');
});
test('refuse une date de fin avant la date de début', () => {
const demande = { materiel: 'VP-02', debut: '2027-03-20', fin: '2027-03-19' };
expect(verifierReservation(demande, reservations, aujourdhui).motif).toBe('La date de fin précède la date de début.');
});
});
describe('joursDeRetard', () => {
test('vaut 0 le jour du retour prévu', () => {
expect(joursDeRetard('2027-03-14', '2027-03-14')).toBe(0);
});
test('vaut 0 avant le retour prévu', () => {
expect(joursDeRetard('2027-03-14', '2027-03-10')).toBe(0);
});
test('compte les jours après le retour prévu', () => {
expect(joursDeRetard('2027-03-14', '2027-03-17')).toBe(3);
});
});
Et voici le code testé, en entier :
// src/regles.js : les règles de réservation de Prêt'Matos
export const DUREE_MAX_JOURS = 15;
const MS_PAR_JOUR = 24 * 60 * 60 * 1000;
// « 2027-03-12 » devient un numéro de jour : on compare des jours, pas des heures.
function numeroDeJour(dateIso) {
const [annee, mois, jour] = dateIso.split('-').map(Number);
return Date.UTC(annee, mois - 1, jour) / MS_PAR_JOUR;
}
// « 2027-03-12 » devient « 12/03/2027 ».
export function formaterDate(dateIso) {
const [annee, mois, jour] = dateIso.split('-');
return `${jour}/${mois}/${annee}`;
}
// Du 12 au 18 mars : 7 jours, le premier et le dernier compris.
export function dureeEnJours(debut, fin) {
return numeroDeJour(fin) - numeroDeJour(debut) + 1;
}
// Deux périodes se chevauchent si chacune commence avant la fin de l'autre.
export function periodesSeChevauchent(a, b) {
return numeroDeJour(a.debut) <= numeroDeJour(b.fin) && numeroDeJour(b.debut) <= numeroDeJour(a.fin);
}
export function verifierReservation(demande, reservations, aujourdhui) {
if (numeroDeJour(demande.fin) < numeroDeJour(demande.debut)) {
return { acceptee: false, motif: 'La date de fin précède la date de début.' };
}
if (numeroDeJour(demande.debut) < numeroDeJour(aujourdhui)) {
return { acceptee: false, motif: 'La date de début est déjà passée.' };
}
if (dureeEnJours(demande.debut, demande.fin) > DUREE_MAX_JOURS) {
return { acceptee: false, motif: `Un prêt dure au plus ${DUREE_MAX_JOURS} jours.` };
}
const conflit = reservations.find(
(r) => r.materiel === demande.materiel && periodesSeChevauchent(r, demande),
);
if (conflit) {
return {
acceptee: false,
motif: `${demande.materiel} est déjà réservé du ${formaterDate(conflit.debut)} au ${formaterDate(conflit.fin)}.`,
};
}
return { acceptee: true };
}
// Nombre de jours de retard d'un prêt à la date du jour (0 s'il n'est pas en retard).
export function joursDeRetard(retourPrevu, aujourdhui) {
return Math.max(0, numeroDeJour(aujourdhui) - numeroDeJour(retourPrevu));
}
On lance la suite :
$ npx vitest run src/regles.test.js
✓ src/regles.test.js (19 tests) 6ms
Test Files 1 passed (1)
Tests 19 passed (19)
Avec --reporter=verbose, Vitest affiche chaque test sur sa ligne : le nom du describe, puis celui du test. C'est là qu'on voit l'intérêt des noms en forme de phrase.
✓ src/regles.test.js > periodesSeChevauchent > une période qui commence pendant → true 1ms
✓ src/regles.test.js > periodesSeChevauchent > une période qui finit le premier jour → true 0ms
✓ src/regles.test.js > verifierReservation > refuse un prêt de 16 jours 0ms
Les blocs describe et les fonctions de préparation
describe regroupe les tests d'une même fonction ou d'un même scénario. Les variables déclarées dans un describe (comme aujourdhui et reservations) sont partagées par ses tests : à condition qu'aucun test ne les modifie. Dès qu'un test modifie une donnée commune, il faut la recréer avant chaque test avec beforeEach :
import { describe, test, expect, beforeEach } from 'vitest';
describe('le dépôt en mémoire', () => {
let depot;
beforeEach(() => {
// Un dépôt neuf avant CHAQUE test : aucun test ne voit les ajouts d'un autre.
depot = creerDepotMemoire(jeuDeTest());
});
test('ajoute une réservation', async () => {
await depot.ajouterReservation({ materiel: 'VP-02', debut: '2027-03-15', fin: '2027-03-18', salarie: 3 });
expect(await depot.reservationsDu('VP-02')).toHaveLength(1);
});
test('ne contient au départ aucune réservation de VP-02', async () => {
expect(await depot.reservationsDu('VP-02')).toHaveLength(0);
});
});
| Fonction | Exécutée… | Usage typique |
|---|---|---|
beforeEach | avant chaque test du bloc | Recréer les données, remettre une doublure à zéro |
afterEach | après chaque test du bloc | Remettre la vraie horloge, nettoyer le DOM |
beforeAll | une fois, avant le premier test du bloc | Ouvrir une connexion à une base de test |
afterAll | une fois, après le dernier test du bloc | Fermer la connexion |
Les matchers essentiels
Un matcher est la méthode appelée sur expect(…) pour comparer. Tous peuvent être inversés avec .not : expect(liste).not.toContain('PC-07').
| Matcher | Vérifie que… | Exemple |
|---|---|---|
toBe(v) | la valeur est identique (Object.is) : nombres, chaînes, booléens | expect(duree).toBe(7) |
toEqual(obj) | le contenu est égal, récursivement : objets et tableaux | expect(resultat).toEqual({ acceptee: true }) |
toStrictEqual(obj) | comme toEqual, en tenant compte aussi des propriétés undefined et des classes | expect(reservation).toStrictEqual(attendue) |
toMatchObject(obj) | l'objet contient au moins ces propriétés | expect(reponse.body).toMatchObject({ materiel: 'VP-02' }) |
toContain(x) | un tableau contient l'élément, ou une chaîne la sous-chaîne | expect(codes).toContain('VP-02') |
toHaveLength(n) | la longueur d'un tableau ou d'une chaîne | expect(reservations).toHaveLength(1) |
toBeNull(), toBeUndefined(), toBeDefined() | la valeur est null, undefined ou définie | expect(depot.trouver(99)).toBeNull() |
toBeTruthy(), toBeFalsy() | la valeur est vraie ou fausse au sens de JavaScript | à éviter quand toBe(true) est possible |
toBeGreaterThan(n), toBeLessThanOrEqual(n) | comparaison numérique | expect(id).toBeGreaterThan(1) |
toBeCloseTo(n) | un nombre à virgule est proche de n | expect(0.1 + 0.2).toBeCloseTo(0.3) |
toMatch(regex) | une chaîne respecte une expression régulière | expect(motif).toMatch(/déjà réservé/) |
toThrow(…) | une fonction lève une exception | voir plus bas |
La confusion la plus fréquente est toBe sur un objet :
AssertionError: expected { acceptee: true } to be { acceptee: true } // Object.is equality
If it should pass with deep equality, replace "toBe" with "toStrictEqual"
Deux objets créés séparément ne sont jamais le même objet, même avec le même contenu : toBe compare les références. Pour comparer le contenu, utilise toEqual. Vitest le suggère d'ailleurs dans son message.
Tester une exception
Pour vérifier qu'une fonction lève une erreur, on passe à expect une fonction qui fait l'appel, pas l'appel lui-même :
// src/dates.js
export function exigerDateIso(valeur) {
if (!/^\d{4}-\d{2}-\d{2}$/.test(valeur)) {
throw new TypeError(`Date invalide : ${valeur}`);
}
return valeur;
}
test('lève une TypeError pour une date au format français', () => {
expect(() => exigerDateIso('14/03/2027')).toThrow(TypeError);
expect(() => exigerDateIso('14/03/2027')).toThrow('Date invalide : 14/03/2027');
});
Si tu écris expect(exigerDateIso('14/03/2027')).toThrow(), l'exception est levée avant qu'expect ne soit appelé : le test échoue avec l'erreur de la fonction, au lieu de la constater. Le () => retarde l'appel pour que Vitest puisse l'attraper.
Tester du code asynchrone
Les fonctions qui accèdent à une base ou au réseau renvoient des promesses. Un test asynchrone est une fonction async, et chaque appel asynchrone est attendu avec await :
test('ajoute une réservation et la retrouve', async () => {
const depot = creerDepotMemoire(jeuDeTest());
await depot.ajouterReservation({ materiel: 'VP-02', debut: '2027-03-15', fin: '2027-03-18', salarie: 3 });
const reservations = await depot.reservationsDu('VP-02');
expect(reservations).toHaveLength(1);
});
Pour vérifier directement le résultat d'une promesse, resolves et rejects existent, toujours précédés de await :
await expect(depot.reservationsDu('VP-02')).resolves.toHaveLength(0);
await expect(lireFichierAbsent()).rejects.toThrow('ENOENT');
Les tests paramétrés : test.each
Quand plusieurs tests ne diffèrent que par leurs données, on les écrit une fois avec test.each. Chaque ligne du tableau donne un test séparé, avec son propre nom et son propre résultat. Avec des lignes en objets, $cas ou $attendu dans le nom sont remplacés par la valeur de la propriété correspondante : c'est ce que fait le bloc periodesSeChevauchent ci-dessus. On peut aussi écrire les lignes en tableaux, et utiliser %s (chaîne), %i (entier) ou %o (objet) dans le nom :
test.each([
['2027-03-31', '2027-04-01'],
['2027-12-31', '2028-01-01'],
['2028-02-28', '2028-02-29'],
])('le lendemain du %s est le %s', (date, attendu) => {
expect(lendemain(date)).toBe(attendu);
});
Contrôler le temps avec les faux minuteurs
Certaines fonctions doivent lire l'horloge : la date du jour envoyée à verifierReservation vient bien de quelque part. Cette fonction donne la date du jour à Paris, au format AAAA-MM-JJ :
// src/dates.js
// La date du jour à Paris, au format AAAA-MM-JJ (le format suédois « sv-SE » est justement celui-ci).
export function aujourdhuiAParis() {
return new Date().toLocaleDateString('sv-SE', { timeZone: 'Europe/Paris' });
}
Pour la tester, Vitest remplace l'horloge par une horloge simulée : vi.useFakeTimers() l'active, vi.setSystemTime() choisit l'instant, vi.useRealTimers() rend la vraie.
import { describe, test, expect, vi, afterEach } from 'vitest';
import { aujourdhuiAParis } from './dates.js';
describe('aujourdhuiAParis', () => {
afterEach(() => {
vi.useRealTimers();
});
test('donne la date de Paris, pas celle de Londres', () => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2027-03-13T23:30:00Z')); // 00 h 30 le 14 mars à Paris
expect(aujourdhuiAParis()).toBe('2027-03-14');
});
});
Ce test choisit exprès un instant piège : 23 h 30 en temps universel, soit 0 h 30 le lendemain à Paris (heure d'hiver, UTC+1). Une implémentation naïve avec new Date().toISOString().slice(0, 10) renverrait 2027-03-13, la date de Londres. Le test passe quel que soit le fuseau de la machine qui le lance, ce qui le rend reproductible.
Les faux minuteurs servent aussi pour setTimeout et setInterval : vi.advanceTimersByTime(60_000) fait avancer l'horloge d'une minute instantanément, sans attendre.
Isoler, sauter, marquer à faire
| Écriture | Effet |
|---|---|
test.only('…', …) | Seuls les tests marqués only du fichier s'exécutent : pratique pour déboguer, à ne jamais committer |
test.skip('…', …) | Le test est sauté et compté comme tel dans le bilan |
test.todo('refuse un matériel en réparation') | Un test à écrire : il apparaît dans le bilan comme un rappel |
describe.skipIf(condition)('…', …) | Saute tout le bloc si la condition est vraie, par exemple quand aucune base de test n'est configurée (chapitre 8) |
Configurer Vitest
Sans configuration, Vitest teste du code Node.js. Un fichier vitest.config.js à la racine (ou une clé test dans vite.config.js pour un projet Vite) change les réglages :
// vitest.config.js
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node', // 'jsdom' pour tester des composants React (chapitre 9)
include: ['src/**/*.test.js'], // où chercher les tests
coverage: {
provider: 'v8',
include: ['src/**/*.js'],
},
},
});
Lire un test qui échoue
Un test rouge est une information, pas une catastrophe. Voici ce qu'affiche Vitest si l'on remplace, dans periodesSeChevauchent, le premier <= par < :
❯ src/regles.test.js (19 tests | 1 failed) 7ms
❯ periodesSeChevauchent (5)
× une période qui finit le premier jour → true 4ms
FAIL src/regles.test.js > periodesSeChevauchent > une période qui finit le premier jour → true
AssertionError: expected false to be true // Object.is equality
- Expected
+ Received
- true
+ false
❯ src/regles.test.js:29:57
Lis-le dans cet ordre :
- Le nom du test : « une période qui finit le premier jour ». Tu sais déjà quel cas est cassé : une limite.
- L'assertion : on attendait
true, on a obtenufalse. Le code ne voit plus de chevauchement quand la demande finit le jour où la réservation commence. - L'emplacement : la ligne 29 du fichier de test, avec l'extrait du code.
- Les tests verts : les 18 autres passent, dont « commence pendant » et « englobe ». Le défaut ne touche que la frontière, ce qui oriente directement vers un
<ou un<=.
Et avec Jest ?
Le même test, écrit pour Jest 30 dans un projet en CommonJS :
// regles.test.js, version Jest : describe, test et expect sont globaux
const { dureeEnJours } = require('./regles.cjs');
describe('dureeEnJours', () => {
test('compte le premier et le dernier jour', () => {
expect(dureeEnJours('2027-03-12', '2027-03-18')).toBe(7);
});
});
npm install --save-dev jest
npx jest
| Vitest | Jest |
|---|---|
import { describe, test, expect, vi } from 'vitest' | rien à importer : describe, test, expect, jest sont globaux |
vi.fn(), vi.spyOn(), vi.mock() | jest.fn(), jest.spyOn(), jest.mock() |
vi.useFakeTimers(), vi.setSystemTime() | jest.useFakeTimers(), jest.setSystemTime() |
vitest run, vitest | jest, jest --watch |
vitest.config.js | jest.config.js |
Les matchers (toBe, toEqual, toThrow…) sont les mêmes. Pour migrer un projet de Jest vers Vitest, on remplace jest. par vi., on ajoute les imports (ou l'option globals: true), et on supprime la configuration Babel devenue inutile.
Exercices
Exercice 1 sur 4 Écrire les tests d'une fonction Réussi À revoir
Voici la fonction lendemain de Prêt'Matos. Écris ses tests avec Vitest : au moins quatre cas bien choisis, dont les cas pièges des dates.
// src/rappels.js
export function lendemain(dateIso) {
const date = new Date(`${dateIso}T00:00:00Z`);
date.setUTCDate(date.getUTCDate() + 1);
return date.toISOString().slice(0, 10);
}
Voir la réponseMasquer la réponse de l'exercice 1
Les classes intéressantes sont : un jour ordinaire, la fin d'un mois de 31 jours, la fin d'un mois de 30 jours, la fin de février (bissextile ou non) et la fin d'année.
import { test, expect } from 'vitest';
import { lendemain } from './rappels.js';
test.each([
{ cas: 'un jour ordinaire', date: '2027-03-13', attendu: '2027-03-14' },
{ cas: "la fin d'un mois de 31 jours", date: '2027-03-31', attendu: '2027-04-01' },
{ cas: "la fin d'un mois de 30 jours", date: '2027-04-30', attendu: '2027-05-01' },
{ cas: "le 28 février d'une année non bissextile", date: '2027-02-28', attendu: '2027-03-01' },
{ cas: "le 28 février d'une année bissextile", date: '2028-02-28', attendu: '2028-02-29' },
{ cas: "la fin d'année", date: '2027-12-31', attendu: '2028-01-01' },
])('le lendemain de $cas', ({ date, attendu }) => {
expect(lendemain(date)).toBe(attendu);
});
Un cas de plus vaut la peine : le 28 mars 2027, nuit du passage à l'heure d'été. La fonction travaille en UTC, donc lendemain('2027-03-28') donne bien '2027-03-29' ; une version qui utiliserait l'heure locale et ajouterait 24 heures pourrait tomber à côté.
Tu avais trouvé ?
Exercice 2 sur 4 Choisir le matcher Réussi À revoir
Pour chaque vérification, donne le matcher le plus adapté.
- La réponse de l'API contient
materiel: 'VP-02'etsalarie: 3, parmi d'autres propriétés. verifierReservationrenvoie exactement{ acceptee: true }.- Le total d'une note vaut 0,3 (calcul en virgule flottante).
- La liste des codes de matériel contient
'PC-07'. trouverPret(999)renvoienull.- Le motif de refus contient les mots « déjà réservé ».
Voir la réponseMasquer la réponse de l'exercice 2
toMatchObject({ materiel: 'VP-02', salarie: 3 }): l'objet contient au moins ces propriétés.toEqual({ acceptee: true })(outoStrictEqual), pastoBe, qui comparerait les références.toBeCloseTo(0.3).toContain('PC-07').toBeNull().toMatch(/déjà réservé/)outoContain('déjà réservé').
Tu avais trouvé ?
Exercice 3 sur 4 Le test toujours vert Réussi À revoir
Ce test est vert, et pourtant la méthode reservationsDu renvoie une liste vide à cause d'un bug. Trouve la cause et corrige le test.
test('retrouve la réservation de PC-07', () => {
const depot = creerDepotMemoire(jeuDeTest());
depot.reservationsDu('PC-07').then((reservations) => {
expect(reservations).toHaveLength(1);
});
});
Voir la réponseMasquer la réponse de l'exercice 3
La fonction de test n'attend pas la promesse : elle se termine immédiatement, avant que le then ne s'exécute. Vitest considère le test comme réussi, puisqu'aucune assertion n'a échoué pendant son exécution. On rend le test asynchrone et on attend le résultat :
test('retrouve la réservation de PC-07', async () => {
const depot = creerDepotMemoire(jeuDeTest());
const reservations = await depot.reservationsDu('PC-07');
expect(reservations).toHaveLength(1);
});
Pour t'en assurer, fais échouer le test exprès (attends toHaveLength(5)) : la version corrigée passe au rouge, l'ancienne restait verte.
Tu avais trouvé ?
Exercice 4 sur 4 Migrer de Jest à Vitest Réussi À revoir
Convertis ce test Jest en test Vitest pour un projet en modules ES.
const { envoyerRappels } = require('./rappels');
test("n'envoie rien quand aucun prêt ne se termine demain", async () => {
const depot = { pretsARendreLe: jest.fn().mockResolvedValue([]) };
const messagerie = { envoyer: jest.fn() };
await envoyerRappels({ depot, messagerie, journal: {}, aujourdhui: '2027-03-13' });
expect(messagerie.envoyer).not.toHaveBeenCalled();
});
Voir la réponseMasquer la réponse de l'exercice 4
import { test, expect, vi } from 'vitest';
import { envoyerRappels } from './rappels.js';
test("n'envoie rien quand aucun prêt ne se termine demain", async () => {
const depot = { pretsARendreLe: vi.fn().mockResolvedValue([]) };
const messagerie = { envoyer: vi.fn() };
await envoyerRappels({ depot, messagerie, journal: {}, aujourdhui: '2027-03-13' });
expect(messagerie.envoyer).not.toHaveBeenCalled();
});
Trois changements : import au lieu de require (avec l'extension .js, obligatoire en modules ES), l'import de test, expect et vi depuis vitest, et vi.fn() à la place de jest.fn(). Le reste est identique.
Tu avais trouvé ?