From 3423b3d6fbce5decc6da366c3498b0dfc66bef7d Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 10 Apr 2026 19:20:31 +0200 Subject: [PATCH 01/28] Fix the code in the log on how to get dictionary 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 940a6af83..f28985431 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}`); \ No newline at end of file From 8ea5df9fbea73d7560ed7f3572f7d96184c75d8c Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 10 Apr 2026 20:02:08 +0200 Subject: [PATCH 02/28] Fix the code for iterating dictionary --- Sprint-2/debug/author.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..7ba8f4c75 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -11,6 +11,6 @@ const author = { alive: true, }; -for (const value of author) { +for (const value of Object.values(author)) { console.log(value); } From 1030df2f0a08e9e4828ddeeef34f7c2f37748763 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 10 Apr 2026 20:12:00 +0200 Subject: [PATCH 03/28] Fix the code to get ingredients from recipe to recipe.ingredient --- Sprint-2/debug/recipe.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..d0b246f22 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -12,4 +12,4 @@ const recipe = { console.log(`${recipe.title} serves ${recipe.serves} ingredients: -${recipe}`); +${recipe.ingredients}`); From b05607426dfe1708567425b1a3cfe6f4f67d98e9 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 10 Apr 2026 20:29:08 +0200 Subject: [PATCH 04/28] Implement the function contains --- Sprint-2/implement/contains.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..bd1be68b4 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,6 @@ -function contains() {} +function contains(Obj,key) { + if(Obj === null || typeof Obj !== "object" || Array.isArray(Obj)) return false; + return Object.prototype.hasOwnProperty.call(Obj, key); +} module.exports = contains; From dd0f4aa5b135d24f3a292e3ddfc24b01fd7272b7 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 10 Apr 2026 23:37:16 +0200 Subject: [PATCH 05/28] Write tests for contains function --- Sprint-2/implement/contains.test.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..a631e6414 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -33,3 +33,19 @@ test.todo("contains on empty object returns false"); // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error + +test("contains on empty object returns false", () => { + expect(contains({}, "a")).toEqual(false); +}); + +test("returns true when property exists", () => { + expect(contains({ a: 1, b: 2 }, "a")).toEqual(true); +}); + +test("returns false when property does not exist", () => { + expect(contains({ a: 1, b: 2 }, "c")).toEqual(false); +}); + +test("returns false for invalid input like array", () => { + expect(contains([1, 2, 3], "0")).toEqual(false); +}); \ No newline at end of file From 3926858fe68b086ea6ddbb70a7bde41a1804c704 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Sat, 11 Apr 2026 11:47:11 +0200 Subject: [PATCH 06/28] Implement function createLookUp --- Sprint-2/implement/lookup.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..6c2466437 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,5 @@ -function createLookup() { - // implementation here +function createLookup(countryCurrencyPairs) { +return Object.fromEntries(countryCurrencyPairs); } module.exports = createLookup; From cb7f840de05ebba8e039cf8b095999f8eb6b6155 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Sat, 11 Apr 2026 11:59:29 +0200 Subject: [PATCH 07/28] Add test for undefined array --- Sprint-2/implement/lookup.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index 6c2466437..1839a7455 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,4 +1,7 @@ function createLookup(countryCurrencyPairs) { + if (!Array.isArray(countryCurrencyPairs)) { + return {}; + } return Object.fromEntries(countryCurrencyPairs); } From 126e361e1a4ecca4b0a90c8a6f1c906af166a4ea Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Sat, 11 Apr 2026 11:59:52 +0200 Subject: [PATCH 08/28] Write tests for lookup function --- Sprint-2/implement/lookup.test.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..a27e6ba44 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -33,3 +33,31 @@ It should return: 'CA': 'CAD' } */ + + +test("returns empty object for empty array", () => { + expect(createLookup([])).toEqual({}); +}); + +test("creates lookup from country-currency pairs", () => { + expect(createLookup([['US', 'USD'], ['CA', 'CAD']])).toEqual({ + US: 'USD', + CA: 'CAD', + }); +}); + +test("handles single pair", () => { + expect(createLookup([['JP', 'JPY']])).toEqual({ + JP: 'JPY', + }); +}); + +test("overwrites duplicate country codes (last one wins)", () => { + expect(createLookup([['US', 'USD'], ['US', 'USN']])).toEqual({ + US: 'USN', + }); +}); + +test("handles invalid input (non-array)", () => { + expect(createLookup(null)).toEqual({}); +}); \ No newline at end of file From 35fb86ce036ee5865a8a3f2e48fa04f2fb5bfc72 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 09:17:05 +0200 Subject: [PATCH 09/28] Fix the code for queryString --- Sprint-2/implement/querystring.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..1dc051774 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -6,11 +6,12 @@ function parseQueryString(queryString) { const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); + var [key, ...value] = pair.split("="); + value = value.join("="); queryParams[key] = value; } return queryParams; } - +parseQueryString("equation=x=y+1"); module.exports = parseQueryString; From baf9e28c8d250a54e1f12e5b874fa7d48f644924 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 09:27:01 +0200 Subject: [PATCH 10/28] Remove ? from the query string --- Sprint-2/implement/querystring.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 1dc051774..62af86fe9 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -3,6 +3,10 @@ function parseQueryString(queryString) { if (queryString.length === 0) { return queryParams; } + if (queryString.startsWith('?')) { + queryString = queryString.slice(1); +} + const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { From c2cc321985d30203748f64c3bbdcf46ab70e63cc Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 09:32:28 +0200 Subject: [PATCH 11/28] Add code to skip empty segments --- Sprint-2/implement/querystring.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 62af86fe9..433604fb0 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -10,6 +10,7 @@ function parseQueryString(queryString) { const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { + if (!pair) continue; var [key, ...value] = pair.split("="); value = value.join("="); queryParams[key] = value; @@ -17,5 +18,5 @@ function parseQueryString(queryString) { return queryParams; } -parseQueryString("equation=x=y+1"); + module.exports = parseQueryString; From 8688782d82a0b5b1578d8d22514fbd2aa15b5c22 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 09:34:11 +0200 Subject: [PATCH 12/28] Add simple key value pair --- Sprint-2/implement/querystring.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3e218b789..05593b6db 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -10,3 +10,9 @@ test("parses querystring values containing =", () => { "equation": "x=y+1", }); }); +test("parses simple key-value pairs", () => { + expect(parseQueryString("name=alice&age=25")).toEqual({ + "name": "alice", + "age": "25", + }); +}); From 4fc58195491f15256ca094ec9a7400a5ffee3edb Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 09:52:58 +0200 Subject: [PATCH 13/28] Add test to check if it strips leading question marks --- Sprint-2/implement/querystring.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 05593b6db..4da84d18c 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -16,3 +16,9 @@ test("parses simple key-value pairs", () => { "age": "25", }); }); +test("strips leading question marks", () => { + expect(parseQueryString("?user=bob&status=active")).toEqual({ + "user": "bob", + "status": "active", + }); +}); From bde632c2e7dc84967a5410325e26f6f51b4c3ae8 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 10:07:55 +0200 Subject: [PATCH 14/28] Add test for null,empty and undefined --- Sprint-2/implement/querystring.test.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 4da84d18c..a620df312 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -22,3 +22,11 @@ test("strips leading question marks", () => { "status": "active", }); }); +test("returns empty object for empty string", () => { + expect(parseQueryString("")).toEqual({}); +}); + +test("returns empty object for null or undefined", () => { + expect(parseQueryString(null)).toEqual({}); + expect(parseQueryString(undefined)).toEqual({}); +}); From feb056f01e28d8716f7e4af5fe0ad418783576ad Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 10:18:12 +0200 Subject: [PATCH 15/28] Add test for URL Encoded Content --- Sprint-2/implement/querystring.js | 2 +- Sprint-2/implement/querystring.test.js | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 433604fb0..ef0415932 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,6 +1,6 @@ function parseQueryString(queryString) { const queryParams = {}; - if (queryString.length === 0) { + if (!queryString) { return queryParams; } if (queryString.startsWith('?')) { diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index a620df312..d5d36845d 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -30,3 +30,16 @@ test("returns empty object for null or undefined", () => { expect(parseQueryString(null)).toEqual({}); expect(parseQueryString(undefined)).toEqual({}); }); +test("decodes URL encoded keys and values", () => { + expect(parseQueryString("search=coding%20tutorials&city=New%20York")).toEqual({ + "search": "coding tutorials", + "city": "New York", + }); +}); + +test("decodes complex characters and emojis", () => { + expect(parseQueryString("item=%F0%9F%8D%95&price=%2410")).toEqual({ + "item": "🍕", + "price": "$10", + }); +}); From 51e10b8070d0c6538668d49a195c6374af162a57 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 10:19:49 +0200 Subject: [PATCH 16/28] Add test for redudant and duplicate ampersands --- Sprint-2/implement/querystring.test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index d5d36845d..6d59062a2 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -43,3 +43,16 @@ test("decodes complex characters and emojis", () => { "price": "$10", }); }); +test("ignores empty segments from double ampersands", () => { + expect(parseQueryString("a=1&&b=2")).toEqual({ + "a": "1", + "b": "2", + }); +}); + +test("ignores trailing ampersands", () => { + expect(parseQueryString("a=1&b=2&")).toEqual({ + "a": "1", + "b": "2", + }); +}); From 6a3191402d58d7981c5cf625038949bb5dca97c8 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 10:20:25 +0200 Subject: [PATCH 17/28] Add test for empty and missing values --- Sprint-2/implement/querystring.test.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 6d59062a2..2311841e5 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -56,3 +56,15 @@ test("ignores trailing ampersands", () => { "b": "2", }); }); +test("handles keys with empty values", () => { + expect(parseQueryString("key=")).toEqual({ + "key": "", + }); +}); + +test("handles keys without an equals sign", () => { + expect(parseQueryString("flag")).toEqual({ + "flag": "", + }); +}); + From 02c49e6585dd001e38279dbc3d4a48d52aa376f6 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 10:29:39 +0200 Subject: [PATCH 18/28] Fix code to pass the decodess url encoded strings and complex characters tests --- Sprint-2/implement/querystring.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index ef0415932..0249b3f89 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,18 +1,21 @@ function parseQueryString(queryString) { const queryParams = {}; - if (!queryString) { - return queryParams; - } + + if (!queryString) return queryParams; + if (queryString.startsWith('?')) { - queryString = queryString.slice(1); -} + queryString = queryString.slice(1); + } const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { if (!pair) continue; - var [key, ...value] = pair.split("="); - value = value.join("="); + + const [rawKey, ...rawValue] = pair.split("="); + const key = decodeURIComponent(rawKey); + const value = decodeURIComponent(rawValue.join("=")); + queryParams[key] = value; } From f370fe331d61ae7da79842c48dc3b5a5c736e130 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 10:44:15 +0200 Subject: [PATCH 19/28] Add test for empty array --- Sprint-2/implement/tally.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..d8ca58263 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -24,6 +24,9 @@ const tally = require("./tally.js"); // When passed to tally // Then it should return an empty object test.todo("tally on an empty array returns an empty object"); +test("Empty array of items",()=>{ + expect([]).toEqual({}); +}); // Given an array with duplicate items // When passed to tally From fa3b44255118032bc86408fa932bbd334516f9f9 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 10:53:50 +0200 Subject: [PATCH 20/28] Add code for the empty array --- Sprint-2/implement/tally.js | 8 +++++++- Sprint-2/implement/tally.test.js | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..e87c86905 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,9 @@ -function tally() {} +function tally(array) { + const tally = {}; + if(array.length === 0) + return tally; + + +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index d8ca58263..06bc9b67d 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -25,7 +25,7 @@ const tally = require("./tally.js"); // Then it should return an empty object test.todo("tally on an empty array returns an empty object"); test("Empty array of items",()=>{ - expect([]).toEqual({}); + expect(tally([])).toEqual({}); }); // Given an array with duplicate items @@ -35,3 +35,7 @@ test("Empty array of items",()=>{ // Given an invalid input like a string // When passed to tally // Then it should throw an error + +test("Invalid input",()=>{ + expect(tally("some string")).toThrow(); +}); \ No newline at end of file From 4176d2402c7ab41df232b8d2db6fcdaa2b750b87 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 11:13:10 +0200 Subject: [PATCH 21/28] Add code for throwing error if not array --- Sprint-2/implement/tally.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index e87c86905..5fb0736ae 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,5 +1,7 @@ function tally(array) { const tally = {}; + if(!Array.isArray(array)) + throw new TypeError("Expected an array"); if(array.length === 0) return tally; From e0f7967eb65332404ec40e19af3046925eb6353d Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 11:45:30 +0200 Subject: [PATCH 22/28] Add test for not array --- 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 06bc9b67d..f37f78f2e 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -37,5 +37,5 @@ test("Empty array of items",()=>{ // Then it should throw an error test("Invalid input",()=>{ - expect(tally("some string")).toThrow(); + expect(() => tally("not an array")).toThrow(TypeError); }); \ No newline at end of file From 85dab098c8b20755575f124b5e4ff515b6271b33 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 11:49:46 +0200 Subject: [PATCH 23/28] Add code for counting duplicates --- Sprint-2/implement/tally.js | 5 ++++- Sprint-2/implement/tally.test.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index 5fb0736ae..a444edc2f 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -4,7 +4,10 @@ function tally(array) { throw new TypeError("Expected an array"); if(array.length === 0) return tally; - +for (const item of array) { + tally[item] = (tally[item] || 0) + 1; + } + return tally; } diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index f37f78f2e..c01e2e3f6 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -38,4 +38,4 @@ test("Empty array of items",()=>{ test("Invalid input",()=>{ expect(() => tally("not an array")).toThrow(TypeError); -}); \ No newline at end of file +}); \ No newline at end of file From b046080dec2196a530adc6a02ebc825ee64f8a63 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 11:53:01 +0200 Subject: [PATCH 24/28] Add test for duplicate array --- Sprint-2/implement/tally.test.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index c01e2e3f6..33bfcda39 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -38,4 +38,13 @@ test("Empty array of items",()=>{ test("Invalid input",()=>{ expect(() => tally("not an array")).toThrow(TypeError); -}); \ No newline at end of file +}); +test("Test duplicate array",()=>{ +const duplicatesArray = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']; +const result = tally(duplicatesArray); + expect(result).toEqual({ + apple: 3, + banana: 2, + orange: 1, + }); +}); \ No newline at end of file From 29cfb099df6ecf39d3ff41299e83ce94cf870c59 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 12:02:46 +0200 Subject: [PATCH 25/28] Fix the code and answer the questions --- Sprint-2/interpret/invert.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..91f7707d9 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -5,7 +5,7 @@ // Then it should swap the keys and values in the object // E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"} - +/* function invert(obj) { const invertedObj = {}; @@ -17,13 +17,32 @@ function invert(obj) { } // a) What is the current return value when invert is called with { a : 1 } +//{ key: 1 } // b) What is the current return value when invert is called with { a: 1, b: 2 } +//{ 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? +//It returns An array of the object's own property [key, value] pairs. +// It allows the for...of loop to easily access both the key and the value at the same time during each iteration. // d) Explain why the current return value is different from the target output +//Using invertedObj.key creates a literal property named "key" on the object. +// To use the value inside the key variable, you must use bracket notation: invertedObj[key]. +//The function is setting the original value to the key. +// To actually "invert" the object, it needs to swap them: invertedObj[value] = key;. // 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; +} \ No newline at end of file From 20d5acca65b01fbabc7c4507ce8a71bebd3dfe59 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 12:04:45 +0200 Subject: [PATCH 26/28] Create test file for invert --- Sprint-2/interpret/invert.test.js | 1 + 1 file changed, 1 insertion(+) 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..b8b93fb2d --- /dev/null +++ b/Sprint-2/interpret/invert.test.js @@ -0,0 +1 @@ +const invert = require("./invert.js"); \ No newline at end of file From 6cc9c372550623442b39fb45d5e8c0243abecee6 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 12:10:38 +0200 Subject: [PATCH 27/28] Create test for the invert function --- Sprint-2/interpret/invert.js | 3 ++- Sprint-2/interpret/invert.test.js | 25 ++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index 91f7707d9..7a7767454 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -45,4 +45,5 @@ function invert(obj) { } return invertedObj; -} \ No newline at end of file +} +module.exports = invert; \ No newline at end of file diff --git a/Sprint-2/interpret/invert.test.js b/Sprint-2/interpret/invert.test.js index b8b93fb2d..ff3f2afda 100644 --- a/Sprint-2/interpret/invert.test.js +++ b/Sprint-2/interpret/invert.test.js @@ -1 +1,24 @@ -const invert = require("./invert.js"); \ No newline at end of file +const invert = require("./invert.js"); +test('inverts a single key-value pair', () => { + const input = { a: 1 }; + expect(invert(input)).toEqual({ 1: 'a' }); + }); +test('inverts multiple key-value pairs', () => { + const input = { a: 1, b: 2, c: 3 }; + const expected = { 1: 'a', 2: 'b', 3: 'c' }; + + expect(invert(input)).toEqual(expected); + }); + test('returns empty object for empty input', () => { + expect(invert({})).toEqual({}); + }); + test('overwrites keys when duplicate values exist', () => { + const input = { a: 1, b: 1 }; + expect(invert(input)).toEqual({ 1: 'b' }); + }); + test('turns boolean and null values into string keys', () => { + const input = { a: true, b: null }; + const expected = { 'true': 'a', 'null': 'b' }; + + expect(invert(input)).toEqual(expected); + }); \ No newline at end of file From 24b56be28b3d93213f50dee0466f308b5a0227f1 Mon Sep 17 00:00:00 2001 From: jamesishimwe Date: Fri, 1 May 2026 12:28:25 +0200 Subject: [PATCH 28/28] Format the code --- Sprint-2/debug/address.js | 2 +- Sprint-2/implement/contains.js | 7 ++-- Sprint-2/implement/contains.test.js | 2 +- Sprint-2/implement/lookup.js | 4 +-- Sprint-2/implement/lookup.test.js | 27 ++++++++++----- Sprint-2/implement/querystring.js | 8 ++--- Sprint-2/implement/querystring.test.js | 39 +++++++++++----------- Sprint-2/implement/tally.js | 17 ++++------ Sprint-2/implement/tally.test.js | 35 ++++++++++++-------- Sprint-2/interpret/invert.js | 2 +- Sprint-2/interpret/invert.test.js | 46 +++++++++++++------------- 11 files changed, 102 insertions(+), 87 deletions(-) diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index f28985431..36d2f865d 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.houseNumber}`); \ No newline at end of file +console.log(`My house number is ${address.houseNumber}`); diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index bd1be68b4..6b3ef26b9 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,6 +1,7 @@ -function contains(Obj,key) { - if(Obj === null || typeof Obj !== "object" || Array.isArray(Obj)) return false; - return Object.prototype.hasOwnProperty.call(Obj, key); +function contains(Obj, key) { + if (Obj === null || typeof Obj !== "object" || Array.isArray(Obj)) + return false; + return Object.prototype.hasOwnProperty.call(Obj, key); } module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index a631e6414..0c4b1ced3 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -48,4 +48,4 @@ test("returns false when property does not exist", () => { test("returns false for invalid input like array", () => { expect(contains([1, 2, 3], "0")).toEqual(false); -}); \ No newline at end of file +}); diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index 1839a7455..3281fdf20 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,8 +1,8 @@ function createLookup(countryCurrencyPairs) { - if (!Array.isArray(countryCurrencyPairs)) { + if (!Array.isArray(countryCurrencyPairs)) { return {}; } -return Object.fromEntries(countryCurrencyPairs); + return Object.fromEntries(countryCurrencyPairs); } module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index a27e6ba44..d92c73101 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -34,30 +34,39 @@ It should return: } */ - test("returns empty object for empty array", () => { expect(createLookup([])).toEqual({}); }); test("creates lookup from country-currency pairs", () => { - expect(createLookup([['US', 'USD'], ['CA', 'CAD']])).toEqual({ - US: 'USD', - CA: 'CAD', + expect( + createLookup([ + ["US", "USD"], + ["CA", "CAD"], + ]) + ).toEqual({ + US: "USD", + CA: "CAD", }); }); test("handles single pair", () => { - expect(createLookup([['JP', 'JPY']])).toEqual({ - JP: 'JPY', + expect(createLookup([["JP", "JPY"]])).toEqual({ + JP: "JPY", }); }); test("overwrites duplicate country codes (last one wins)", () => { - expect(createLookup([['US', 'USD'], ['US', 'USN']])).toEqual({ - US: 'USN', + expect( + createLookup([ + ["US", "USD"], + ["US", "USN"], + ]) + ).toEqual({ + US: "USN", }); }); test("handles invalid input (non-array)", () => { expect(createLookup(null)).toEqual({}); -}); \ No newline at end of file +}); diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 0249b3f89..0872f83fa 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,9 +1,9 @@ function parseQueryString(queryString) { const queryParams = {}; - + if (!queryString) return queryParams; - if (queryString.startsWith('?')) { + if (queryString.startsWith("?")) { queryString = queryString.slice(1); } @@ -11,11 +11,11 @@ function parseQueryString(queryString) { for (const pair of keyValuePairs) { if (!pair) continue; - + const [rawKey, ...rawValue] = pair.split("="); const key = decodeURIComponent(rawKey); const value = decodeURIComponent(rawValue.join("=")); - + queryParams[key] = value; } diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 2311841e5..e6b0e31df 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -3,23 +3,23 @@ // Below is one test case for an edge case the implementation doesn't handle well. // Fix the implementation for this test, and try to think of as many other edge cases as possible - write tests and fix those too. -const parseQueryString = require("./querystring.js") +const parseQueryString = require("./querystring.js"); test("parses querystring values containing =", () => { expect(parseQueryString("equation=x=y+1")).toEqual({ - "equation": "x=y+1", + equation: "x=y+1", }); }); test("parses simple key-value pairs", () => { expect(parseQueryString("name=alice&age=25")).toEqual({ - "name": "alice", - "age": "25", + name: "alice", + age: "25", }); }); test("strips leading question marks", () => { expect(parseQueryString("?user=bob&status=active")).toEqual({ - "user": "bob", - "status": "active", + user: "bob", + status: "active", }); }); test("returns empty object for empty string", () => { @@ -31,40 +31,41 @@ test("returns empty object for null or undefined", () => { expect(parseQueryString(undefined)).toEqual({}); }); test("decodes URL encoded keys and values", () => { - expect(parseQueryString("search=coding%20tutorials&city=New%20York")).toEqual({ - "search": "coding tutorials", - "city": "New York", - }); + expect(parseQueryString("search=coding%20tutorials&city=New%20York")).toEqual( + { + search: "coding tutorials", + city: "New York", + } + ); }); test("decodes complex characters and emojis", () => { expect(parseQueryString("item=%F0%9F%8D%95&price=%2410")).toEqual({ - "item": "🍕", - "price": "$10", + item: "🍕", + price: "$10", }); }); test("ignores empty segments from double ampersands", () => { expect(parseQueryString("a=1&&b=2")).toEqual({ - "a": "1", - "b": "2", + a: "1", + b: "2", }); }); test("ignores trailing ampersands", () => { expect(parseQueryString("a=1&b=2&")).toEqual({ - "a": "1", - "b": "2", + a: "1", + b: "2", }); }); test("handles keys with empty values", () => { expect(parseQueryString("key=")).toEqual({ - "key": "", + key: "", }); }); test("handles keys without an equals sign", () => { expect(parseQueryString("flag")).toEqual({ - "flag": "", + flag: "", }); }); - diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index a444edc2f..94a6da1cb 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,14 +1,11 @@ function tally(array) { - const tally = {}; - if(!Array.isArray(array)) - throw new TypeError("Expected an array"); - if(array.length === 0) - return tally; -for (const item of array) { - tally[item] = (tally[item] || 0) + 1; - } - return tally; - + const tally = {}; + if (!Array.isArray(array)) throw new TypeError("Expected an array"); + if (array.length === 0) return tally; + for (const item of array) { + tally[item] = (tally[item] || 0) + 1; + } + return tally; } module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 33bfcda39..6b0888faf 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -24,8 +24,8 @@ const tally = require("./tally.js"); // When passed to tally // Then it should return an empty object test.todo("tally on an empty array returns an empty object"); -test("Empty array of items",()=>{ - expect(tally([])).toEqual({}); +test("Empty array of items", () => { + expect(tally([])).toEqual({}); }); // Given an array with duplicate items @@ -36,15 +36,22 @@ test("Empty array of items",()=>{ // When passed to tally // Then it should throw an error -test("Invalid input",()=>{ - expect(() => tally("not an array")).toThrow(TypeError); -}); -test("Test duplicate array",()=>{ -const duplicatesArray = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']; -const result = tally(duplicatesArray); - expect(result).toEqual({ - apple: 3, - banana: 2, - orange: 1, - }); -}); \ No newline at end of file +test("Invalid input", () => { + expect(() => tally("not an array")).toThrow(TypeError); +}); +test("Test duplicate array", () => { + const duplicatesArray = [ + "apple", + "banana", + "apple", + "orange", + "banana", + "apple", + ]; + const result = tally(duplicatesArray); + expect(result).toEqual({ + apple: 3, + banana: 2, + orange: 1, + }); +}); diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index 7a7767454..f35a148fa 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -46,4 +46,4 @@ function invert(obj) { return invertedObj; } -module.exports = invert; \ No newline at end of file +module.exports = invert; diff --git a/Sprint-2/interpret/invert.test.js b/Sprint-2/interpret/invert.test.js index ff3f2afda..5f879e88e 100644 --- a/Sprint-2/interpret/invert.test.js +++ b/Sprint-2/interpret/invert.test.js @@ -1,24 +1,24 @@ const invert = require("./invert.js"); -test('inverts a single key-value pair', () => { - const input = { a: 1 }; - expect(invert(input)).toEqual({ 1: 'a' }); - }); -test('inverts multiple key-value pairs', () => { - const input = { a: 1, b: 2, c: 3 }; - const expected = { 1: 'a', 2: 'b', 3: 'c' }; - - expect(invert(input)).toEqual(expected); - }); - test('returns empty object for empty input', () => { - expect(invert({})).toEqual({}); - }); - test('overwrites keys when duplicate values exist', () => { - const input = { a: 1, b: 1 }; - expect(invert(input)).toEqual({ 1: 'b' }); - }); - test('turns boolean and null values into string keys', () => { - const input = { a: true, b: null }; - const expected = { 'true': 'a', 'null': 'b' }; - - expect(invert(input)).toEqual(expected); - }); \ No newline at end of file +test("inverts a single key-value pair", () => { + const input = { a: 1 }; + expect(invert(input)).toEqual({ 1: "a" }); +}); +test("inverts multiple key-value pairs", () => { + const input = { a: 1, b: 2, c: 3 }; + const expected = { 1: "a", 2: "b", 3: "c" }; + + expect(invert(input)).toEqual(expected); +}); +test("returns empty object for empty input", () => { + expect(invert({})).toEqual({}); +}); +test("overwrites keys when duplicate values exist", () => { + const input = { a: 1, b: 1 }; + expect(invert(input)).toEqual({ 1: "b" }); +}); +test("turns boolean and null values into string keys", () => { + const input = { a: true, b: null }; + const expected = { true: "a", null: "b" }; + + expect(invert(input)).toEqual(expected); +});