Skip to content

Commit d4189cd

Browse files
authored
Merge pull request #1461 from CodeYourFuture/sprint-2-error-handling
Make Sprint 2 exercises throw on bad input, matching the Sprint 1 prep
2 parents 4a13588 + 53942c6 commit d4189cd

4 files changed

Lines changed: 65 additions & 22 deletions

File tree

‎Sprint-2/implement/contains.test.js‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ as the object contains a key of 'a'
99
1010
E.g. contains({a: 1, b: 2}, 'c') // returns false
1111
as the object doesn't contains a key of 'c'
12+
13+
E.g. contains([1, 2, 3], 'a') throws Error("contains requires an object")
14+
as an array isn't an object
1215
*/
1316

1417
// Acceptance criteria:
@@ -30,6 +33,8 @@ test.todo("contains on empty object returns false");
3033
// When passed to contains with a non-existent property name
3134
// Then it should return false
3235

33-
// Given invalid parameters like an array
36+
// Given a value that isn't an object - an array, a string, a number,
37+
// null, or no argument at all
3438
// When passed to contains
35-
// Then it should return false or throw an error
39+
// Then it should throw Error("contains requires an object")
40+
// (careful: typeof [] and typeof null are both "object")

‎Sprint-2/implement/tally.test.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,6 @@ test.todo("tally on an empty array returns an empty object");
2929
// When passed to tally
3030
// Then it should return counts for each unique item
3131

32-
// Given an invalid input like a string
32+
// Given an invalid input like a string, a number, or no argument at all
3333
// When passed to tally
34-
// Then it should throw an error
34+
// Then it should throw Error("tally requires an array")

‎Sprint-2/stretch/mode.js‎

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
1-
// You are given an implementation of calculateMode
1+
// You are given a working implementation of calculateMode.
2+
// Run the tests in mode.test.js before you start: they all pass.
23

3-
// calculateMode's implementation can be broken down into two stages:
4+
// calculateMode's implementation can be broken down into three stages:
45

5-
// Stage 1. One part of the code tracks the frequency of each value
6-
// Stage 2. The other part finds the value with the highest frequency
6+
// Stage 1. Check the input is a non-empty array of numbers, and throw if not
7+
// Stage 2. Track the frequency of each value
8+
// Stage 3. Find the value with the highest frequency
79

8-
// refactor calculateMode by splitting up the code
9-
// into smaller functions using the stages above
10+
// Refactor calculateMode by moving each stage into its own function,
11+
// then calling those functions from calculateMode.
12+
13+
// The tests must still pass after your refactor. Run them again to check.
1014

1115
function calculateMode(list) {
16+
// check the input is a non-empty array of numbers
17+
if (!Array.isArray(list)) {
18+
throw new Error("calculateMode requires an array of numbers");
19+
}
20+
if (list.length === 0) {
21+
throw new Error("calculateMode requires a non-empty array");
22+
}
23+
for (const item of list) {
24+
if (typeof item !== "number") {
25+
throw new Error("calculateMode requires an array of numbers");
26+
}
27+
}
28+
1229
// track frequency of each value
1330
let freqs = new Map();
1431

1532
for (let num of list) {
16-
if (typeof num !== "number") {
17-
continue;
18-
}
19-
2033
freqs.set(num, (freqs.get(num) || 0) + 1);
2134
}
2235

@@ -30,7 +43,7 @@ function calculateMode(list) {
3043
}
3144
}
3245

33-
return maxFreq === 0 ? NaN : mode;
46+
return mode;
3447
}
3548

3649
module.exports = calculateMode;

‎Sprint-2/stretch/mode.test.js‎

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// Don't change this file. The tests check your refactored calculateMode still behaves the same.
2+
13
const calculateMode = require("./mode.js");
24

35
// Acceptance criteria for calculateMode function
@@ -6,10 +8,15 @@ const calculateMode = require("./mode.js");
68
// When calculateMode is called on the array
79
// Then it should return the number that appears most frequently in the array
810

9-
// Example:
10-
// Given [2,4,1,2,3,2,1]
11-
// When calculateMode is called on [2,4,1,2,3,2,1]
12-
// Then it should return 2 */
11+
// E.g. calculateMode([2, 4, 1, 2, 3, 2, 1]) returns 2
12+
13+
// Given an empty array
14+
// When calculateMode is called on the array
15+
// Then it should throw Error("calculateMode requires a non-empty array")
16+
17+
// Given something that isn't an array of numbers, e.g. "banana" or [1, "2", 3]
18+
// When calculateMode is called on it
19+
// Then it should throw Error("calculateMode requires an array of numbers")
1320

1421
describe("calculateMode()", () => {
1522
test("returns the most frequent number in an array", () => {
@@ -24,9 +31,27 @@ describe("calculateMode()", () => {
2431
expect(calculateMode(nums)).toEqual(2);
2532
});
2633

27-
test("ignores non-number values", () => {
28-
const nums = [1, 3, "2", 2, 3, null];
34+
test("throws when the array contains a non-number", () => {
35+
expect(() => calculateMode([1, 3, "2", 2, 3, null])).toThrow(
36+
new Error("calculateMode requires an array of numbers")
37+
);
38+
});
39+
40+
test("throws when given something that isn't an array", () => {
41+
expect(() => calculateMode("banana")).toThrow(
42+
new Error("calculateMode requires an array of numbers")
43+
);
44+
});
45+
46+
test("throws when given no argument", () => {
47+
expect(() => calculateMode()).toThrow(
48+
new Error("calculateMode requires an array of numbers")
49+
);
50+
});
2951

30-
expect(calculateMode(nums)).toEqual(3);
52+
test("throws when given an empty array", () => {
53+
expect(() => calculateMode([])).toThrow(
54+
new Error("calculateMode requires a non-empty array")
55+
);
3156
});
3257
});

0 commit comments

Comments
 (0)