From 5cf1d409951b9765c64c117a44e57a83293ef04b Mon Sep 17 00:00:00 2001 From: Fayaz Date: Thu, 5 Mar 2026 23:40:53 +0000 Subject: [PATCH 01/14] fixed the issue with the code in address, the objects are accessed using their property names by (dot). instead of index --- Sprint-2/debug/address.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..f91c6d5e0 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -1,4 +1,7 @@ // Predict and explain first... +// The code is trying to access the houseNumber property of the address object using an index, which is not correct. +// In JavaScript, objects are accessed using their property names, not indices. +// To fix this, we should use the property name 'houseNumber' instead of an index. // This code should log out the houseNumber from the address object // but it isn't working... @@ -12,4 +15,4 @@ const address = { postcode: "XYZ 123", }; -console.log(`My house number is ${address[0]}`); +console.log(`My house number is ${address.houseNumber}`); From d223f630314db95b5305400429b991d6a0b53df0 Mon Sep 17 00:00:00 2001 From: Fayaz Date: Thu, 5 Mar 2026 23:51:36 +0000 Subject: [PATCH 02/14] for of loop is used to log out the value fo authro object but it treats it as ordered list in for of so we can use for in in objects to access its key and value pair --- Sprint-2/debug/author.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..1c1180b1b 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -2,6 +2,8 @@ // 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 +// The code is trying to iterate over the properties of the author object using a for...of loop, which is not correct for objects in JavaScript. +// In JavaScript, objects are not iterable with for...of loops. Instead, we can use a for...in loop to iterate over the property names of the object, and then access the corresponding values. const author = { firstName: "Zadie", @@ -11,6 +13,6 @@ const author = { alive: true, }; -for (const value of author) { +for (const value in author) { console.log(value); } From da8a73ddce49df9dbe0e8a2974baae0119b38fbf Mon Sep 17 00:00:00 2001 From: Fayaz Date: Fri, 6 Mar 2026 00:04:18 +0000 Subject: [PATCH 03/14] used join method to make all the items of ingredients array in one array and then used line break to make each of them in new line --- Sprint-2/debug/recipe.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..6327f8fa2 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -3,6 +3,7 @@ // This program should log out the title, how many it serves and the ingredients. // Each ingredient should be logged on a new line // How can you fix it? +// The issue with the code is that it is trying to log the entire recipe object directly, which will not format the ingredients as desired. Instead, we need to access the properties of the recipe object and format the output correctly. We can use template literals to format the string and join the ingredients array with new line characters. const recipe = { title: "bruschetta", @@ -12,4 +13,4 @@ const recipe = { console.log(`${recipe.title} serves ${recipe.serves} ingredients: -${recipe}`); +${recipe.ingredients.join('\n')}`); From 1a07ec3dfc3f9ca07e1456b0439303a92e0e90f9 Mon Sep 17 00:00:00 2001 From: Fayaz Date: Fri, 6 Mar 2026 23:24:45 +0000 Subject: [PATCH 04/14] wrote function for contain and wrote test cases for acceptance criteria --- Sprint-2/implement/contains.js | 5 +++-- Sprint-2/implement/contains.test.js | 24 ++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..869517a74 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,4 @@ -function contains() {} - +function contains(obj, key) { + return key in obj; +} module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..fb2295a2a 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -16,20 +16,40 @@ 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("returns true if the object contains the property, false otherwise", () => { + const obj = { a: 1, b: 2 }; + + expect(contains(obj, "a")).toBe(true); // existing property + expect(contains(obj, "b")).toBe(true); // existing property + expect(contains(obj, "c")).toBe(false); // non‑existent property +}); + + // 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({}, "a")).toBe(false); + }); + // Given an object with properties // When passed to contains with an existing property name // Then it should return true - +test("contains on object with existing property returns true", () => { + 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("contains on object with non-existent property returns false", () => { + 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 +test("contains on invalid parameters returns false", () => { + expect(contains([], "a")).toBe(false); + }); From bbd644995fe52750e9546ef8e4574ec8c76e0c0e Mon Sep 17 00:00:00 2001 From: Fayaz Date: Fri, 6 Mar 2026 23:57:39 +0000 Subject: [PATCH 05/14] wrote the function lookup to look for country: currency pair and wrote test for it --- Sprint-2/implement/lookup.js | 15 +++++++++++++-- Sprint-2/implement/lookup.test.js | 12 +++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..664bcd4d1 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,16 @@ -function createLookup() { - // implementation here +function createLookup(countryCurrencyPairs) { +let lookup ={}; +for(let pair of countryCurrencyPairs){ +let key = pair[0]; +let value = pair[1]; +lookup[key] = value; } +return lookup; + + + +} + + module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..cb9c5f7dd 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,16 @@ const createLookup = require("./lookup.js"); -test.todo("creates a country currency code lookup for multiple codes"); +test("creates a country currency code lookup for multiple codes", () => { + const countryCurrencyPairs = [['US', 'USD'], ['CA', 'CAD'], ['GB', 'GBP']]; + const expectedLookup = { + US: 'USD', + CA: 'CAD', + GB: 'GBP' + }; + + expect(createLookup(countryCurrencyPairs)).toEqual(expectedLookup); +}); + /* From 93021521b5f9888c0168dc53b408a645be96ec81 Mon Sep 17 00:00:00 2001 From: Fayaz Date: Thu, 12 Mar 2026 23:47:53 +0000 Subject: [PATCH 06/14] changed comment from one line to multiple lines for readability. --- Sprint-2/debug/recipe.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6327f8fa2..59cad6579 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -3,7 +3,10 @@ // This program should log out the title, how many it serves and the ingredients. // Each ingredient should be logged on a new line // How can you fix it? -// The issue with the code is that it is trying to log the entire recipe object directly, which will not format the ingredients as desired. Instead, we need to access the properties of the recipe object and format the output correctly. We can use template literals to format the string and join the ingredients array with new line characters. +/* The issue with the code is that it is trying to log the entire recipe object directly, which will not format the ingredients as desired. +Instead, we need to access the properties of the recipe object and format the output correctly. +We can use template literals to format the string and join the ingredients array with new line characters. +*/ const recipe = { title: "bruschetta", From b44572c515bf29e9ed2c67c3292d9a6dd9ed73c0 Mon Sep 17 00:00:00 2001 From: Fayaz Date: Fri, 13 Mar 2026 00:12:19 +0000 Subject: [PATCH 07/14] implemented querystring function and wrote test for it with edge cases well --- Sprint-2/implement/querystring.js | 18 ++++++++++++++++-- Sprint-2/implement/querystring.test.js | 25 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..d1010f8c6 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,16 +1,30 @@ function parseQueryString(queryString) { const queryParams = {}; + if (queryString.length === 0) { return queryParams; } + const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); + const index = pair.indexOf("="); + + let key; + let value; + + if (index === -1) { + key = pair; + value = ""; + } else { + key = pair.slice(0, index); + value = pair.slice(index + 1); + } + queryParams[key] = value; } return queryParams; } -module.exports = parseQueryString; +module.exports = parseQueryString; \ No newline at end of file diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3e218b789..35fc1b0c8 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -10,3 +10,28 @@ test("parses querystring values containing =", () => { "equation": "x=y+1", }); }); + +test("parses querystring values containing &", () => { + expect(parseQueryString("equation=x&y=1")).toEqual({ + "equation": "x", + "y": "1", + }); +}); + +test("parses querystring values containing & and =", () => { + expect(parseQueryString("equation=x&y=1&formula=a=b+c")).toEqual({ + "equation": "x", + "y": "1", + "formula": "a=b+c", + }); +}); + +test("parses empty querystring", () => { + expect(parseQueryString("")).toEqual({}); +}); + +test("parses querystring with no value", () => { + expect(parseQueryString("key")).toEqual({ + "key": "", + }); +}); \ No newline at end of file From 320bf84b4590d9d019837b5f4f27939ddd96720e Mon Sep 17 00:00:00 2001 From: Fayaz Date: Fri, 13 Mar 2026 00:19:10 +0000 Subject: [PATCH 08/14] implemented tally function adn wrote test cases for it --- Sprint-2/implement/tally.js | 20 ++++++++++++++++++-- Sprint-2/implement/tally.test.js | 15 ++++++++++++++- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..05b271042 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,19 @@ -function tally() {} +function tally(items) { + if (!Array.isArray(items)) { + throw new Error("Input must be an array"); + } -module.exports = tally; + const result = {}; + + for (const item of items) { + if (result[item]) { + result[item]++; + } else { + result[item] = 1; + } + } + + return result; +} + +module.exports = tally; \ No newline at end of file diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..4126e9ffd 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("tally counts the frequency of each item in an 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("tally on an empty array returns an empty object", () => { + expect(tally([])).toEqual({}); +}); // Given an array with duplicate items // When passed to tally // Then it should return counts for each unique item +test("tally counts duplicate items correctly", () => { + expect(tally(["x", "y", "x", "z", "y"])).toEqual({ x: 2, y: 2, z: 1 }); +}); // Given an invalid input like a string // When passed to tally // Then it should throw an error +test("tally throws an error for non-array input", () => { + expect(() => tally("not an array")).toThrow("Input must be an array"); +}); From 0a1884564675308c69fc3f4deae6a23412db3134 Mon Sep 17 00:00:00 2001 From: Fayaz Date: Mon, 23 Mar 2026 21:40:03 +0000 Subject: [PATCH 09/14] fixed implementation and write test to prove its fixed --- Sprint-2/interpret/invert.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..1397c558e 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -6,7 +6,7 @@ // E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"} -function invert(obj) { +/* function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { @@ -15,15 +15,42 @@ function invert(obj) { return invertedObj; } + */ // 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 return value is { key: 1, 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" } // c) What does Object.entries return? Why is it needed in this program? +/* Object.entries returns an array of a given object's own enumerable string-keyed property [key, value] pairs. +In this program, it is needed to iterate over the key-value pairs of the input object so that we can swap them and create the inverted object. +*/ // d) Explain why the current return value is different from the target output +/* The current return value is different from the target output because in the current implementation, + we are assigning the value to a property named "key" in the inverted object, + which means that every key-value pair in the input object will overwrite the same "key" property in the inverted object. + As a result, only the last key-value pair from the input object will be reflected in the inverted object, leading to incorrect output. + To achieve the target output, we need to use the value from the input object as the key in the inverted object and + the key from the input object as the value in the inverted object. +*/ // e) Fix the implementation of invert (and write tests to prove it's fixed!) +function invert(obj) { + const invertedObj = {}; + + for (const [key, value] of Object.entries(obj)) { + invertedObj[value] = key; + } + + return invertedObj; +} + + + +expect(invert({ a: 1, b: 2 })).toEqual({ '1': 'a', '2': 'b' }); From ed9cce67702c7816772c30a8c8b065aeacd2893a Mon Sep 17 00:00:00 2001 From: Fayaz Date: Tue, 7 Apr 2026 22:18:40 +0100 Subject: [PATCH 10/14] clarify for...in loop iteration over object keys vs values. --- Sprint-2/debug/author.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 1c1180b1b..1964fc732 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -13,6 +13,6 @@ const author = { alive: true, }; -for (const value in author) { - console.log(value); -} +for (const key in author) { + console.log(author[key]); +} \ No newline at end of file From 106cf86a2e1cac75849255e641b9753d3eff0b3f Mon Sep 17 00:00:00 2001 From: Fayaz Date: Tue, 7 Apr 2026 22:21:39 +0100 Subject: [PATCH 11/14] used Object.hasOwn for stricter property checking. --- Sprint-2/implement/contains.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index 869517a74..de06b68b0 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,4 +1,5 @@ function contains(obj, key) { - return key in obj; + return Object.hasOwn(obj, key); } -module.exports = contains; + +module.exports = contains; \ No newline at end of file From d3e14ce9fe321da82165b25e81557a6cde8fbf05 Mon Sep 17 00:00:00 2001 From: Fayaz Date: Tue, 7 Apr 2026 22:27:51 +0100 Subject: [PATCH 12/14] strengthen array validation and update contains logic to reject arrays. --- Sprint-2/implement/contains.js | 4 ++++ Sprint-2/implement/contains.test.js | 10 +++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index de06b68b0..4eed2e990 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,4 +1,8 @@ function contains(obj, key) { + if (obj === null || typeof obj !== "object" || Array.isArray(obj)) { + return false; + } + return Object.hasOwn(obj, key); } diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index fb2295a2a..d1f3bc12a 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -50,6 +50,10 @@ test("contains on object with non-existent property returns false", () => { // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error -test("contains on invalid parameters returns false", () => { - expect(contains([], "a")).toBe(false); - }); + + test("contains on invalid parameters returns false", () => { + // We use an index that EXISTS in the array (0) + // If the function returns false, we know it's because it rejected the ARRAY type + expect(contains(["test"], 0)).toBe(false); + expect(contains(null, "a")).toBe(false); +}); \ No newline at end of file From b1c7edb7c919aefcb9159290bd7a493dba5cb2cf Mon Sep 17 00:00:00 2001 From: Fayaz Date: Tue, 7 Apr 2026 22:29:47 +0100 Subject: [PATCH 13/14] fixed indentation --- Sprint-2/implement/lookup.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index 664bcd4d1..8819e7327 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,16 +1,11 @@ function createLookup(countryCurrencyPairs) { -let lookup ={}; -for(let pair of countryCurrencyPairs){ -let key = pair[0]; -let value = pair[1]; -lookup[key] = value; + let lookup = {}; + for (let pair of countryCurrencyPairs) { + let key = pair[0]; + let value = pair[1]; + lookup[key] = value; + } + return lookup; } -return lookup; - - - -} - - module.exports = createLookup; From 4204a37060d2b2cfa9b9ee4a8752d78408dee480 Mon Sep 17 00:00:00 2001 From: Fayaz Date: Tue, 7 Apr 2026 22:38:34 +0100 Subject: [PATCH 14/14] use Object.create(null) to avoid inherited property conflicts in tally. --- 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 05b271042..8c87eb7f3 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 be an array"); } - const result = {}; + const result = Object.create(null); for (const item of items) { if (result[item]) {