Skip to content

Commit 08645c7

Browse files
authored
Merge branch 'main' into alarmclock
2 parents f157825 + d4189cd commit 08645c7

13 files changed

Lines changed: 290 additions & 67 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: 101 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,44 +7,112 @@
77
const calculateMedian = require("./median.js");
88

99
describe("calculateMedian", () => {
10-
[
11-
{ input: [1, 2, 3], expected: 2 },
12-
{ input: [1, 2, 3, 4, 5], expected: 3 },
13-
{ input: [1, 2, 3, 4], expected: 2.5 },
14-
{ input: [1, 2, 3, 4, 5, 6], expected: 3.5 },
15-
].forEach(({ input, expected }) =>
16-
it(`returns the median for [${input}]`, () => expect(calculateMedian(input)).toEqual(expected))
17-
);
18-
19-
[
20-
{ input: [3, 1, 2], expected: 2 },
21-
{ input: [5, 1, 3, 4, 2], expected: 3 },
22-
{ input: [4, 2, 1, 3], expected: 2.5 },
23-
{ input: [6, 1, 5, 3, 2, 4], expected: 3.5 },
24-
{ input: [110, 20, 0], expected: 20 },
25-
{ input: [6, -2, 2, 12, 14], expected: 6 },
26-
].forEach(({ input, expected }) =>
27-
it(`returns the correct median for unsorted array [${input}]`, () => expect(calculateMedian(input)).toEqual(expected))
28-
);
10+
it("returns the median for [1, 2, 3]", () => {
11+
expect(calculateMedian([1, 2, 3])).toEqual(2);
12+
});
13+
14+
it("returns the median for [1, 2, 3, 4, 5]", () => {
15+
expect(calculateMedian([1, 2, 3, 4, 5])).toEqual(3);
16+
});
17+
18+
it("returns the median for [1, 2, 3, 4]", () => {
19+
expect(calculateMedian([1, 2, 3, 4])).toEqual(2.5);
20+
});
21+
22+
it("returns the median for [1, 2, 3, 4, 5, 6]", () => {
23+
expect(calculateMedian([1, 2, 3, 4, 5, 6])).toEqual(3.5);
24+
});
25+
26+
it("returns the correct median for unsorted array [3, 1, 2]", () => {
27+
expect(calculateMedian([3, 1, 2])).toEqual(2);
28+
});
29+
30+
it("returns the correct median for unsorted array [5, 1, 3, 4, 2]", () => {
31+
expect(calculateMedian([5, 1, 3, 4, 2])).toEqual(3);
32+
});
33+
34+
it("returns the correct median for unsorted array [4, 2, 1, 3]", () => {
35+
expect(calculateMedian([4, 2, 1, 3])).toEqual(2.5);
36+
});
37+
38+
it("returns the correct median for unsorted array [6, 1, 5, 3, 2, 4]", () => {
39+
expect(calculateMedian([6, 1, 5, 3, 2, 4])).toEqual(3.5);
40+
});
41+
42+
it("returns the correct median for unsorted array [110, 20, 0]", () => {
43+
expect(calculateMedian([110, 20, 0])).toEqual(20);
44+
});
45+
46+
it("returns the correct median for unsorted array [6, -2, 2, 12, 14]", () => {
47+
expect(calculateMedian([6, -2, 2, 12, 14])).toEqual(6);
48+
});
2949

3050
it("doesn't modify the input array [3, 1, 2]", () => {
3151
const list = [3, 1, 2];
3252
calculateMedian(list);
3353
expect(list).toEqual([3, 1, 2]);
3454
});
3555

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))
38-
);
39-
40-
[
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))
49-
);
56+
// There is no median of an empty array, so calculateMedian should throw
57+
it("throws when given an empty array", () => {
58+
expect(() => calculateMedian([])).toThrow(
59+
new Error("calculateMedian requires a non-empty array")
60+
);
61+
});
62+
63+
// Input that isn't an array should throw
64+
it("throws when given a string", () => {
65+
expect(() => calculateMedian("banana")).toThrow(
66+
new Error("calculateMedian requires an array of numbers")
67+
);
68+
});
69+
70+
it("throws when given a number", () => {
71+
expect(() => calculateMedian(123)).toThrow(
72+
new Error("calculateMedian requires an array of numbers")
73+
);
74+
});
75+
76+
it("throws when given null", () => {
77+
expect(() => calculateMedian(null)).toThrow(
78+
new Error("calculateMedian requires an array of numbers")
79+
);
80+
});
81+
82+
it("throws when given an object", () => {
83+
expect(() => calculateMedian({})).toThrow(
84+
new Error("calculateMedian requires an array of numbers")
85+
);
86+
});
87+
88+
it("throws when called with no argument", () => {
89+
expect(() => calculateMedian()).toThrow(
90+
new Error("calculateMedian requires an array of numbers")
91+
);
92+
});
93+
94+
// Arrays containing any non-number value should throw, rather than filtering them out
95+
it("throws for an array of strings", () => {
96+
expect(() => calculateMedian(["ten", "twenty", "thirty"])).toThrow(
97+
new Error("calculateMedian requires an array of numbers")
98+
);
99+
});
100+
101+
it("throws for an array mixing numbers and strings", () => {
102+
expect(() => calculateMedian([1, "2", 3, "4", 5])).toThrow(
103+
new Error("calculateMedian requires an array of numbers")
104+
);
105+
});
106+
107+
it("throws for an array containing null", () => {
108+
expect(() => calculateMedian([1, 2, null, 4])).toThrow(
109+
new Error("calculateMedian requires an array of numbers")
110+
);
111+
});
112+
113+
it("throws for an array containing undefined", () => {
114+
expect(() => calculateMedian([3, 1, undefined, 2])).toThrow(
115+
new Error("calculateMedian requires an array of numbers")
116+
);
117+
});
50118
});
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: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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"

‎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, 6]), target output: 3
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, 6], returns 3");
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

‎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")

0 commit comments

Comments
 (0)