Tu testes déjà, sans le savoir
Tu écris une fonction double. Tu l'appelles dans la console : double(5). Tu regardes si le résultat a l'air bon. Tu essaies avec double(0), tu jettes un œil. Ça marche, ou du moins ça en a l'air. Tu passes à la suite.
Ce que tu viens de faire, c'est un test. Un test manuel, jeté, non rejouable. Le lendemain, tu modifies la fonction pour ajouter un cas. Tu dois tout re-regarder à l'œil : double(5), double(0), double(-3)… À chaque modification, la même cérémonie. C'est épuisant. Et surtout faillible : tu oublies un cas, tu fais confiance à ta mémoire, tu passes à côté du bug.
Le piège du test visuel : regarder un résultat dans la console, c'est une vérification humaine. Elle dépend de ton attention du moment et disparaît dès que tu fermes l'onglet. La prochaine fois que quelqu'un modifie cette fonction (toi dans deux semaines, ou l'IA), personne ne sait qu'il faut re-vérifier. Le test automatisé, lui, re-joue la vérification à chaque fois, sans se fatiguer.
La fonction fait return n + 2. Que renvoie double(5) ? Et double(0) ? Lequel des deux tests va passer au rouge ? Écris les deux valeurs avant de dérouler.
Voir la réponse
double(5) renvoie 7 (5 + 2 = 7, attendu 10 → rouge). double(0) renvoie 2 (0 + 2 = 2, attendu 0 → rouge aussi). Les deux tests échouent : n + 2 n'est jamais égal à n * 2, sauf si n vaut 2. Ici, ni 5 ni 0 ne sont 2. Dans le labo ci-dessous, tu vas le confirmer en direct, puis corriger la fonction d'un seul mot.
Un test, c'est un if et une erreur
Oublie les frameworks une seconde. Dans son essence, un test, c'est ça :
if (double(5) !== 10) {
throw new Error('double(5) devrait valoir 10, mais vaut ' + double(5));
}
Trois étapes : exécuter le code (double(5)), comparer au résultat attendu (!== 10), et lever une erreur si ça ne colle pas. C'est tout. Rien de magique.
Si tu veux écrire plusieurs vérifications, tu peux te fabriquer un mini expect maison :
function expect(actual) {
return {
toBe(attendu) {
if (actual !== attendu) {
throw new Error('attendu ' + attendu + ', reçu ' + actual);
}
}
};
}
// Usage :
expect(double(5)).toBe(10); // lève une erreur si double(5) !== 10
Info : test() et expect() d'un framework comme Vitest ou Jest, c'est exactement ces quelques lignes, en plus présentable. Ils ajoutent un nom de test, une sortie colorée, et la capacité de continuer après un échec. Mais le mécanisme central reste identique : comparer, puis jeter une erreur si ça diffère.
À toi : corrige la fonction
Dans ce labo, test() et expect() sont déjà fournis : tu n'as qu'à éditer le code de la fonction. Lance les tests : ils vont passer au rouge. Lis le message d'erreur, corrige la fonction, relance jusqu'au vert.
Bloqué sur la correction ? Voir le fix
Remplace n + 2 par n * 2. La ligne devient return n * 2;. Relance : les deux tests passent au vert. La fonction s'appelle double : elle doit multiplier par deux, pas ajouter deux. Un seul caractère changeait tout : le + devait être un *.
Lis le message d'erreur avant de corriger. Il te dit exactement ce que la fonction a renvoyé (7) et ce qu'elle aurait dû renvoyer (10). C'est cette précision qui fait la valeur du test sur un simple coup d'œil dans la console.
Pourquoi un framework, alors ?
Si un if/throw suffit, pourquoi tout le monde parle de Vitest et Jest ? La réponse est honnête : même principe, mais le framework rend la vie plus confortable.
Ce que ton if/throw maison ne fait pas facilement :
- Regrouper les tests et leur donner un nom lisible : tu sais ce qui échoue sans décrypter le message d'erreur.
- Afficher rouge/vert proprement, avec un récapitulatif en fin de suite.
- Continuer après un échec : un
thrownu arrête tout au premier test raté ; un framework exécute tous les tests et te liste tout ce qui cloche.
Règle d'or : avant d'ouvrir la doc d'un framework, formule toujours le test dans ta tête : « si résultat ≠ attendu → erreur ». Le framework n'est qu'un confort par-dessus ce if/throw. Si tu comprends le mécanisme, tu seras à l'aise avec n'importe quel outil.
You already test — you just don't know it
You write a double function. You call it in the console: double(5). You glance at the result to see if it looks right. You try double(0), check again. Seems fine. You move on.
What you just did is a test. A manual, throwaway, unreplayable test. The next day, you tweak the function to handle a new case. You have to eyeball everything again: double(5), double(0), double(-3)… The same ceremony with every change. Exhausting, and above all unreliable: you forget a case, you trust your memory, you miss the bug.
The visual-check trap: looking at a result in the console is a human check. It depends on your focus at that moment and disappears the instant you close the tab. The next time someone changes that function — you in two weeks, or the AI — nobody knows to re-check. An automated test replays the check every single time, without tiring.
The function does return n + 2. What does double(5) return? And double(0)? Which of the two tests will go red? Write both values before expanding.
Show the answer
double(5) returns 7 (5 + 2 = 7, expected 10 → red). double(0) returns 2 (0 + 2 = 2, expected 0 → red too). Both tests fail: n + 2 never equals n * 2 except when n is 2. Neither 5 nor 0 is 2. In the lab below, you'll confirm this live, then fix the function with a single character.
A test is an if and a throw
Forget frameworks for a second. At its core, a test is this:
if (double(5) !== 10) {
throw new Error('double(5) should be 10, got ' + double(5));
}
Three steps: run the code (double(5)), compare to the expected result (!== 10), and throw an error if they don't match. That's it. No magic.
If you want to write several checks, you can build a tiny expect yourself:
function expect(actual) {
return {
toBe(expected) {
if (actual !== expected) {
throw new Error('expected ' + expected + ', got ' + actual);
}
}
};
}
// Usage:
expect(double(5)).toBe(10); // throws if double(5) !== 10
Info: test() and expect() from a framework like Vitest or Jest are exactly these few lines, made more presentable. They add a test name, coloured output, and the ability to continue after a failure — but the core mechanism is identical: compare and throw if they differ.
Your turn: fix the function
In this lab, test() and expect() are already provided — you just need to edit the function code. Run the tests: they'll go red. Read the error message, fix the function, rerun until green.
Stuck on the fix? Show it
Replace n + 2 with n * 2. The line becomes return n * 2;. Rerun: both tests go green. The function is called double — it should multiply by two, not add two. One character changed everything: the + should have been a *.
Read the error message before fixing. It tells you exactly what the function returned (7) and what it should have returned (10). That precision is what makes a test more valuable than a quick console glance.
So why use a framework?
If an if/throw is enough, why does everyone talk about Vitest and Jest? The honest answer: same principle, but the framework makes life more comfortable.
What your homemade if/throw doesn't do easily:
- Group tests and give them a readable name — you know what failed without decoding the error message.
- Display red/green cleanly, with a summary at the end of the test suite.
- Continue after a failure: a bare
throwstops everything at the first failure; a framework runs all tests and lists everything that's wrong.
Golden rule: before opening a framework's docs, always frame the test mentally: "if result ≠ expected → throw". The framework is just a comfort layer on top of that if/throw. Understand the mechanism, and you'll be at ease with any tool.
🎯 Pratique
S'entraîner (clique pour ouvrir) :
💬 Ré-explique sans regarder
Avec tes mots : décris les 3 choses que fait n'importe quel test. (Pense à ce que fait if (x !== attendu) throw new Error(…).)
test() et expect() ne sont que l'emballage de ce if/throw.🧠 Rappel libre
Sans remonter : écris (en pseudo-code) le test le plus simple possible pour vérifier que somme(2, 3) vaut 5.
if (somme(2, 3) !== 5) throw new Error('attendu 5, reçu ' + somme(2, 3));. Un test, c'est ça ; le reste (framework, nom, sortie colorée) n'est que confort.⚖️ Juge le code de l'IA
Tu demandes un test à l'IA. Elle répond : « C'est testé ! test('double marche', () => { console.log(double(5)); }). Ça passe au vert, c'est bon ! » Tu acceptes, ou tu rejettes ?
expect, aucune assertion : le test affiche juste une valeur dans la console et ne lève jamais d'erreur. Il passera toujours au vert, même si double renvoie n'importe quoi. Un test sans assertion n'est pas un test : c'est un console.log déguisé en test.expect(x).toBe(y) à l'intérieur ?You can write a test. But how do you make it readable by anyone, even six months from now? Lesson 3 introduces Arrange-Act-Assert: three lines that cleanly structure any test.
Lesson 3: Arrange-Act-Assert →