Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions Sprint-1/fix/median.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,23 @@
// or contains values that aren't numbers (the function is expected to throw - see the tests).

function calculateMedian(list) {
if (!Array.isArray(list)) {
throw new Error("calculateMedian requires an array of numbers");
}
if (list.length === 0) {
throw new Error("calculateMedian requires a non-empty 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);
const median = list.splice(middleIndex, 1)[0];
return median;
const sorted = [...list].sort((a, b) => a - b);
if (sorted.length % 2 === 0) {
return (sorted[middleIndex - 1] + sorted[middleIndex]) / 2;
}
return sorted[middleIndex];
}

module.exports = calculateMedian;
12 changes: 11 additions & 1 deletion Sprint-1/implement/dedupe.js
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
function dedupe() {}
function dedupe(list) {
const result = [];
for (const item of list) {
if (!result.includes(item)) {
result.push(item);
}
}
return result;
}

module.exports = dedupe;
45 changes: 34 additions & 11 deletions Sprint-1/implement/dedupe.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,40 @@ E.g. dedupe([1, 2, 1]) returns [1, 2]
*/

// Acceptance Criteria:
describe("dedupe", () => {
// Given an empty array
// When passed to the dedupe function
// Then it should return an empty array
it("returns [] for []", () => {
expect(dedupe([])).toEqual([]);
});

// Given an empty array
// When passed to the dedupe function
// Then it should return an empty array
test.todo("given an empty array, it returns an empty array");
// Given an array with no duplicates
// When passed to the dedupe function
// Then it should return a copy of the original array
it("returns a copy of the array when there are no duplicates", () => {
// const list = [1, 2, 3];
// const result = dedupe(list);
// expect(result).toEqual([1, 2, 3]);
// expect(result).not.toBe(list);
expect(dedupe([1, "1", 2])).toEqual([1, "1", 2]);
});
Comment on lines +23 to +32

@cjyuan cjyuan Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your function implementation is correct. However, this test could be improved to better ensure
that any future changes continue to align with the expected behavior described on line 25:

Then it should return a copy of the original array

This test should fail if the function returns the original array (instead of a copy of the original array).

The current test checks only if both the original array and the returned array contain identical elements.
In order to validate the returned array is a different array, we need an additional check.

Could you find out what this additional check is?


Also, any unused code should be deleted instead of kept in comment.

// Given an array of strings or numbers
// When passed to the dedupe function
// Then it should return a new array with duplicates removed while preserving the
// first occurrence of each element from the original array.
it("removes duplicate numbers, keeping the first occurrence order", () => {
expect(dedupe([5, 1, 1, 2, 3, 2, 5, 8])).toEqual([5, 1, 2, 3, 8]);
expect(dedupe([1, 2, 1])).toEqual([1, 2]);
});

// Given an array with no duplicates
// When passed to the dedupe function
// Then it should return a copy of the original array
it("treats 1 and '1' as different values", () => {
expect(dedupe([1, "1", 1, "1"])).toEqual([1, "1"]);
});

// Given an array of strings or numbers
// When passed to the dedupe function
// Then it should return a new array with duplicates removed while preserving the
// first occurrence of each element from the original array.
it("doesn't modify the input array", () => {
const list = [1, 1, 2];
dedupe(list);
expect(list).toEqual([1, 1, 2]);
});
});
9 changes: 8 additions & 1 deletion Sprint-1/implement/describe-median.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ function calculateMedian(list) {
}

// Implement this function. See describe-median.test.js for the acceptance criteria.
function describeMedian(list) {}
function describeMedian(list) {
try {
const median = calculateMedian(list);
return `The median is ${median}`;
} catch (error) {
return `Could not calculate a median: ${error.message}`;
}
}

module.exports = describeMedian;
65 changes: 54 additions & 11 deletions Sprint-1/implement/describe-median.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,60 @@ message, so the caller can see what went wrong.
const describeMedian = require("./describe-median.js");

// Acceptance criteria:
describe("describeMedian", () => {
// Given an array of numbers
// When passed to describeMedian
// Then it should return "The median is " followed by the median
// Delete this test.todo and replace it with a test.
it('returns "The median is 2" for [1, 2, 3]', () => {
expect(describeMedian([1, 2, 3])).toEqual("The median is 2");
});

// Given an array of numbers
// When passed to describeMedian
// Then it should return "The median is " followed by the median
// Delete this test.todo and replace it with a test.
test.todo('given [1, 2, 3], returns "The median is 2"');
it("works for an even-length array", () => {
expect(describeMedian([1, 2, 3, 4])).toEqual("The median is 2.5");
});

// Given an empty array
// When passed to describeMedian
// Then it should return "Could not calculate a median: calculateMedian requires a non-empty array"
it("works for an unsorted array", () => {
expect(describeMedian([3, 1, 2])).toEqual("The median is 2");
});

// Given something that isn't an array of numbers, e.g. "banana"
// When passed to describeMedian
// Then it should return "Could not calculate a median: calculateMedian requires an array of numbers"
// Given an empty array
// When passed to describeMedian
// Then it should return "Could not calculate a median: calculateMedian requires a non-empty array"
it("explains the problem for an empty array", () => {
expect(describeMedian([])).toEqual(
"Could not calculate a median: calculateMedian requires a non-empty array"
);
});

// Given something that isn't an array of numbers, e.g. "banana"
// When passed to describeMedian
// Then it should return "Could not calculate a median: calculateMedian requires an array of numbers"
it("explains the problem for an empty array", () => {
expect(describeMedian([])).toEqual(
"Could not calculate a median: calculateMedian requires a non-empty array"
);
});

// Given something that isn't an array of numbers, explain why
it.each([["banana"], [42], [null], [{}]])(
"explains the problem when given %p instead of an array",
(input) => {
expect(describeMedian(input)).toEqual(
"Could not calculate a median: calculateMedian requires an array of numbers"
);
}
);

it("explains the problem when called with no argument", () => {
expect(describeMedian()).toEqual(
"Could not calculate a median: calculateMedian requires an array of numbers"
);
});

it("explains the problem for an array containing a non-number", () => {
expect(describeMedian([1, "2", 3])).toEqual(
"Could not calculate a median: calculateMedian requires an array of numbers"
);
});
});
11 changes: 11 additions & 0 deletions Sprint-1/implement/max.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
function findMax(elements) {
if (!Array.isArray(elements)) {
throw new Error("findMax requires an array of numbers");
}
if (!elements.every((v) => typeof v === "number" && !Number.isNaN(v))) {
throw new Error("findMax requires an array of numbers");
}
let max = -Infinity;
for (const value of elements) {
if (value > max) max = value;
}
return max;
}

module.exports = findMax;
82 changes: 57 additions & 25 deletions Sprint-1/implement/max.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,65 @@ We have set things up already so that this file can see your function from the o
*/

const findMax = require("./max.js");
describe("findMax", () => {
// Given an empty array
// When passed to the max function
// Then it should return -Infinity
// Delete this test.todo and replace it with a test.
it("returns -Infinity for []", () => {
expect(findMax([])).toEqual(-Infinity);
});

// Given an empty array
// When passed to the max function
// Then it should return -Infinity
// Delete this test.todo and replace it with a test.
test.todo("given an empty array, returns -Infinity");
// Given an array with one number
// When passed to the max function
// Then it should return that number
it("returns the only number for [1]", () => {
expect(findMax([1])).toEqual(1);
});

// Given an array with one number
// When passed to the max function
// Then it should return that number
// Given an array with both positive and negative numbers
// When passed to the max function
// Then it should return the largest number overall
it("returns the largest of positive and negative numbers", () => {
expect(findMax([5, -7, 3, -5])).toEqual(5);
});

// Given an array with both positive and negative numbers
// When passed to the max function
// Then it should return the largest number overall
// Given an array with just negative numbers
// When passed to the max function
// Then it should return the closest one to zero
it("returns the negative number closest to zero", () => {
expect(findMax([-10, -3, -20, -5])).toEqual(-3);
});

// Given an array with just negative numbers
// When passed to the max function
// Then it should return the closest one to zero
// Given an array with decimal numbers
// When passed to the max function
// Then it should return the largest decimal number
it("returns the largest decimal number", () => {
expect(findMax([1.5, 2.25, 2.2, -0.5])).toEqual(2.25);
});
// Given an array containing a value that isn't a number
// When passed to the max function
// Then it should throw Error("findMax requires an array of numbers")
it("throws when the array contains a non-number", () => {
expect(() => findMax(["hey", 10, "hi", 60, 10])).toThrow(
new Error("findMax requires an array of numbers")
);
});
// Given something that isn't an array at all, such as "hey", 42 or no argument
// When passed to the max function
// Then it should throw Error("findMax requires an array of numbers")
it.each([["hey"], [42], [null], [{}]])(
"throws when given %p instead of an array",
(input) => {
expect(() => findMax(input)).toThrow(
new Error("findMax requires an array of numbers")
);
}
);

// Given an array with decimal numbers
// When passed to the max function
// Then it should return the largest decimal number

// Given an array containing a value that isn't a number
// When passed to the max function
// Then it should throw Error("findMax requires an array of numbers")

// Given something that isn't an array at all, such as "hey", 42 or no argument
// When passed to the max function
// Then it should throw Error("findMax requires an array of numbers")
it("throws when called with no argument", () => {
expect(() => findMax()).toThrow(
new Error("findMax requires an array of numbers")
);
});
});
20 changes: 19 additions & 1 deletion Sprint-1/implement/mean.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
function calculateMean(list) {}
function calculateMean(list) {
if (!Array.isArray(list)) {
throw new Error("calculateMean requires an array of numbers");
}

if (list.length === 0) {
throw new Error("calculateMean requires a non-empty array");
}

if (!list.every((v) => typeof v === "number" && !Number.isNaN(v))) {
throw new Error("calculateMean requires an array of numbers");
}

let total = 0;
for (const value of list) {
total += value;
}
return total / list.length;
}

module.exports = calculateMean;
Loading
Loading