From 0ada3c78331a8629ecf43fa51192854eae1e49ee Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Tue, 17 Mar 2026 22:35:08 +0000 Subject: [PATCH 01/24] fix: correct address property access in console log --- 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..fde180d6d 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 51fbc9386092e83ff3ad90637e49a683e412f3d0 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Tue, 17 Mar 2026 22:58:11 +0000 Subject: [PATCH 02/24] fix: iterate over author object values instead of object directly --- Sprint-2/debug/author.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..3667ab42f 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -11,6 +11,10 @@ const author = { alive: true, }; -for (const value of author) { +for (const value of Object.values(author)) { console.log(value); } + + +// It did work because an object is not iterable as an array, but we can use Object.values() +// to get an array of the property values and then iterate over that array. \ No newline at end of file From 2af5e5273ef3588677183e7fe53bf3b809743b15 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 18 Mar 2026 20:51:58 +0000 Subject: [PATCH 03/24] feat: add for of to print the ingredients logged on a new line --- Sprint-2/debug/recipe.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..5c6dbd4f6 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -4,12 +4,20 @@ // Each ingredient should be logged on a new line // How can you fix it? +// it won't work because the last line is calling the object property recipe and we +// need the ingredientes, the console.log is trying to log the whole array of ingredients +// as a string, but we want to log each ingredient on a new line. We can fix this by +// using a for loop to iterate over the ingredients array and log each ingredient separately. + const recipe = { - title: "bruschetta", + title: "Bruschetta", serves: 2, ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; -console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); +console.log(`Recipe: ${recipe.title} \nserves: ${recipe.serves}`); +for(const ingredient of recipe.ingredients) { + console.log(`${ingredient}`); +} + + From 431ad8dccf53f49b2002319dd30ec12f9621448c Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 18 Mar 2026 21:27:19 +0000 Subject: [PATCH 04/24] test: enhance contains function tests for various scenarios --- Sprint-2/implement/contains.test.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..fa0286034 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -16,20 +16,35 @@ 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 +test("return true when an object has the property name", () => { + expect(contains({a: 1, b: 2}, "a")).toBe(true); +}) // Given an empty object // When passed to contains // Then it should return false -test.todo("contains on empty object returns false"); +test("returns false on empty object ", () => { + expect(contains({}, "a")).toBe(false); +}); // Given an object with properties // When passed to contains with an existing property name // Then it should return true +test("return true when pass an object that contains the property name", () => { + expect(contains({name: "John", age: 30}, "name")).toBe(true); +}) // Given an object with properties // When passed to contains with a non-existent property name // Then it should return false +test("return false when pass an object that does not contain the property name", () => { + expect(contains({id: 12, status: "active"}, "age")).toBe(false); +}) // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error +test("return false when pass an array instead of an object", () => { + expect(contains([1, 2, 3], "name")).toBe(false); + expect(contains(null, "prop")).toBe(false); +}) From 12b176a1d7eb7e4a1f3333ae529887d31da267bf Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 18 Mar 2026 21:45:18 +0000 Subject: [PATCH 05/24] feat: implement contains function to check property existence in objects --- Sprint-2/implement/contains.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..cbac8e5a9 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,12 @@ -function contains() {} +function contains(obj, property) { + if (typeof obj !== "object" || obj === null || Array.isArray(obj)){ + return false; + } + + return property in obj; +} + module.exports = contains; + + From a6db5d0e500c68090dd169bdf5dcc6103e8e0a0e Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 18 Mar 2026 22:44:30 +0000 Subject: [PATCH 06/24] test: add tests for createLookup function to validate country and currency code --- Sprint-2/implement/lookup.test.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..b6ba7c768 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,5 @@ const createLookup = require("./lookup.js"); -test.todo("creates a country currency code lookup for multiple codes"); /* @@ -33,3 +32,20 @@ It should return: 'CA': 'CAD' } */ + +test("return an object with country codes as keys and currency codes as values", () => { + expect( createLookup([ ["MX", "MXN"], ["JP", "JPY"] ])).toEqual({ MX: "MXN", JP: "JPY"}); + expect( createLookup([ ["AU", "AUD"], ["CH", "CHF"] ])).toEqual({ AU: "AUD", CH: "CHF" }); +}); + +describe("return an object with country codes as keys and currency codes as values", () => { + [ + { input: [["US", "USD"],["CA", "CAD"]], expected: { US: "USD", CA: "CAD" } }, + { input: [["GB", "GBP"],["FR", "EUR"]], expected: { GB: "GBP", FR: "EUR" } }, + { input: [["JP", "JPY"],["AU", "AUD"]], expected: { JP: "JPY", AU: "AUD" } }, + ].forEach(({ input, expected }) => { + it(`should convert ${JSON.stringify(input)} into ${JSON.stringify(expected)}`, () => { + expect(createLookup(input)).toEqual(expected); + }); + }); +}); From 45eff04bb8754696beab9bffa4ecb119bb905c20 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 18 Mar 2026 22:45:27 +0000 Subject: [PATCH 07/24] feat: implement createLooKup function to map countries to currencies --- Sprint-2/implement/lookup.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..dd08c9306 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,9 @@ -function createLookup() { - // implementation here +function createLookup(pairs) { + const result = {}; + for(const [country, currency] of pairs) { + result[country] = currency; + } + return result } module.exports = createLookup; From 8e727fa733a080bc1070aac58ce30d5bd2e4820f Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 18 Mar 2026 23:17:49 +0000 Subject: [PATCH 08/24] fix: correct implementation of invert function to return expected key-value pairs --- Sprint-2/interpret/invert.js | 44 ++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..7cf548f67 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -10,20 +10,50 @@ function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj[value] = key; } return invertedObj; } -// a) What is the current return value when invert is called with { a : 1 } +console.log(invert({ a: 1, b: 2 })); // Expected output: { '1': 'a', '2': 'b' } -// b) What is the current 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} -// c) What does Object.entries return? Why is it needed in this program? +/* +a) What is the current return value when invert is called with { a : 1 } + *the value { key: 1 } + +b) What is the current return value when invert is called with { a: 1, b: 2 } + *the first pair is { key: 1 } + *and the second pair the value is { key: 'b' } that means the first pair is + being overwritten by the second pair, so the final return value is { key: 'b' } + +c) What is the target return value when invert is called with {a : 1, b: 2} + *the target return value is { "1": "a", "2": "b" } + +d) What does Object.entries return? Why is it needed in this program? + *Return value: It returns an array of arrays, where each sub-array is a [key, value] + pair (e.g., [['a', 1]]). + *Why it's needed: Objects are not iterables by default. We need Object.entries + to convert the object into an array so we can use the for...of loop to go through each pair. + +e) Explain why the current return value is different from the target output + *Literal Property Creation: The current code uses dot notation (invertedObj.key), + which creates a property literally named "key" instead of using the value stored + inside the key variable. + + *Overwriting: Because it keeps targetting the same literal property name ("key"), + each iteration overwrites the previous one. This is why the final object only contains + the last value processed. + + *Target vs. Current: The target output requires bracket notation (invertedObj[value]) + to dynamically assign the new keys based on the input's values. + + +f) Fix the implementation of invert (and write tests to prove it's fixed!) + expect({ a: 1, b: 2 })toEqual({ '1': 'a', '2': 'b' } ) now is working as expected + +**/ -// d) Explain why the current return value is different from the target output -// e) Fix the implementation of invert (and write tests to prove it's fixed!) From bbadd0548720582b0f38ffb0aaebf74e3c65f038 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Thu, 26 Mar 2026 14:07:57 +0000 Subject: [PATCH 09/24] feat: simplify ingredient logging by joining array elements --- Sprint-2/debug/recipe.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 5c6dbd4f6..5e389e417 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -15,9 +15,6 @@ const recipe = { ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; -console.log(`Recipe: ${recipe.title} \nserves: ${recipe.serves}`); -for(const ingredient of recipe.ingredients) { - console.log(`${ingredient}`); -} - +console.log(`Recipe: ${recipe.title} \nserves: ${recipe.serves}`); +console.log(recipe.ingredients.join("\n")); \ No newline at end of file From 5954a24b834972699d7f6de3750769df205fdb78 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Thu, 26 Mar 2026 16:48:35 +0000 Subject: [PATCH 10/24] fix: replace property check with Object.hasOwn for better accuracy --- Sprint-2/implement/contains.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cbac8e5a9..5ff840c0a 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -3,10 +3,8 @@ function contains(obj, property) { return false; } - return property in obj; + return Object.hasOwn(obj, property); } module.exports = contains; - - From 32d596c5d2baff934c9b5408ce47d1e303c56020 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Thu, 26 Mar 2026 16:52:22 +0000 Subject: [PATCH 11/24] test: add test for inherited properties in contains function --- Sprint-2/implement/contains.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index fa0286034..8ec01656d 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -48,3 +48,10 @@ test("return false when pass an array instead of an object", () => { expect(contains([1, 2, 3], "name")).toBe(false); expect(contains(null, "prop")).toBe(false); }) + +// Given: A standard object created with literal notation {}. +// When: It is passed to the 'contains' function looking for a built-in property like "toString". +// Then: It should return false because the object is not the "owner" of that property. +test("Should return false for inherited properties like 'toString'", () => { + expect(contains({}, "toString")).toBe(false); +}); \ No newline at end of file From 5fb163b68dd8dd3898e64831f96840fd668b70c2 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Thu, 26 Mar 2026 17:20:16 +0000 Subject: [PATCH 12/24] test: add additional tests for non-object parameters in contains function --- Sprint-2/implement/contains.test.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 8ec01656d..7f0d07dc7 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -42,13 +42,22 @@ test("return false when pass an object that does not contain the property name", }) // Given invalid parameters like an array -// When passed to contains +// When: Checking for a valid array property like 'length' or an index // Then it should return false or throw an error test("return false when pass an array instead of an object", () => { - expect(contains([1, 2, 3], "name")).toBe(false); - expect(contains(null, "prop")).toBe(false); + expect(contains(["Banana"], "length")).toBe(false); + expect(contains(["Apple"], "0")).toBe(false); }) +// Given a value that is null, undefined, or a primitive (like 123) +// When passed to the contains function +// Then it should return false to prevent errors and ensure only real objects are processed. +test("should return false for null and other non-objects", () => { + expect(contains(null, "prop")).toBe(false); + expect(contains(undefined, "prop")).toBe(false); + expect(contains(123, "toFixed")).toBe(false); +}); + // Given: A standard object created with literal notation {}. // When: It is passed to the 'contains' function looking for a built-in property like "toString". // Then: It should return false because the object is not the "owner" of that property. From 7de36928dd2793e786297438789c054fda5c80d7 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Fri, 27 Mar 2026 22:15:48 +0000 Subject: [PATCH 13/24] fix: enhance query string parsing to handle empty and malformed pairs --- Sprint-2/implement/querystring.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..2bb036706 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,15 +1,22 @@ function parseQueryString(queryString) { const queryParams = {}; - if (queryString.length === 0) { + if (!queryString || queryString.trim() === "" ) { return queryParams; } const keyValuePairs = queryString.split("&"); - for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); - queryParams[key] = value; - } + for(const pair of keyValuePairs){ + if(!pair) continue; + + const [key, ...rest] = pair.split("="); + + const value = rest.join("="); + if (key) { + queryParams[key] = value; + } + + } return queryParams; } From 9f2cfaa5d83b901cc8b7a09d6ef03aa5ffe51b02 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Mon, 30 Mar 2026 22:20:08 +0100 Subject: [PATCH 14/24] fix: improve query string parsing to decode keys and values correctly --- Sprint-2/implement/querystring.js | 5 ++++- Sprint-2/implement/querystring.test.js | 11 +++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 2bb036706..c525237b1 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -13,7 +13,10 @@ function parseQueryString(queryString) { const value = rest.join("="); if (key) { - queryParams[key] = value; + + const decodedkey = decodeURIComponent(key.replace(/\+/g, "")); + const decodedValue = decodeURIComponent(value.replace(/\+/g, " ")); + queryParams[decodedkey] = decodedValue; } } diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3e218b789..3070388bf 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -5,8 +5,15 @@ const parseQueryString = require("./querystring.js") + +// Given a querystring with a value that contains an = symbol +// When passed to parseQueryString +// Then it should treat everything after the first = as the value test("parses querystring values containing =", () => { - expect(parseQueryString("equation=x=y+1")).toEqual({ - "equation": "x=y+1", + expect(parseQueryString("equation=x=y%2B1")).toEqual({ + equation: "x=y+1", }); }); + +// Given an empty string +// when From f576b001fa3356c0f67bf02ae3001705801b9f7f Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Mon, 30 Mar 2026 23:49:23 +0100 Subject: [PATCH 15/24] test: add tests for query string parsing edge cases --- Sprint-2/implement/querystring.test.js | 44 ++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3070388bf..4da5996b6 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -6,7 +6,7 @@ const parseQueryString = require("./querystring.js") -// Given a querystring with a value that contains an = symbol +// Given a querystring with a value that contains an = symbol ( + URL encoded as %2B and spaces encoded as + ) // When passed to parseQueryString // Then it should treat everything after the first = as the value test("parses querystring values containing =", () => { @@ -15,5 +15,43 @@ test("parses querystring values containing =", () => { }); }); -// Given an empty string -// when +// Given an querystring string with spaces encoded as (%20 and +) +// when passed to parseQueryString +// then it should return the string with real spaces in both cases +test("decodes spaces correctly from both %20 and +", () => { + expect(parseQueryString("name=John%20Doe&city=New+York")).toEqual({ + "name": "John Doe", + "city": "New York", + }); +}); + + +// Given a URL-encoded key like like %5B%5D = [] +// When passed to parseQueryString +// Then it should decode the key to 'tags[]' +test("Handles URL-Encoded keys", () =>{ + expect(parseQueryString("tags%5B%5D=javascript")).toEqual({ + "tags[]": "javascript", + }); +}) + +// Given a string with multiple ampersands like a=1&&b=2&c=3&& +// When passed to parseQueryString +// Then it should ignore the empty segments and return valid pairs +test("Should ignore empty ampersand", () => { + expect(parseQueryString("a=1&&b=2")).toEqual({ + a: "1", + b: "2", + + }); +}) + +// Given a key without a value like 'flag' or 'empty=' +// When passed to parseQueryString +// Then it should return the key with an empty string as value +test("handles keys with no values", () => { + expect(parseQueryString("empty=&flag")).toEqual({ + "empty": "", + "flag": "" + }); +}); \ No newline at end of file From c8745abfef61245b74f78300eefb4e4383bc393e Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Tue, 31 Mar 2026 20:54:34 +0100 Subject: [PATCH 16/24] test: update query string parsing test to cover additional value formats --- Sprint-2/implement/querystring.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 4da5996b6..3341bbc01 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -9,7 +9,7 @@ const parseQueryString = require("./querystring.js") // Given a querystring with a value that contains an = symbol ( + URL encoded as %2B and spaces encoded as + ) // When passed to parseQueryString // Then it should treat everything after the first = as the value -test("parses querystring values containing =", () => { +test('parses querystring values containing (=, +, " ")', () => { expect(parseQueryString("equation=x=y%2B1")).toEqual({ equation: "x=y+1", }); From f1acefa2847f63b11a18bf9dccd281c1397219c0 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Tue, 31 Mar 2026 22:21:40 +0100 Subject: [PATCH 17/24] test: add unit tests for tally function to validate item counting and error handling --- Sprint-2/implement/tally.test.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..3ef605508 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -19,16 +19,29 @@ const tally = require("./tally.js"); // Given a function called tally // When passed an array of items // Then it should return an object containing the count for each unique item +test("Should return an object with the count of each unique item in the array", () => { + expect(tally(['a'])).toEqual({ a: 1 }); + expect(tally(['a', 'a', 'a'])).toEqual({ a: 3 }); + expect(tally(['a', 'a', 'b', 'c'])).toEqual({ a : 2, b: 1, c: 1 }); +}); // Given an empty array // When passed to tally // Then it should return an empty object -test.todo("tally on an empty array returns an empty object"); +test("Should return an empty object when passed an empty array", () => { + expect(tally([])).toEqual({}); +}); // Given an array with duplicate items // When passed to tally // Then it should return counts for each unique item +test("Should return counts for each unique item in an array with duplicate items", () => { + expect(tally(['x', 'y', 'x', 'z', 'y', 'x'])).toEqual({ x: 3, y: 2, z: 1 }); +}); // Given an invalid input like a string // When passed to tally // Then it should throw an error +test("Should throw and error when passed and invalid input like a string", () => { + expect(() => tally('not an array')).toThrow('Input must be an array'); +}); From 65beafc36e5b1cdd1f44a73bd32b1fefff2b712f Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Tue, 31 Mar 2026 22:21:57 +0100 Subject: [PATCH 18/24] feat: implement tally function to count items in an array with error handling --- Sprint-2/implement/tally.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..0420d99bf 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,14 @@ -function tally() {} +function tally(items) { + const counts = {}; + + if (!Array.isArray(items)) { + throw new Error("Input must be an array"); + } + + for (const item of items) { + counts[item] = (counts[item] || 0) + 1; + } + return counts; +} module.exports = tally; From 9ed9f13043c0fedc2974f7f5ee1b0698ac658f5c Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Tue, 31 Mar 2026 23:04:48 +0100 Subject: [PATCH 19/24] refactor: split calculateMode into smaller functions for improved readability --- Sprint-2/stretch/mode.js | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/Sprint-2/stretch/mode.js b/Sprint-2/stretch/mode.js index 3f7609d79..9f95c1f93 100644 --- a/Sprint-2/stretch/mode.js +++ b/Sprint-2/stretch/mode.js @@ -8,22 +8,25 @@ // 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(); - for (let num of list) { - if (typeof num !== "number") { - continue; - } +// track frequency of each value +function getFrequency(list) { + let frequency = new Map(); - freqs.set(num, (freqs.get(num) || 0) + 1); + for (let num of list) { + if (typeof num !== "number") continue; + frequency.set(num, (frequency.get(num) || 0) + 1); } + return frequency; +} + - // Find the value with the highest frequency +// Find the value with the highest frequency +function getHighestFrequency(frequency) { let maxFreq = 0; let mode; - for (let [num, freq] of freqs) { + + for (let [num, freq] of frequency) { if (freq > maxFreq) { mode = num; maxFreq = freq; @@ -33,4 +36,11 @@ function calculateMode(list) { return maxFreq === 0 ? NaN : mode; } +// The refactored calculateMode using the stages above +function calculateMode(list) { + const frequency = getFrequency(list); + return getHighestFrequency(frequency); +} + + module.exports = calculateMode; From 0a6a3519dea81727a4f6b41ee5dffc8f1dfd8fd9 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 1 Apr 2026 00:37:50 +0100 Subject: [PATCH 20/24] fix: correct coin value calculation and format total output in totalTill function --- Sprint-2/stretch/till.js | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/Sprint-2/stretch/till.js b/Sprint-2/stretch/till.js index 6a08532e7..ba9ec4e37 100644 --- a/Sprint-2/stretch/till.js +++ b/Sprint-2/stretch/till.js @@ -8,24 +8,28 @@ 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 = { - "1p": 10, - "5p": 6, - "50p": 4, - "20p": 10, -}; -const totalAmount = totalTill(till); -// a) What is the target output when totalTill is called with the till object +module.exports = totalTill; -// b) Why do we need to use Object.entries inside the for...of loop in this function? +/* -// c) What does coin * quantity evaluate to inside the for...of loop? +a) What is the target output when totalTill is called with the till object + ----£4.40 because the total value of the coins in the till is 440 pence, which is equivalent to £4.40. -// d) Write a test for this function to check it works and then fix the implementation of totalTill +b) Why do we need to use Object.entries inside the for...of loop in this function? + ----Object.entries allows us to iterate over the key-value pairs of the till object, + otherwise is an object and we cannot directly iterate over it with a for...of loop. + +c) What does coin * quantity evaluate to inside the for...of loop? + ----£NaN because the coin values are strings multiplied by numbers, which results in NaN. + +d) Write a test for this function to check it works and then fix the implementation of totalTill + +**/ \ No newline at end of file From dace1b2543bfbbd05dec5794d3cb8ccb1f44daf1 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 1 Apr 2026 00:38:10 +0100 Subject: [PATCH 21/24] test: add unit tests for totalTill function to validate coin calculations --- Sprint-2/stretch/till.test.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Sprint-2/stretch/till.test.js diff --git a/Sprint-2/stretch/till.test.js b/Sprint-2/stretch/till.test.js new file mode 100644 index 000000000..5a3958a29 --- /dev/null +++ b/Sprint-2/stretch/till.test.js @@ -0,0 +1,28 @@ +const totalTill = require("./till.js"); + +describe("totalTill", () => { + test("returns the total amount in pounds for a given till object", () => { + const till = { + "1p": 10, + "5p": 6, + "50p": 4, + "20p": 10, + }; + + expect(totalTill(till)).toEqual("£4.40"); + }); + + test("returns £0.00 for an empty till", () => { + const emptyTill = {}; + + expect(totalTill(emptyTill)).toEqual("£0.00"); + }); + + test("handles tills with only one type of coin", () => { + const singleCoinTill = { + "10p": 5, + }; + + expect(totalTill(singleCoinTill)).toEqual("£0.50"); + }); +}); From e100de671571f32502c5f12318e30c38f3f6a7d0 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 1 Apr 2026 00:56:21 +0100 Subject: [PATCH 22/24] fix: update comments in invert function to clarify return values --- Sprint-2/interpret/invert.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index 7cf548f67..db022ed4a 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -6,6 +6,7 @@ // E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"} + function invert(obj) { const invertedObj = {}; @@ -22,12 +23,12 @@ console.log(invert({ a: 1, b: 2 })); // Expected output: { '1': 'a', '2': 'b' } /* a) What is the current return value when invert is called with { a : 1 } - *the value { key: 1 } + * is the following { key: 1 } b) What is the current return value when invert is called with { a: 1, b: 2 } *the first pair is { key: 1 } - *and the second pair the value is { key: 'b' } that means the first pair is - being overwritten by the second pair, so the final return value is { key: 'b' } + *and the second pair the value is { key: '2' } that means the first pair is + being overwritten by the second pair, so the final return value is { key: '2' } c) What is the target return value when invert is called with {a : 1, b: 2} *the target return value is { "1": "a", "2": "b" } From 2a4bad9a8d8abaa13615735414c3703c4617045d Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 1 Apr 2026 01:03:09 +0100 Subject: [PATCH 23/24] fix: correct variable name for decoded key in query string parsing --- 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 c525237b1..80852a80d 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -14,9 +14,9 @@ function parseQueryString(queryString) { if (key) { - const decodedkey = decodeURIComponent(key.replace(/\+/g, "")); + const decodedKey = decodeURIComponent(key.replace(/\+/g, " ")); const decodedValue = decodeURIComponent(value.replace(/\+/g, " ")); - queryParams[decodedkey] = decodedValue; + queryParams[decodedKey] = decodedValue; } } From cbe948e06a3c763f6e53ff8c2dfa6f1d69927522 Mon Sep 17 00:00:00 2001 From: "Karla G." Date: Wed, 1 Apr 2026 01:18:20 +0100 Subject: [PATCH 24/24] fix: use Object.create(null) for counts in tally function to avoid prototype pollution --- 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 0420d99bf..f5db8d5b5 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,5 +1,5 @@ function tally(items) { - const counts = {}; + const counts = Object.create(null); if (!Array.isArray(items)) { throw new Error("Input must be an array");