From 70093be7285c3036c01f3c6ed54cefcd14ba8b4a Mon Sep 17 00:00:00 2001 From: Abdi Saeed Date: Wed, 22 Jul 2026 08:28:44 +0100 Subject: [PATCH 1/8] Add error handling fundamentals to Data Groups Sprint 1 Trainees currently learn fetch, promises, and async/await without being taught how to throw or catch an error. Adds three js2 blocks (throwing errors, try/catch, throw vs return) built around the existing calculateMedian exercise, and wires them into Sprint 1 prep. Refs #1946 --- .../en/module/js2/throw-or-return/index.md | 63 ++++++++++++++ .../en/module/js2/throwing-errors/index.md | 84 +++++++++++++++++++ .../en/module/js2/try-catch/index.md | 65 ++++++++++++++ .../itp/data-groups/sprints/1/prep/index.md | 9 ++ 4 files changed, 221 insertions(+) create mode 100644 common-content/en/module/js2/throw-or-return/index.md create mode 100644 common-content/en/module/js2/throwing-errors/index.md create mode 100644 common-content/en/module/js2/try-catch/index.md diff --git a/common-content/en/module/js2/throw-or-return/index.md b/common-content/en/module/js2/throw-or-return/index.md new file mode 100644 index 000000000..0a44ee613 --- /dev/null +++ b/common-content/en/module/js2/throw-or-return/index.md @@ -0,0 +1,63 @@ ++++ +title = 'Throw or return?' + +time = 10 +[objectives] + 1='Decide whether a function should throw an error or return a value' + 2='Identify where in a program an error should be handled' +[build] + render = 'never' + list = 'local' + publishResources = false + ++++ + +We now have two ways for a function to respond when it meets a problem: return a value, or throw an error. How do we choose? + +### Expected situations: use a return value + +If a situation is a normal part of using the function, handle it with ordinary code. Searching an array for a value that isn't there is not an error; that's why [`indexOf`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) returns `-1` rather than throwing. The caller expects both outcomes and can check with an `if`. + +### Broken expectations: throw + +If the function _cannot do what its name promises_, throw. `calculateMedian("apple")` can't calculate any median; returning a made-up value would hide a bug in the caller's code. Throwing makes the problem loud and points at where it was detected. + +A useful question to ask: **is this situation something the caller should have prevented?** Passing a string to `calculateMedian` is a bug in the calling code, so throw. A user typing their name into a date field is not a bug, it's expected human behaviour, so handle it with normal conditional logic. + +### Where should errors be caught? + +_Throwing_ tells us the function can't do its job. _Catching_ is about something different: who can do something useful with that information? + +Only catch an error where you can do something useful with it: skip one bad record and continue, use a default value instead, or show the user a helpful message. If the code you're in can't do any of those things, don't catch the error there. Let it travel up to a caller who can. If nobody can do anything useful with the error, it's better for the program to crash with a clear error trace, because that shows exactly what needs to be fixed. + +### 🧰 Decide for yourself + +For each scenario, decide what the code should do before you check the answer. Some of these are judgement calls, so what matters most is your reasoning: is this situation expected or a broken expectation, and who can do something useful about it? + +{{}} + +{{}} + +{{}} + +{{}} diff --git a/common-content/en/module/js2/throwing-errors/index.md b/common-content/en/module/js2/throwing-errors/index.md new file mode 100644 index 000000000..72442e946 --- /dev/null +++ b/common-content/en/module/js2/throwing-errors/index.md @@ -0,0 +1,84 @@ ++++ +title = 'Throwing errors' + +time = 15 +[objectives] + 1='Explain what happens when an error is thrown' + 2='Throw an error when a function cannot do its job' +[build] + render = 'never' + list = 'local' + publishResources = false + ++++ + +By now, `calculateMedian` should handle lists of both odd and even length. Here's one way to do that, which we'll build on for the rest of this page: + +```js +function calculateMedian(list) { + const middleIndex = Math.floor(list.length / 2); + if (list.length % 2 === 0) { + // Even length: average the two middle values + return (list[middleIndex - 1] + list[middleIndex]) / 2; + } + // Odd length: there's a single middle value + return list[middleIndex]; +} +``` + +But what should it do with input like this? + +```js +calculateMedian([]); +calculateMedian("banana"); +calculateMedian("apple"); +``` + +There is no median of an empty list. And a string isn't a list of numbers at all. But our implementation doesn't know that. It will happily return `NaN` for the empty array, `NaN` again for `"banana"`, and a plausible-looking `"p"` for `"apple"`. The results aren't just wrong, they're unpredictable: the same kind of bad input produces a different kind of bad output depending on exactly what you pass in. + +This is a problem. The {{}}The caller of a function is the code that calls it, not a person. If `main` calls `calculateMedian(list)`, then `main` is the caller.{{}} of `calculateMedian` gets back a value that _looks_ like an answer, and carries on using it. The program doesn't fail here, where the mistake happened. It fails later, somewhere else, when that nonsense value gets used. Bugs like this are hard to track down because the error trace points far away from the real cause. + +When a function cannot do its job, it shouldn't guess. It should fail immediately and loudly, at the point where the problem is. We call this {{}}Failing fast means stopping as soon as we know something is wrong, instead of carrying on with bad data and failing later somewhere confusing.{{}}. + +### Using `throw` + +In Structuring Data, you [interpreted error traces](/itp/structuring-data/sprints/2/prep/#interpreting-this-error) when JavaScript threw a `SyntaxError` at you. Now we can {{}}Throwing an error stops normal execution immediately. The error travels up through the calling functions until something handles it. If nothing handles it, the program crashes and prints the error trace.{{}} errors from our own code, using the `throw` keyword: + +```js +function calculateMedian(list) { + if (Array.isArray(list) === false) { + throw new Error("calculateMedian requires an array of numbers"); + } + if (list.length === 0) { + throw new Error("calculateMedian requires a non-empty array"); + } + const middleIndex = Math.floor(list.length / 2); + if (list.length % 2 === 0) { + return (list[middleIndex - 1] + list[middleIndex]) / 2; + } + return list[middleIndex]; +} +``` + +[`Array.isArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) checks whether a value is an array. If the input isn't an array, or is an empty one, we `throw` a new [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) with a message explaining what went wrong. + +Save this in a file and try calling `calculateMedian([])`. The program stops and prints an error trace, just like the ones you interpreted before, except this time the message is one we wrote ourselves: + +```console +Error: calculateMedian requires a non-empty array + at calculateMedian (/Users/cyf/prep/median.js:6:11) +``` + +Now the error points at the exact place the problem was detected, with a message saying what the problem is. That's much more useful to whoever calls our function than a mysterious `NaN`. + +### Testing that a function throws + +We can assert that a function throws using the [`toThrow`](https://jestjs.io/docs/expect#tothrowerror) matcher: + +```js +test("throws an error when given an empty list", () => { + expect(() => calculateMedian([])).toThrow(); +}); +``` + +Note that we wrap the call in a function. If we called `calculateMedian([])` directly, the error would be thrown before `expect` could check anything. diff --git a/common-content/en/module/js2/try-catch/index.md b/common-content/en/module/js2/try-catch/index.md new file mode 100644 index 000000000..33b4ad952 --- /dev/null +++ b/common-content/en/module/js2/try-catch/index.md @@ -0,0 +1,65 @@ ++++ +title = 'try/catch' + +time = 15 +[objectives] + 1='Use a try/catch block to handle a thrown error' + 2='Explain why errors should not be silently ignored' +[build] + render = 'never' + list = 'local' + publishResources = false + ++++ + +`calculateMedian` now throws when it can't do its job. By default, a thrown error crashes the program. Sometimes that's exactly right. But sometimes we know what to do when something goes wrong, and we'd rather do that than crash. + +Suppose we're producing a report of median salaries for several teams, and one team's data is bad: + +```js +const salaryDatasets = [ + [42000, 51000, 60000], + [], + [38000, 45000], +]; +``` + +If we call `calculateMedian` on each dataset in a loop, the empty array will throw, and the whole report will crash. The bad data for one team stops us reporting on all the others. + +### Catching errors + +We can {{}}Catching an error stops it travelling any further up through the calling functions. Execution continues from the catch block, and the program does not crash.{{}} a thrown error with a `try...catch` block: + +```js +for (const salaries of salaryDatasets) { + try { + const median = calculateMedian(salaries); + console.log(`The median salary is ${median}`); + } catch (error) { + console.error(`Skipping a dataset: ${error.message}`); + } +} +``` + +JavaScript _tries_ to run the code inside the `try` block. If any of it throws, execution jumps immediately to the `catch` block; the remaining statements in the `try` block do not run. The thrown error is passed in as `error`, and we can read the message we wrote with `error.message`. + +Run this and you'll see the report is produced for the first and third datasets, with a warning about the empty one in between. One bad dataset no longer stops the whole program: + +```console +The median salary is 51000 +Skipping a dataset: calculateMedian requires a non-empty array +The median salary is 41500 +``` + +### Don't hide errors + +A `catch` block must _do_ something with the error: log it, use a fallback, or tell the user. Look at this version: + +```js +try { + const median = calculateMedian(salaries); + console.log(`The median salary is ${median}`); +} catch (error) {} +``` + +This is worse than not catching at all. The error is silently thrown away, so bad data no longer crashes the program _and_ nobody finds out about it. This is called {{}}Catching an error and doing nothing with it. The problem still happened, but now there is no crash and no message, so nobody knows.{{}}, and it turns loud, easy-to-find bugs back into quiet, hard-to-find ones. If you can't do anything useful with an error, don't catch it. diff --git a/org-cyf/content/itp/data-groups/sprints/1/prep/index.md b/org-cyf/content/itp/data-groups/sprints/1/prep/index.md index d84294877..cbd1bc4c6 100644 --- a/org-cyf/content/itp/data-groups/sprints/1/prep/index.md +++ b/org-cyf/content/itp/data-groups/sprints/1/prep/index.md @@ -43,6 +43,15 @@ src="module/js2/side-effects" name="Implementing all the cases" src="module/js2/more-median-cases" [[blocks]] +name="Throwing errors" +src="module/js2/throwing-errors" +[[blocks]] +name="try/catch" +src="module/js2/try-catch" +[[blocks]] +name="Throw or return?" +src="module/js2/throw-or-return" +[[blocks]] name="Solving problems with arrays 📼" src="module/js2/arrays-workshop" [[blocks]] From 961a67b21f2d3c70ac6170178c69a0ff5e0727da Mon Sep 17 00:00:00 2001 From: Abdi Saeed Date: Fri, 24 Jul 2026 09:34:46 +0100 Subject: [PATCH 2/8] Revert Array.isArray guard to use ! rather than === false --- common-content/en/module/js2/throwing-errors/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-content/en/module/js2/throwing-errors/index.md b/common-content/en/module/js2/throwing-errors/index.md index 72442e946..075677273 100644 --- a/common-content/en/module/js2/throwing-errors/index.md +++ b/common-content/en/module/js2/throwing-errors/index.md @@ -46,7 +46,7 @@ In Structuring Data, you [interpreted error traces](/itp/structuring-data/sprint ```js function calculateMedian(list) { - if (Array.isArray(list) === false) { + if (!Array.isArray(list)) { throw new Error("calculateMedian requires an array of numbers"); } if (list.length === 0) { From a4c086c3e372adbdb0a4b27ebe9ff1af05aad3bd Mon Sep 17 00:00:00 2001 From: Abdi Saeed Date: Fri, 24 Jul 2026 09:51:26 +0100 Subject: [PATCH 3/8] Reword throw intro sentence per review feedback --- common-content/en/module/js2/throwing-errors/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-content/en/module/js2/throwing-errors/index.md b/common-content/en/module/js2/throwing-errors/index.md index 075677273..8efcb57ce 100644 --- a/common-content/en/module/js2/throwing-errors/index.md +++ b/common-content/en/module/js2/throwing-errors/index.md @@ -42,7 +42,7 @@ When a function cannot do its job, it shouldn't guess. It should fail immediatel ### Using `throw` -In Structuring Data, you [interpreted error traces](/itp/structuring-data/sprints/2/prep/#interpreting-this-error) when JavaScript threw a `SyntaxError` at you. Now we can {{}}Throwing an error stops normal execution immediately. The error travels up through the calling functions until something handles it. If nothing handles it, the program crashes and prints the error trace.{{}} errors from our own code, using the `throw` keyword: +In Structuring Data, you [interpreted error traces](/itp/structuring-data/sprints/2/prep/#interpreting-this-error) when JavaScript threw a `SyntaxError` at you. We can also {{}}Throwing an error stops normal execution immediately. The error travels up through the calling functions until something handles it. If nothing handles it, the program crashes and prints the error trace.{{}} errors from our own code, using the `throw` keyword: ```js function calculateMedian(list) { From edca4644fddf1ecf5ffacc873ae1a98ba3c443a3 Mon Sep 17 00:00:00 2001 From: Abdi Saeed Date: Fri, 24 Jul 2026 10:00:08 +0100 Subject: [PATCH 4/8] Remove fragile link to Structuring Data prep block --- common-content/en/module/js2/throwing-errors/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-content/en/module/js2/throwing-errors/index.md b/common-content/en/module/js2/throwing-errors/index.md index 8efcb57ce..b0321e59f 100644 --- a/common-content/en/module/js2/throwing-errors/index.md +++ b/common-content/en/module/js2/throwing-errors/index.md @@ -42,7 +42,7 @@ When a function cannot do its job, it shouldn't guess. It should fail immediatel ### Using `throw` -In Structuring Data, you [interpreted error traces](/itp/structuring-data/sprints/2/prep/#interpreting-this-error) when JavaScript threw a `SyntaxError` at you. We can also {{}}Throwing an error stops normal execution immediately. The error travels up through the calling functions until something handles it. If nothing handles it, the program crashes and prints the error trace.{{}} errors from our own code, using the `throw` keyword: +In Structuring Data, you interpreted error traces when JavaScript threw a `SyntaxError` at you. We can also {{}}Throwing an error stops normal execution immediately. The error travels up through the calling functions until something handles it. If nothing handles it, the program crashes and prints the error trace.{{}} errors from our own code, using the `throw` keyword: ```js function calculateMedian(list) { From 6c74b24b4ff2d5ae8ac120ebc1a65f4eb55ac899 Mon Sep 17 00:00:00 2001 From: Abdi Saeed Date: Fri, 24 Jul 2026 14:43:16 +0100 Subject: [PATCH 5/8] Validate array elements are numbers in calculateMedian Matches review feedback: the guarded implementation checked the input was a non-empty array, but not that its elements were numbers, so calculateMedian(["a", "b"]) would still silently return nonsense. --- .../en/module/js2/throwing-errors/index.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/common-content/en/module/js2/throwing-errors/index.md b/common-content/en/module/js2/throwing-errors/index.md index b0321e59f..87aa977d8 100644 --- a/common-content/en/module/js2/throwing-errors/index.md +++ b/common-content/en/module/js2/throwing-errors/index.md @@ -32,9 +32,10 @@ But what should it do with input like this? calculateMedian([]); calculateMedian("banana"); calculateMedian("apple"); +calculateMedian(["ten", "twenty", "thirty"]); ``` -There is no median of an empty list. And a string isn't a list of numbers at all. But our implementation doesn't know that. It will happily return `NaN` for the empty array, `NaN` again for `"banana"`, and a plausible-looking `"p"` for `"apple"`. The results aren't just wrong, they're unpredictable: the same kind of bad input produces a different kind of bad output depending on exactly what you pass in. +There is no median of an empty list. A string isn't a list of numbers at all. And a list of strings isn't a list of numbers either, even though it _is_ a list. But our implementation doesn't know any of that. It will happily return `NaN` for the empty array, `NaN` again for `"banana"`, a plausible-looking `"p"` for `"apple"`, and `"twenty"` for the list of strings, a value that looks entirely plausible, so nobody would even think to question it. The results aren't just wrong, they're unpredictable: the same kind of bad input produces a different kind of bad output depending on exactly what you pass in. This is a problem. The {{}}The caller of a function is the code that calls it, not a person. If `main` calls `calculateMedian(list)`, then `main` is the caller.{{}} of `calculateMedian` gets back a value that _looks_ like an answer, and carries on using it. The program doesn't fail here, where the mistake happened. It fails later, somewhere else, when that nonsense value gets used. Bugs like this are hard to track down because the error trace points far away from the real cause. @@ -46,12 +47,20 @@ In Structuring Data, you interpreted error traces when JavaScript threw a `Synta ```js function calculateMedian(list) { + // Checking for a non-array if (!Array.isArray(list)) { throw new Error("calculateMedian requires an array of numbers"); } + // Checking for an empty array if (list.length === 0) { throw new Error("calculateMedian requires a non-empty array"); } + // Checking for non-number items in the array + for (const item of list) { + if (typeof item !== "number") { + throw new Error("calculateMedian requires an array of numbers"); + } + } const middleIndex = Math.floor(list.length / 2); if (list.length % 2 === 0) { return (list[middleIndex - 1] + list[middleIndex]) / 2; @@ -60,13 +69,13 @@ function calculateMedian(list) { } ``` -[`Array.isArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) checks whether a value is an array. If the input isn't an array, or is an empty one, we `throw` a new [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) with a message explaining what went wrong. +[`Array.isArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) checks whether a value is an array. We also check every element is a number, using `typeof`. If the input isn't an array, is empty, or contains anything that isn't a number, we `throw` a new [`Error`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error) with a message explaining what went wrong. Save this in a file and try calling `calculateMedian([])`. The program stops and prints an error trace, just like the ones you interpreted before, except this time the message is one we wrote ourselves: ```console Error: calculateMedian requires a non-empty array - at calculateMedian (/Users/cyf/prep/median.js:6:11) + at calculateMedian (/Users/cyf/prep/median.js:8:11) ``` Now the error points at the exact place the problem was detected, with a message saying what the problem is. That's much more useful to whoever calls our function than a mysterious `NaN`. @@ -79,6 +88,10 @@ We can assert that a function throws using the [`toThrow`](https://jestjs.io/doc test("throws an error when given an empty list", () => { expect(() => calculateMedian([])).toThrow(); }); + +test("throws an error when given an array with a non-number", () => { + expect(() => calculateMedian(["ten", "twenty", "thirty"])).toThrow("array of numbers"); +}); ``` Note that we wrap the call in a function. If we called `calculateMedian([])` directly, the error would be thrown before `expect` could check anything. From 3685980dd17a1919583a33c0bed80e748434ee0a Mon Sep 17 00:00:00 2001 From: Abdi Saeed Date: Fri, 24 Jul 2026 14:47:56 +0100 Subject: [PATCH 6/8] Add example and test for calling calculateMedian with no argument Calling with no argument does crash on its own (list is undefined), but with a generic engine error that doesn't mention calculateMedian or say a list was expected. The existing non-array guard already catches this case, so add an example and test showing that. --- .../en/module/js2/throwing-errors/index.md | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/common-content/en/module/js2/throwing-errors/index.md b/common-content/en/module/js2/throwing-errors/index.md index 87aa977d8..c6f340692 100644 --- a/common-content/en/module/js2/throwing-errors/index.md +++ b/common-content/en/module/js2/throwing-errors/index.md @@ -41,13 +41,27 @@ This is a problem. The {{}}The caller of a function is t When a function cannot do its job, it shouldn't guess. It should fail immediately and loudly, at the point where the problem is. We call this {{}}Failing fast means stopping as soon as we know something is wrong, instead of carrying on with bad data and failing later somewhere confusing.{{}}. +What about calling it with no argument at all? + +```js +calculateMedian(); +``` + +This time our implementation does crash, straight away: + +```console +TypeError: Cannot read properties of undefined (reading 'length') +``` + +Here, at least, we get an error message. But it comes from the JavaScript engine, not from us, and it doesn't explain what's wrong: it doesn't mention `calculateMedian`, or say that a list was expected. Whoever hits this has to read our code to work out what actually went wrong. If we check for a missing argument ourselves, we can throw a message that says exactly that, straight away. + ### Using `throw` In Structuring Data, you interpreted error traces when JavaScript threw a `SyntaxError` at you. We can also {{}}Throwing an error stops normal execution immediately. The error travels up through the calling functions until something handles it. If nothing handles it, the program crashes and prints the error trace.{{}} errors from our own code, using the `throw` keyword: ```js function calculateMedian(list) { - // Checking for a non-array + // Checking for a non-array (including no argument at all) if (!Array.isArray(list)) { throw new Error("calculateMedian requires an array of numbers"); } @@ -92,6 +106,10 @@ test("throws an error when given an empty list", () => { test("throws an error when given an array with a non-number", () => { expect(() => calculateMedian(["ten", "twenty", "thirty"])).toThrow("array of numbers"); }); + +test("throws an error when given no argument", () => { + expect(() => calculateMedian()).toThrow("array of numbers"); +}); ``` Note that we wrap the call in a function. If we called `calculateMedian([])` directly, the error would be thrown before `expect` could check anything. From 78404ccb25c5a05adc5a42d139457838ee726b18 Mon Sep 17 00:00:00 2001 From: Abdi Saeed Date: Fri, 24 Jul 2026 14:56:08 +0100 Subject: [PATCH 7/8] Switch throw tests to exact-message matching, bump time estimate toThrow(string) only checks the message contains a substring, not that it equals it. toThrow(new Error(...)) is Jest's documented way to assert the exact message, more precise given we now write the messages ourselves. Also add the missing non-array test case, and bump time to 20 minutes to reflect the added content. --- .../en/module/js2/throwing-errors/index.md | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/common-content/en/module/js2/throwing-errors/index.md b/common-content/en/module/js2/throwing-errors/index.md index c6f340692..10747286b 100644 --- a/common-content/en/module/js2/throwing-errors/index.md +++ b/common-content/en/module/js2/throwing-errors/index.md @@ -1,7 +1,7 @@ +++ title = 'Throwing errors' -time = 15 +time = 20 [objectives] 1='Explain what happens when an error is thrown' 2='Throw an error when a function cannot do its job' @@ -100,15 +100,27 @@ We can assert that a function throws using the [`toThrow`](https://jestjs.io/doc ```js test("throws an error when given an empty list", () => { - expect(() => calculateMedian([])).toThrow(); + expect(() => calculateMedian([])).toThrow( + new Error("calculateMedian requires a non-empty array") + ); +}); + +test("throws an error when given something that isn't an array", () => { + expect(() => calculateMedian("banana")).toThrow( + new Error("calculateMedian requires an array of numbers") + ); }); test("throws an error when given an array with a non-number", () => { - expect(() => calculateMedian(["ten", "twenty", "thirty"])).toThrow("array of numbers"); + expect(() => calculateMedian(["ten", "twenty", "thirty"])).toThrow( + new Error("calculateMedian requires an array of numbers") + ); }); test("throws an error when given no argument", () => { - expect(() => calculateMedian()).toThrow("array of numbers"); + expect(() => calculateMedian()).toThrow( + new Error("calculateMedian requires an array of numbers") + ); }); ``` From 4d3ca3310b9575dc8aa9874436056538b1c12238 Mon Sep 17 00:00:00 2001 From: Abdi Saeed Date: Fri, 24 Jul 2026 15:14:32 +0100 Subject: [PATCH 8/8] Explain why we wrap the toThrow call in a function --- common-content/en/module/js2/throwing-errors/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common-content/en/module/js2/throwing-errors/index.md b/common-content/en/module/js2/throwing-errors/index.md index 10747286b..0d774e884 100644 --- a/common-content/en/module/js2/throwing-errors/index.md +++ b/common-content/en/module/js2/throwing-errors/index.md @@ -124,4 +124,4 @@ test("throws an error when given no argument", () => { }); ``` -Note that we wrap the call in a function. If we called `calculateMedian([])` directly, the error would be thrown before `expect` could check anything. +Note that we wrap the call in a function. When we call a function with arguments, those arguments get evaluated before the function is called. If we called `expect(calculateMedian([])).toThrow()` directly, the error would be thrown before `expect` was called, and so before `expect` could check anything.