From b27b10f2f70012a43708d9ea7bb60f3adcbec491 Mon Sep 17 00:00:00 2001 From: Tobias Date: Thu, 23 Jul 2026 22:25:44 +0100 Subject: [PATCH 01/48] predicted and explaint what will happen --- Sprint-2/debug/address.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..710da7f25 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -1,4 +1,4 @@ -// Predict and explain first... +// Predict and explain first.../* there will be output of undefined as we are trying to access a property that is not yet defined // This code should log out the houseNumber from the address object // but it isn't working... From f017ce15b39a689910f5b71e0f8d29a5091d6495 Mon Sep 17 00:00:00 2001 From: Tobias Date: Thu, 23 Jul 2026 22:27:21 +0100 Subject: [PATCH 02/48] fix the bracket notation to access the key property of the onject and log out the value --- Sprint-2/debug/address.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 710da7f25..5b254bfc7 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -12,4 +12,4 @@ const address = { postcode: "XYZ 123", }; -console.log(`My house number is ${address[0]}`); +console.log(`My house number is ${address["houseNumber"]}`); From e5e37a2772df3a34e3e333f8deb240e569ead446 Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 11:32:36 +0100 Subject: [PATCH 03/48] made a prediction with my reason on what will happen when the programm is run --- Sprint-2/debug/author.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..17d4d7dea 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -1,4 +1,5 @@ // Predict and explain first... +// My prediction is that there will be a TypeError as for ..of loop that is meant for array like object is being used on an object literals to access it's properties // This program attempts to log out all the property values in the object. // But it isn't working. Explain why first and then fix the problem From ae5347bdb082a1bac1eab5f61e7469cc844c2e8e Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 11:36:14 +0100 Subject: [PATCH 04/48] I used for ..in and bracket notation to access the properties value from the object --- Sprint-2/debug/author.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 17d4d7dea..115358174 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -1,5 +1,5 @@ // Predict and explain first... -// My prediction is that there will be a TypeError as for ..of loop that is meant for array like object is being used on an object literals to access it's properties +// My prediction is that there will be a TypeError as for ..of loop that is meant for array like object is being used on an object literals to access it's properties // This program attempts to log out all the property values in the object. // But it isn't working. Explain why first and then fix the problem @@ -12,6 +12,6 @@ const author = { alive: true, }; -for (const value of author) { - console.log(value); -} +for (const value in author) { + console.log(author[value]); +} \ No newline at end of file From d8493efd6ffa9d4c493fd772d852f30a827ac898 Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 12:23:02 +0100 Subject: [PATCH 05/48] made my prediction as to what will happen when the program runs and the explanations --- Sprint-2/debug/recipe.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..852f77f6a 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -1,4 +1,5 @@ // Predict and explain first... +/* my prediction is that this program will print the title and how many it services but not the ingrientes as there is no dot notation in the recipe expression so the properties are never accessed */ // This program should log out the title, how many it serves and the ingredients. // Each ingredient should be logged on a new line From 01748e7e0bc78f321da75bcb7963b38dfe5f3d0d Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 12:25:38 +0100 Subject: [PATCH 06/48] used for .. of to iterate over the aray elemnts in the ingredient and print the value --- Sprint-2/debug/recipe.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 852f77f6a..f989dc708 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -11,6 +11,10 @@ const recipe = { ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; -console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); +console.log(`${recipe.title} serves ${recipe.serves}`); + console.log("ingredients:"); + // use for of to print the value of the ingredients array element +for (const ingredients of recipe.ingredients){ +console.log(ingredients); +}; + From 2e7ce33e2db94b23bcb65ce7ea63ee6f87e93a9d Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 14:33:08 +0100 Subject: [PATCH 07/48] Wrote a test to check for property name in given object and return true otherwise return false --- Sprint-2/implement/contains.test.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..7688ae340 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -16,7 +16,14 @@ as the object doesn't contains a key of 'c' // Given a contains function // When passed an object and a property name // Then it should return true if the object contains the property, false otherwise - +//Case 1 +test(" Case 1: returns true when the property exists", () => { + expect(contains({ a: 1, b: 2 }, "a")).toBe(true); +}); + +test("Case 2: returns false when the property does not exist", () => { + expect(contains({ a: 1, b: 2 }, "c")).toBe(false); +}); // Given an empty object // When passed to contains // Then it should return false From 0ace00d6e50acb082fa4dcbc0e47e12035693249 Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 14:35:04 +0100 Subject: [PATCH 08/48] implements a function to pass the test --- Sprint-2/implement/contains.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..94b1264be 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,10 @@ -function contains() {} + +function contains(obj, target) { + for (const key in obj) { + if (key === target) return true; + } + return false; + } + module.exports = contains; From bd7b8a34ce81ba74a0970a368984af9109e0fbd5 Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 14:38:31 +0100 Subject: [PATCH 09/48] Wrote a test to check for name property from an empty array and return false --- Sprint-2/implement/contains.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 7688ae340..d44dfb75d 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -27,7 +27,8 @@ test("Case 2: returns false when the property does not exist", () => { // Given an empty object // When passed to contains // Then it should return false -test.todo("contains on empty object returns false"); +test("contains on empty object returns false", () => { + expect(contains({ }, "c")).toBe(false);}); // Given an object with properties // When passed to contains with an existing property name From 7995caca58f917b7025c86eaf080b6a260547a3a Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 14:46:09 +0100 Subject: [PATCH 10/48] Re-write the General acceptance criteria to a separate test for when there is existence property name and when there is not --- Sprint-2/implement/contains.test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index d44dfb75d..ec9638f5c 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -33,11 +33,16 @@ test("contains on empty object returns false", () => { // Given an object with properties // When passed to contains with an existing property name // Then it should return true +test(" Case 1: returns true when the property exists", () => { + expect(contains({ a: 1, b: 2 }, "a")).toBe(true); +}); // Given an object with properties // When passed to contains with a non-existent property name // Then it should return false - +test("Case 2: returns false when the property does not exist", () => { + expect(contains({ a: 1, b: 2 }, "c")).toBe(false); +}); // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error From d0d5b6c123c0e0cd8195a5dfc190cbf8b8e8a5dc Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 14:54:25 +0100 Subject: [PATCH 11/48] Wrote a test to return false when invalid parameters like array are passed --- Sprint-2/implement/contains.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index ec9638f5c..4fffe03f4 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -46,3 +46,7 @@ test("Case 2: returns false when the property does not exist", () => { // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error + +test(" returns false when invalid parameters like arrays are passed ", () => { + expect(contains([1,"a","NaN","b","3"], "a")).toBe(false); +}); From 105c0e79e9755893204de4ebdcd7c018d0b6d5d9 Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 14:56:33 +0100 Subject: [PATCH 12/48] wrote a test check and return false when string is passed --- Sprint-2/implement/contains.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 4fffe03f4..bdcc880d3 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -50,3 +50,6 @@ test("Case 2: returns false when the property does not exist", () => { test(" returns false when invalid parameters like arrays are passed ", () => { expect(contains([1,"a","NaN","b","3"], "a")).toBe(false); }); +test(" returns false when invalid parameters like String is passed ", () => { + expect(contains("Toby", "Toby")).toBe(false); +}); From 931be7632db771da9dbf6b7c0b507971eb3d3d7a Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 14:58:46 +0100 Subject: [PATCH 13/48] Wrote a test to check and return false when invalid parameter like number is passed --- Sprint-2/implement/contains.test.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index bdcc880d3..ec12ac711 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -53,3 +53,7 @@ test(" returns false when invalid parameters like arrays are passed ", () => { test(" returns false when invalid parameters like String is passed ", () => { expect(contains("Toby", "Toby")).toBe(false); }); + +test(" returns false when invalid parameters like number is passed ", () => { + expect(contains(1, 1)).toBe(false); +}); From 96db9d36f3f52b79178262336b2fd555566693cb Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 16:51:45 +0100 Subject: [PATCH 14/48] commented out the test.todo --- Sprint-2/implement/lookup.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..d518057f6 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,6 @@ const createLookup = require("./lookup.js"); -test.todo("creates a country currency code lookup for multiple codes"); +//test.todo("creates a country currency code lookup for multiple codes"); /* From e07fc9273bb55163be68207648d55d58d3c0fe51 Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 16:57:58 +0100 Subject: [PATCH 15/48] wrote a test suite to check for multiple array , empty array and single array of country code and return the corresponding currency code --- Sprint-2/implement/lookup.test.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index d518057f6..954e510a7 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -33,3 +33,28 @@ It should return: 'CA': 'CAD' } */ +describe("createLookup", () => { + test("creates a country currency code lookup for multiple codes", () => { + const input = [ + ["US", "USD"], + ["CA", "CAD"], + ["GB", "GBP"], + ]; + + const result = createLookup(input); + + expect(result).toEqual({ + US: "USD", + CA: "CAD", + GB: "GBP", + }); + }); + + test("returns an empty object when given an empty array", () => { + expect(createLookup([])).toEqual({}); + }); + + test("handles a single pair correctly", () => { + expect(createLookup([["JP", "JPY"]])).toEqual({ JP: "JPY" }); + }); +}); \ No newline at end of file From c6fad45eb278dc64c130edf2bfee33025eb3286c Mon Sep 17 00:00:00 2001 From: Tobias Date: Fri, 24 Jul 2026 17:00:50 +0100 Subject: [PATCH 16/48] Implemented a function to pass the test of country and currency code --- Sprint-2/implement/lookup.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..f685e6b79 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,4 +1,11 @@ -function createLookup() { +function createLookup(pairs) { + const lookup = {}; + + for (let [country, currency] of pairs) { + lookup[country] = currency; + } + + return lookup; // implementation here } From 311f34a674d5432f5f7bd8dd071659bf6471dd14 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 13:40:54 +0100 Subject: [PATCH 17/48] refatored the consitional statement to check for empty string ,also filetr out spaces --- Sprint-2/implement/querystring.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..0d50331eb 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,9 +1,9 @@ function parseQueryString(queryString) { const queryParams = {}; - if (queryString.length === 0) { + if (!queryString) { return queryParams; } - const keyValuePairs = queryString.split("&"); + const keyValuePairs = queryString.split("&").filter(item=>item!==''); for (const pair of keyValuePairs) { const [key, value] = pair.split("="); From 502af08bdd146a508476a0aac2039affc7f5cfbc Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 13:46:59 +0100 Subject: [PATCH 18/48] repaced the occurence of plus sign with spaces --- Sprint-2/implement/querystring.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 0d50331eb..6a5fe8619 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -6,8 +6,7 @@ function parseQueryString(queryString) { const keyValuePairs = queryString.split("&").filter(item=>item!==''); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); - queryParams[key] = value; + pair = pair.replace(/\+/g,'') } return queryParams; From 1e8578b3e4fdff5eb5fac0656ffba27597d123e2 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 13:55:23 +0100 Subject: [PATCH 19/48] separated the key, value at the first occurance of "=" --- Sprint-2/implement/querystring.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 6a5fe8619..abf63b503 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -6,7 +6,9 @@ function parseQueryString(queryString) { const keyValuePairs = queryString.split("&").filter(item=>item!==''); for (const pair of keyValuePairs) { - pair = pair.replace(/\+/g,'') + pair = pair.replace(/\+/g,' '),// replace any occurrences of plus sign with spaces + + let } return queryParams; From 4ea0c563bb64b436c7650b508f41637fb9c9f20b Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 14:06:48 +0100 Subject: [PATCH 20/48] replace const with let to allow for reassigment in the for .. of loop , removed the comme and changed the correct variables --- Sprint-2/implement/querystring.js | 36 +++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index abf63b503..97772b86b 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,14 +1,36 @@ function parseQueryString(queryString) { const queryParams = {}; - if (!queryString) { - return queryParams; - } - const keyValuePairs = queryString.split("&").filter(item=>item!==''); + if (!queryString) return queryParams; + + const keyValuePairs = queryString.split("&").filter((item) => item !== ""); + + for (let pair of keyValuePairs) { + // Replace '+' with spaces + pair = pair.replace(/\+/g, " "); + + const eqIdx = pair.indexOf("="); + + let keyPair, valuePair; + + if (eqIdx === -1) { + keyPair = pair; + valuePair = ""; + } else { + keyPair = pair.slice(0, eqIdx); + valuePair = pair.slice(eqIdx + 1); + } - for (const pair of keyValuePairs) { - pair = pair.replace(/\+/g,' '),// replace any occurrences of plus sign with spaces + const key = decodeURIComponent(keyPair); + const value = decodeURIComponent(valuePair); - let + // Handle duplicates + if (!(key in queryParams)) { + queryParams[key] = value; + } else if (Array.isArray(queryParams[key])) { + queryParams[key].push(value); + } else { + queryParams[key] = [queryParams[key], value]; + } } return queryParams; From a404823d4cfcb26417401a3ac1f47177ae702aae Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 14:30:34 +0100 Subject: [PATCH 21/48] created an empty array --- Sprint-2/implement/tally.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..704b6238e 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,5 @@ -function tally() {} +function tally() { + frequency ={}; +} module.exports = tally; From a76b2fdfca009537ce388803b252ab84bd6dfd4f Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 14:44:50 +0100 Subject: [PATCH 22/48] declare the items vatiable and validate if it has anything at all --- Sprint-2/implement/tally.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index 704b6238e..aa570b2f5 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,5 +1,9 @@ -function tally() { +function tally(items) { + if(!item){ + return {}; // validate if there Item to count first + } frequency ={}; + } module.exports = tally; From 2ebe778dec5f19f4f6445af12ce2a5af032c3ce7 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 15:04:33 +0100 Subject: [PATCH 23/48] Validate the inpute data corectly with the correct name to ensure the date is only array --- Sprint-2/implement/tally.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index aa570b2f5..e5d36f847 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,9 +1,20 @@ function tally(items) { - if(!item){ - return {}; // validate if there Item to count first + if(!Array.isArray(items)){ + throw new Error("Input must me and array"); + // validate and throw error if input is not an array . } - frequency ={}; - + frequency = {}; + for (let item of items){ + if (item in frequency){ + frequency[item] +=1; + }else{ + frequency[item] = 1 + } + + } + + + return frequency; } module.exports = tally; From 30b4cdd519879be5988427838ead92668a99bead Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 15:05:20 +0100 Subject: [PATCH 24/48] declare the variable frequency an assign it empty object --- Sprint-2/implement/tally.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index e5d36f847..33923613d 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -3,7 +3,7 @@ function tally(items) { throw new Error("Input must me and array"); // validate and throw error if input is not an array . } - frequency = {}; + const frequency = {}; for (let item of items){ if (item in frequency){ frequency[item] +=1; From 8c60483c474222c7b44db58ea1964333e86b96bd Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 15:15:08 +0100 Subject: [PATCH 25/48] wrote the test suite for the test cases --- Sprint-2/implement/tally.test.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..ccadd95b2 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -32,3 +32,27 @@ test.todo("tally on an empty array returns an empty object"); // Given an invalid input like a string // When passed to tally // Then it should throw an error + +const tally = require("./tally.js"); + +describe("tally()", () => { + test("counts frequency of each unique item", () => { + const result = tally(["a", "a", "b", "c"]); + expect(result).toEqual({ a: 2, b: 1, c: 1 }); + }); + test("returns an empty object when given an empty array", () => { + expect(tally([])).toEqual({}); + }); + + test("counts a single item correctly", () => { + expect(tally(["x"])).toEqual({ x: 1 }); + }); + + test("throws an error when input is not an array", () => { + expect(() => tally("hello")).toThrow(Error); + expect(() => tally(123)).toThrow(Error); + expect(() => tally({})).toThrow(Error); + expect(() => tally(null)).toThrow(Error); + }); +}); + From 5683e3849975b0920fadf736c87f17496e422c8c Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 15:59:19 +0100 Subject: [PATCH 26/48] answered the first question a --- Sprint-2/interpret/invert.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..6e890b7a5 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -15,8 +15,9 @@ function invert(obj) { return invertedObj; } +console.log(invert({ a: 1 })); -// a) What is the current return value when invert is called with { a : 1 } +// a) What is the current return value when invert is called with { a : 1 }// the current return value is 1 // b) What is the current return value when invert is called with { a: 1, b: 2 } From 1760ba20fbe012db00362c96a26790f138f29a20 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:02:11 +0100 Subject: [PATCH 27/48] answered the questin for b --- Sprint-2/interpret/invert.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index 6e890b7a5..6aaa7a583 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -15,11 +15,11 @@ function invert(obj) { return invertedObj; } -console.log(invert({ a: 1 })); +console.log(invert({ a: 1, b: 2 })); // a) What is the current return value when invert is called with { a : 1 }// the current return value is 1 -// b) What is the current return value when invert is called with { a: 1, b: 2 } +// b) What is the current return value when invert is called with { a: 1, b: 2 }// the current returned value is {key:2} // c) What is the target return value when invert is called with {a : 1, b: 2} From 55dd8a593083f18e3d57b2e7596f6810250a4fd8 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:03:03 +0100 Subject: [PATCH 28/48] gave the correct response for the question a --- Sprint-2/interpret/invert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index 6aaa7a583..7e8101577 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -17,7 +17,7 @@ function invert(obj) { } console.log(invert({ a: 1, b: 2 })); -// a) What is the current return value when invert is called with { a : 1 }// the current return value is 1 +// a) What is the current return value when invert is called with { a : 1 }// the current return value is {key: 1} // b) What is the current return value when invert is called with { a: 1, b: 2 }// the current returned value is {key:2} From 0b3d681cb95019f4c1d5a26cc8e3df644c9ac7f4 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:08:23 +0100 Subject: [PATCH 29/48] answered question about what the target return should be --- Sprint-2/interpret/invert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index 7e8101577..1e8a719da 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -21,7 +21,7 @@ console.log(invert({ a: 1, b: 2 })); // b) What is the current return value when invert is called with { a: 1, b: 2 }// the current returned value is {key:2} -// c) What is the target return value when invert is called with {a : 1, b: 2} +// c) What is the target return value when invert is called with {a : 1, b: 2}// the target output is { '1': 'a', '2': 'b' } // c) What does Object.entries return? Why is it needed in this program? From 7757d5fde0989ae94951233c70c64c7e411df79a Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:12:16 +0100 Subject: [PATCH 30/48] Answered question on what Object.entries does --- Sprint-2/interpret/invert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index 1e8a719da..aa1af6295 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -23,7 +23,7 @@ console.log(invert({ a: 1, b: 2 })); // c) What is the target return value when invert is called with {a : 1, b: 2}// the target output is { '1': 'a', '2': 'b' } -// c) What does Object.entries return? Why is it needed in this program? +// c) What does Object.entries return? Why is it needed in this program?// Object.entries converts the object into an array of [key, value] pairs. // d) Explain why the current return value is different from the target output From 82dbb8ac35f5354f2bd883622536582a3d20cecd Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:17:53 +0100 Subject: [PATCH 31/48] Answered the question for d --- Sprint-2/interpret/invert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index aa1af6295..22fa5f852 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -25,6 +25,6 @@ console.log(invert({ a: 1, b: 2 })); // c) What does Object.entries return? Why is it needed in this program?// Object.entries converts the object into an array of [key, value] pairs. -// d) Explain why the current return value is different from the target output +// d) Explain why the current return value is different from the target output// Because after iterations the "invertedObj.key=value" is assigning same value to the new variable name "key" with the dot notation. // e) Fix the implementation of invert (and write tests to prove it's fixed!) From 2d3c86d81f0bca79d3acb32e3f41247616b40ba8 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:19:35 +0100 Subject: [PATCH 32/48] fixed the implementation to invert the returned value --- Sprint-2/interpret/invert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index 22fa5f852..0ba7def04 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -10,7 +10,7 @@ function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj[value] = key; } return invertedObj; From 4de7d6b4e54aa9c57c0af558100e82a811320e7b Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:36:53 +0100 Subject: [PATCH 33/48] implemented the function --- Sprint-2/interpret/invert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index 0ba7def04..32d69575d 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -15,7 +15,7 @@ function invert(obj) { return invertedObj; } -console.log(invert({ a: 1, b: 2 })); +console.assert(invert({ a: 1, b: 2 })); // a) What is the current return value when invert is called with { a : 1 }// the current return value is {key: 1} From e75e0c56bfcab194441ca5d06ef3b8983dc23438 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:39:21 +0100 Subject: [PATCH 34/48] created an empty file invert.test.js --- Sprint-2/interpret/invert.test.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Sprint-2/interpret/invert.test.js diff --git a/Sprint-2/interpret/invert.test.js b/Sprint-2/interpret/invert.test.js new file mode 100644 index 000000000..e69de29bb From 61b22056b4d08d0f149026f3f4e11f9fe74e34f7 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:40:28 +0100 Subject: [PATCH 35/48] deleted the console.assert and exported the function invert --- Sprint-2/interpret/invert.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index 32d69575d..c8d2c060b 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -15,7 +15,7 @@ function invert(obj) { return invertedObj; } -console.assert(invert({ a: 1, b: 2 })); +module.exports = invert; // a) What is the current return value when invert is called with { a : 1 }// the current return value is {key: 1} From d50ad7f6c13cb0d6e513b76e5d144453da616515 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:51:23 +0100 Subject: [PATCH 36/48] wrote a test to passed the implemetion --- Sprint-2/interpret/invert.test.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Sprint-2/interpret/invert.test.js b/Sprint-2/interpret/invert.test.js index e69de29bb..ab3d0103f 100644 --- a/Sprint-2/interpret/invert.test.js +++ b/Sprint-2/interpret/invert.test.js @@ -0,0 +1,9 @@ + + +const invert = require("./invert.js"); + + test("swaps keys and values for a simple object", () => { + const input = { x: 10, y: 20 }; + const output = invert(input); + expect(output).toEqual({ 10: "x", 20: "y" }); + }); \ No newline at end of file From f350f5ec482f84ccd7677934141a03100173d353 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 16:52:33 +0100 Subject: [PATCH 37/48] removed the second tally.js file import from the tall.test.js file --- Sprint-2/implement/tally.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index ccadd95b2..814db124d 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -33,7 +33,7 @@ test.todo("tally on an empty array returns an empty object"); // When passed to tally // Then it should throw an error -const tally = require("./tally.js"); + describe("tally()", () => { test("counts frequency of each unique item", () => { From 3985d779102244f87ec9e552ff90aadcb2781b54 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 19:30:26 +0100 Subject: [PATCH 38/48] Declare a function with a name countWords --- Sprint-2/stretch/count-words.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Sprint-2/stretch/count-words.js b/Sprint-2/stretch/count-words.js index 8e85d19d7..4c4e11c79 100644 --- a/Sprint-2/stretch/count-words.js +++ b/Sprint-2/stretch/count-words.js @@ -26,3 +26,9 @@ 3. Order the results to find out which word is the most common in the input */ + function countWords(){ + + } + + + \ No newline at end of file From b6d67329c9f97054d865d0662afef038b102e299 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 19:34:47 +0100 Subject: [PATCH 39/48] give the function declaration a parameter and validate that it's a string --- Sprint-2/stretch/count-words.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sprint-2/stretch/count-words.js b/Sprint-2/stretch/count-words.js index 4c4e11c79..340e05f03 100644 --- a/Sprint-2/stretch/count-words.js +++ b/Sprint-2/stretch/count-words.js @@ -26,7 +26,10 @@ 3. Order the results to find out which word is the most common in the input */ - function countWords(){ + function countWords(str){ + if(typeof str !=="string"){ + throw new Error("Input must be a string"); + } } From 9f5ff0b442ecb858193276e35954d7c7b19fde79 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 19:36:50 +0100 Subject: [PATCH 40/48] use regex to replace any puncuations with empty string --- Sprint-2/stretch/count-words.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Sprint-2/stretch/count-words.js b/Sprint-2/stretch/count-words.js index 340e05f03..a5f2c3335 100644 --- a/Sprint-2/stretch/count-words.js +++ b/Sprint-2/stretch/count-words.js @@ -30,6 +30,7 @@ if(typeof str !=="string"){ throw new Error("Input must be a string"); } + const cleanedStr = str.replace(/[.,!?;:]/g, "").toLowerCase(); } From bc5e9489bbd03dd75331e462f97b6c85ccbf0b52 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 19:44:09 +0100 Subject: [PATCH 41/48] split the cleanedStr and filler words that passed the condition --- Sprint-2/stretch/count-words.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sprint-2/stretch/count-words.js b/Sprint-2/stretch/count-words.js index a5f2c3335..3c8131c6e 100644 --- a/Sprint-2/stretch/count-words.js +++ b/Sprint-2/stretch/count-words.js @@ -31,7 +31,12 @@ throw new Error("Input must be a string"); } const cleanedStr = str.replace(/[.,!?;:]/g, "").toLowerCase(); + const freq = {}; + const words = cleanedStr.split(" ").filter((w) => w !== ""); + for (const word of words) { + freq[word] = (freq[word] || 0) + 1; + } } From 5940b729606b6f7fa1e3677cf5fbca721fdcbb4b Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 19:46:23 +0100 Subject: [PATCH 42/48] ordered the words by sorting them --- Sprint-2/stretch/count-words.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sprint-2/stretch/count-words.js b/Sprint-2/stretch/count-words.js index 3c8131c6e..bcd992b36 100644 --- a/Sprint-2/stretch/count-words.js +++ b/Sprint-2/stretch/count-words.js @@ -37,6 +37,9 @@ for (const word of words) { freq[word] = (freq[word] || 0) + 1; } + const sorted = Object.entries(freq).sort((a, b) => b[1] - a[1]); + + return sorted; } From e4257fcf9254e7d553e0008904d0bf390e625dc4 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 22:24:56 +0100 Subject: [PATCH 43/48] Refactored the code to have two stages ! to track frequency of each value and the second to find the value with the highest frequency --- Sprint-2/stretch/mode.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Sprint-2/stretch/mode.js b/Sprint-2/stretch/mode.js index 3f7609d79..01a50483a 100644 --- a/Sprint-2/stretch/mode.js +++ b/Sprint-2/stretch/mode.js @@ -8,22 +8,24 @@ // refactor calculateMode by splitting up the code // into smaller functions using the stages above -function calculateMode(list) { - // track frequency of each value - let freqs = new Map(); +function buildFrequencyMap(list) { + const freqs = new Map(); - for (let num of list) { + for (const num of list) { if (typeof num !== "number") { - continue; + continue; // ignore non-numbers } - freqs.set(num, (freqs.get(num) || 0) + 1); } - // Find the value with the highest frequency + return freqs; +} + +function findModeFromFreqs(freqs) { let maxFreq = 0; let mode; - for (let [num, freq] of freqs) { + + for (const [num, freq] of freqs) { if (freq > maxFreq) { mode = num; maxFreq = freq; @@ -33,4 +35,10 @@ function calculateMode(list) { return maxFreq === 0 ? NaN : mode; } +function calculateMode(list) { + const freqs = buildFrequencyMap(list); // Stage 1 + const mode = findModeFromFreqs(freqs); // Stage 2 + return mode; +} + module.exports = calculateMode; From 1dcd83a3e5788335670c5a4f2f3487484916b00d Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 22:48:18 +0100 Subject: [PATCH 44/48] Answered the quest a --- Sprint-2/stretch/till.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/stretch/till.js b/Sprint-2/stretch/till.js index 6a08532e7..6017a45ac 100644 --- a/Sprint-2/stretch/till.js +++ b/Sprint-2/stretch/till.js @@ -22,7 +22,7 @@ const till = { }; const totalAmount = totalTill(till); -// a) What is the target output when totalTill is called with the till object +// a) What is the target output when totalTill is called with the till object/* the target output is (1p*10 + 5p*6 +50p*4 +20p*10) =440/100 = £4.40 // b) Why do we need to use Object.entries inside the for...of loop in this function? From 73823dcfac4e90fce4a02240d3f8143b7cdb59c9 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 22:52:48 +0100 Subject: [PATCH 45/48] Answere question b --- Sprint-2/stretch/till.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sprint-2/stretch/till.js b/Sprint-2/stretch/till.js index 6017a45ac..534dde2b3 100644 --- a/Sprint-2/stretch/till.js +++ b/Sprint-2/stretch/till.js @@ -22,9 +22,9 @@ const till = { }; const totalAmount = totalTill(till); -// a) What is the target output when totalTill is called with the till object/* the target output is (1p*10 + 5p*6 +50p*4 +20p*10) =440/100 = £4.40 +// a) What is the target output when totalTill is called with the till object/* the target output is (1p*10 + 5p*6 +50p*4 +20p*10) =440/100 = £4.40*/ -// b) Why do we need to use Object.entries inside the for...of loop in this function? +// b) Why do we need to use Object.entries inside the for...of loop in this function?// we use Object.entries to convert Object into an arrays of array to enable iteration as javaScript object is not iterable*/ // c) What does coin * quantity evaluate to inside the for...of loop? From 62439d4f306527700fc3d4fff0b2d652325ea4ca Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 23:00:04 +0100 Subject: [PATCH 46/48] Answered question c what the calculation evaluated to inside the for ...loop --- Sprint-2/stretch/till.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/stretch/till.js b/Sprint-2/stretch/till.js index 534dde2b3..a71ce1772 100644 --- a/Sprint-2/stretch/till.js +++ b/Sprint-2/stretch/till.js @@ -26,6 +26,6 @@ const totalAmount = totalTill(till); // b) Why do we need to use Object.entries inside the for...of loop in this function?// we use Object.entries to convert Object into an arrays of array to enable iteration as javaScript object is not iterable*/ -// c) What does coin * quantity evaluate to inside the for...of loop? +// c) What does coin * quantity evaluate to inside the for...of loop?/* The expression coin * quantity evaluated to NaN ,as Object.entries converted the object properties to string and after looping through , when the name Variable which is a string multiples a number they will concatenate to form NaN*/ // d) Write a test for this function to check it works and then fix the implementation of totalTill From 7ecfd73c39f1218f3c4734aba53772d91a08e2b9 Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 23:05:34 +0100 Subject: [PATCH 47/48] Wrote a test to check if the implementation worked --- Sprint-2/stretch/till.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Sprint-2/stretch/till.js b/Sprint-2/stretch/till.js index a71ce1772..63fd4bc2d 100644 --- a/Sprint-2/stretch/till.js +++ b/Sprint-2/stretch/till.js @@ -22,6 +22,15 @@ const till = { }; const totalAmount = totalTill(till); +const result = totalAmount; +const expectedResult = "£4.40"; + +if (result === expectedResult) { + console.log("✅ Test Passed!"); +} else { + console.log(`❌ Test Failed. Expected ${expectedResult} but got ${result}`); +} + // a) What is the target output when totalTill is called with the till object/* the target output is (1p*10 + 5p*6 +50p*4 +20p*10) =440/100 = £4.40*/ // b) Why do we need to use Object.entries inside the for...of loop in this function?// we use Object.entries to convert Object into an arrays of array to enable iteration as javaScript object is not iterable*/ From 7a9a51df408fd93aa0515f50d5048eb67210c64c Mon Sep 17 00:00:00 2001 From: Tobias Date: Mon, 27 Jul 2026 23:12:28 +0100 Subject: [PATCH 48/48] Implement the function to pass the test --- Sprint-2/stretch/till.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sprint-2/stretch/till.js b/Sprint-2/stretch/till.js index 63fd4bc2d..ec3cec837 100644 --- a/Sprint-2/stretch/till.js +++ b/Sprint-2/stretch/till.js @@ -8,10 +8,11 @@ function totalTill(till) { let total = 0; for (const [coin, quantity] of Object.entries(till)) { - total += coin * quantity; + const coinValue = parseInt(coin); + total += coinValue * quantity; } - return `£${total / 100}`; + return `£${(total / 100).toFixed(2)}`; } const till = {