Skip to content

Commit d49e0c2

Browse files
Sprint 1: sync exercises with error-handling prep
Add mean and describe-median katas to implement, and change the existing fix/implement exercises to throw on bad input instead of ignoring it, matching the updated Sprint 1 prep.
1 parent de6889c commit d49e0c2

9 files changed

Lines changed: 159 additions & 22 deletions

File tree

‎Sprint-1/fix/median.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// Start by running the tests for this function
33
// If you're in the Sprint-1 directory, you can run `npm test -- fix` to run the tests in the fix directory
44

5-
// Hint: Please consider scenarios when 'list' doesn't have numbers (the function is expected to return null)
6-
// or 'list' has mixed values (the function is expected to sort only numbers).
5+
// Hint: Please consider scenarios when 'list' isn't an array, is empty,
6+
// or contains values that aren't numbers (the function is expected to throw - see the tests).
77

88
function calculateMedian(list) {
99
const middleIndex = Math.floor(list.length / 2);

‎Sprint-1/fix/median.test.js‎

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,39 @@ describe("calculateMedian", () => {
3333
expect(list).toEqual([3, 1, 2]);
3434
});
3535

36-
[ 'not an array', 123, null, undefined, {}, [], ["apple", null, undefined] ].forEach(val =>
37-
it(`returns null for non-numeric array (${val})`, () => expect(calculateMedian(val)).toBe(null))
36+
// There is no median of an empty array, so calculateMedian should throw
37+
it("throws when given an empty array", () => {
38+
expect(() => calculateMedian([])).toThrow(
39+
new Error("calculateMedian requires a non-empty array")
40+
);
41+
});
42+
43+
// Non-array input should throw (no argument at all counts, as 'list' is then undefined)
44+
[ 'banana', 123, null, undefined, {}, ["apple", null, undefined], ["ten", "twenty"] ].forEach(val =>
45+
it(`throws for non-numeric input (${val})`, () =>
46+
expect(() => calculateMedian(val)).toThrow(
47+
new Error("calculateMedian requires an array of numbers")
48+
))
3849
);
3950

51+
it("throws when called with no argument", () => {
52+
expect(() => calculateMedian()).toThrow(
53+
new Error("calculateMedian requires an array of numbers")
54+
);
55+
});
56+
57+
// Arrays containing any non-number value should throw, rather than filtering them out
4058
[
41-
{ input: [1, 2, "3", null, undefined, 4], expected: 2 },
42-
{ input: ["apple", 1, 2, 3, "banana", 4], expected: 2.5 },
43-
{ input: [1, "2", 3, "4", 5], expected: 3 },
44-
{ input: [1, "apple", 2, null, 3, undefined, 4], expected: 2.5 },
45-
{ input: [3, "apple", 1, null, 2, undefined, 4], expected: 2.5 },
46-
{ input: ["banana", 5, 3, "apple", 1, 4, 2], expected: 3 },
47-
].forEach(({ input, expected }) =>
48-
it(`filters out non-numeric values and calculates the median for [${input}]`, () => expect(calculateMedian(input)).toEqual(expected))
59+
[1, 2, "3", null, undefined, 4],
60+
["apple", 1, 2, 3, "banana", 4],
61+
[1, "2", 3, "4", 5],
62+
[1, "apple", 2, null, 3, undefined, 4],
63+
[3, "apple", 1, null, 2, undefined, 4],
64+
["banana", 5, 3, "apple", 1, 4, 2],
65+
].forEach((input) =>
66+
it(`throws for an array containing a non-number [${input}]`, () =>
67+
expect(() => calculateMedian(input)).toThrow(
68+
new Error("calculateMedian requires an array of numbers")
69+
))
4970
);
5071
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Don't change this function.
2+
function calculateMedian(list) {
3+
if (!Array.isArray(list)) {
4+
throw new Error("calculateMedian requires an array of numbers");
5+
}
6+
if (list.length === 0) {
7+
throw new Error("calculateMedian requires a non-empty array");
8+
}
9+
for (const item of list) {
10+
if (typeof item !== "number") {
11+
throw new Error("calculateMedian requires an array of numbers");
12+
}
13+
}
14+
const middleIndex = Math.floor(list.length / 2);
15+
const sorted = [...list].sort((a, b) => a - b);
16+
if (sorted.length % 2 === 0) {
17+
return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2;
18+
}
19+
return sorted[middleIndex];
20+
}
21+
22+
// Implement this function. See describe-median.test.js for the acceptance criteria.
23+
function describeMedian(list) {}
24+
25+
module.exports = describeMedian;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* Describe the median, or explain why there isn't one
2+
3+
calculateMedian is given to you at the top of describe-median.js. It throws
4+
when it can't calculate a median. Don't change it.
5+
6+
Implement describeMedian, which calls calculateMedian and returns a sentence
7+
instead of crashing.
8+
9+
E.g. describeMedian([1, 2, 3]), target output: "The median is 2"
10+
E.g. describeMedian([]), target output: "Could not calculate a median: calculateMedian requires a non-empty array"
11+
12+
You'll need a try/catch block for this. The catch block must use the error's
13+
message, so the caller can see what went wrong.
14+
*/
15+
16+
const describeMedian = require("./describe-median.js");
17+
18+
// Acceptance criteria:
19+
20+
// Given an array of numbers
21+
// When passed to describeMedian
22+
// Then it should return "The median is " followed by the median
23+
// Delete this test.todo and replace it with a test.
24+
test.todo('given [1, 2, 3], returns "The median is 2"');
25+
26+
// Given an empty array
27+
// When passed to describeMedian
28+
// Then it should return "Could not calculate a median: calculateMedian requires a non-empty array"
29+
30+
// Given something that isn't an array of numbers, e.g. "banana"
31+
// When passed to describeMedian
32+
// Then it should return "Could not calculate a median: calculateMedian requires an array of numbers"
33+
34+
// Given an empty array
35+
// When passed to describeMedian
36+
// Then it should not throw

‎Sprint-1/implement/max.test.js‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
In this kata, you will need to implement a function that find the largest numerical element of an array.
44
55
E.g. max([30, 50, 10, 40]), target output: 50
6-
E.g. max(['hey', 10, 'hi', 60, 10]), target output: 60 (sum ignores any non-numerical elements)
6+
E.g. max(['hey', 10, 'hi', 60, 10]) throws Error("findMax requires an array of numbers") (max can't compare non-numerical elements, so it shouldn't guess)
77
88
You should implement this function in max.js, and add tests for it in this file.
99
@@ -34,10 +34,10 @@ test.todo("given an empty array, returns -Infinity");
3434
// When passed to the max function
3535
// Then it should return the largest decimal number
3636

37-
// Given an array with non-number values
37+
// Given an array containing a value that isn't a number
3838
// When passed to the max function
39-
// Then it should return the max and ignore non-numeric values
39+
// Then it should throw Error("findMax requires an array of numbers")
4040

41-
// Given an array with only non-number values
41+
// Given something that isn't an array at all, such as "hey", 42 or no argument
4242
// When passed to the max function
43-
// Then it should return the least surprising value given how it behaves for all other inputs
43+
// Then it should throw Error("findMax requires an array of numbers")

‎Sprint-1/implement/mean.js‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function calculateMean(list) {}
2+
3+
module.exports = calculateMean;

‎Sprint-1/implement/mean.test.js‎

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/* Calculate the mean of an array of numbers
2+
3+
In this kata, you will need to implement a function that calculates the mean of an array of numbers.
4+
5+
E.g. calculateMean([1, 2, 3]), target output: 2
6+
E.g. calculateMean([]) throws Error("calculateMean requires a non-empty array")
7+
E.g. calculateMean("banana") throws Error("calculateMean requires an array of numbers")
8+
9+
There is no mean of an empty array, and a string isn't an array of numbers, so
10+
calculateMean should throw rather than return a value. This is the same problem
11+
calculateMedian solves in the prep and in the fix directory.
12+
13+
You should implement this function in mean.js, and add tests for it in this file.
14+
15+
We have set things up already so that this file can see your function from the other file.
16+
*/
17+
18+
const calculateMean = require("./mean.js");
19+
20+
// Acceptance criteria:
21+
22+
// Given an array of numbers
23+
// When passed to calculateMean
24+
// Then it should return their mean
25+
// Delete this test.todo and replace it with a test.
26+
test.todo("given [1, 2, 3], returns 2");
27+
28+
// Given an array with a single number
29+
// When passed to calculateMean
30+
// Then it should return that number
31+
32+
// Given an array containing negative or decimal numbers
33+
// When passed to calculateMean
34+
// Then it should return the correct mean
35+
36+
// Given an empty array
37+
// When passed to calculateMean
38+
// Then it should throw Error("calculateMean requires a non-empty array")
39+
40+
// Given a value that isn't an array, e.g. "banana", 42, null or {}
41+
// When passed to calculateMean
42+
// Then it should throw Error("calculateMean requires an array of numbers")
43+
44+
// Given no argument at all
45+
// When passed to calculateMean
46+
// Then it should throw Error("calculateMean requires an array of numbers")
47+
48+
// Given an array containing a non-number value, e.g. [1, "2", 3]
49+
// When passed to calculateMean
50+
// Then it should throw Error("calculateMean requires an array of numbers")

‎Sprint-1/implement/sum.test.js‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
In this kata, you will need to implement a function that sums the numerical elements of an array
44
55
E.g. sum([10, 20, 30]), target output: 60
6-
E.g. sum(['hey', 10, 'hi', 60, 10]), target output: 80 (ignore any non-numerical elements)
6+
E.g. sum(['hey', 10, 'hi', 60, 10]) throws Error("sum requires an array of numbers") (sum can't add non-numerical elements, so it shouldn't guess)
77
*/
88

99
const sum = require("./sum.js");
@@ -27,10 +27,10 @@ test.todo("given an empty array, returns 0")
2727
// When passed to the sum function
2828
// Then it should return the correct total sum
2929

30-
// Given an array containing non-number values
30+
// Given an array containing a value that isn't a number
3131
// When passed to the sum function
32-
// Then it should ignore the non-numerical values and return the sum of the numerical elements
32+
// Then it should throw Error("sum requires an array of numbers")
3333

34-
// Given an array with only non-number values
34+
// Given something that isn't an array at all, such as "hey", 42 or no argument
3535
// When passed to the sum function
36-
// Then it should return the least surprising value given how it behaves for all other inputs
36+
// Then it should throw Error("sum requires an array of numbers")

‎Sprint-1/readme.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Here is a recommended order:
3131
1. `max.test.js`
3232
2. `sum.test.js`
3333
3. `dedupe.test.js`
34+
4. `mean.test.js`
35+
5. `describe-median.test.js`
3436

3537
Again, you can run just the test for the `implement` directory if you're in the `Sprint-1` directory by running `npm test -- implement`.
3638

0 commit comments

Comments
 (0)