From 6e3bb1f26309a79f717550dce0cf66335aa3cf3a Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Sun, 9 Nov 2025 10:37:21 +0000 Subject: [PATCH 01/14] Sumarry:update calulateMedian implementation ...checked if input is an array,otherwise return null..........Filtered out non-numeric element .......Added a check for emty numeric arrays ....Cloned the array to prevent mutation(avoid side effects)......Sorted numbers in ascending order.......Calculated the median for both even and odd length --- Sprint-1/fix/median.js | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/Sprint-1/fix/median.js b/Sprint-1/fix/median.js index b22590bc6..c58f3f369 100644 --- a/Sprint-1/fix/median.js +++ b/Sprint-1/fix/median.js @@ -6,9 +6,27 @@ // or 'list' has mixed values (the function is expected to sort only numbers). function calculateMedian(list) { - const middleIndex = Math.floor(list.length / 2); - const median = list.splice(middleIndex, 1)[0]; - return median; + // must be an array + if (!Array.isArray(list)) return null; + //filter out non-numeric values + + const numericList = list.filter( + (item) => typeof item === "number" && !isNaN(item) + ); + // return null if no valid numbers + if (numericList.length === 0) return null; + + sortedList = [...numericList]; + + sortedList.sort((a, b) => a - b); + if (sortedList.length % 2 === 0) { + let middleIndex = sortedList.length / 2; + return (sortedList[middleIndex] + sortedList[middleIndex - 1]) / 2; + } else { + const middleIndex = Math.floor(sortedList.length / 2); + const median = sortedList.splice(middleIndex, 1)[0]; + return median; + } } module.exports = calculateMedian; From 85d22f2d900b99db19bb9627655e2e8870f59c36 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Sun, 16 Nov 2025 10:24:31 +0000 Subject: [PATCH 02/14] the debug folder has been solve --- Sprint-2/debug/address.js | 4 ++-- Sprint-2/debug/author.js | 4 ++-- Sprint-2/debug/recipe.js | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..a40612037 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -1,5 +1,5 @@ // Predict and explain first... - +// address is object so you can not reach the values by index you can use address.houseNumber or address[houseNumber] // This code should log out the houseNumber from the address object // but it isn't working... // Fix anything that isn't working @@ -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}`); diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..cd5b676b4 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -1,5 +1,5 @@ // Predict and explain first... - +//objects are not iterable in JavaScript. // 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 @@ -11,6 +11,6 @@ const author = { alive: true, }; -for (const value of author) { +for (const value of Object.values(author)) { console.log(value); } diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..a0b6b3777 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -1,4 +1,5 @@ // Predict and explain first... +//${recipe} will not give us the ingredients // This program should log out the title, how many it serves and the ingredients. // Each ingredient should be logged on a new line @@ -11,5 +12,7 @@ const recipe = { }; console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); + ingredients:`); +for (const ingredient of recipe.ingredients) { + console.log(ingredient); +} From 019e2bde8cfb814820738e550171675b9565f587 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Sun, 16 Nov 2025 11:56:03 +0000 Subject: [PATCH 03/14] add comprehensive tests for contains function --- Sprint-2/implement/contains.test.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..78c5528b9 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -20,7 +20,6 @@ as the object doesn't contains a key of 'c' // Given an empty object // When passed to contains // Then it should return false -test.todo("contains on empty object returns false"); // Given an object with properties // When passed to contains with an existing property name @@ -33,3 +32,31 @@ 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 +describe("contains", () => { + it("throws an error when the first parameter is not an object",()=>{ + expect(()=> contains([],"a")).toThrow("Invalid input") + }); + + it("contains an empty object returns false", () => { + expect(contains({}, "a")).toBe(false); + }); + + [ + { input: { a: 1, b: 2 }, prop: "a", expected: true }, + { input: { a: 1, b: 2 }, prop: "b", expected: true }, + { input: { a: 1, b: 2, c: 3 }, prop: "c", expected: true }, + ].forEach(({ input, prop, expected }) => { + it(`returns true when the property exists in the given object , for object ${JSON.stringify(input)} with property "${prop}"`, () => + expect(contains(input, prop)).toBe(expected)); + }); + + + [ + { input: { a: 1, b: 2 }, prop: "c", expected: false }, + { input: { a: 1, b: 2 }, prop: "e", expected: false }, + { input: { a: 1, b: 2, c: 3 }, prop: "w", expected: false }, + ].forEach(({ input, prop, expected }) => { + it(`returns false when the property non-existent in the given object , for object ${JSON.stringify(input)} with property "${prop}"`, () => + expect(contains(input, prop)).toBe(expected)); + }); +}); From d532bac8243245fa254f703917a04d4a0c4249f7 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Tue, 18 Nov 2025 08:07:10 +0000 Subject: [PATCH 04/14] implement a contain function and ensure all test cases pass --- Sprint-2/implement/contains.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..cbed8cb63 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,11 @@ -function contains() {} +function isObject(value) { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +function contains(obj, prop) { + if(!isObject(obj)) throw new Error ("Invalid input"); + + return Object.keys(obj).includes(prop); +} module.exports = contains; From edca8349020796a5748cf12f3ebd281d2902acd3 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Fri, 28 Nov 2025 08:19:52 +0000 Subject: [PATCH 05/14] add test for lookup function --- Sprint-2/implement/lookup.test.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..c16ffbdc4 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,18 @@ const createLookup = require("./lookup.js"); - -test.todo("creates a country currency code lookup for multiple codes"); +describe("createLookup",()=>{ + it("creates an object from country/currency pairs", ()=>{ expect(createLookup([["US", "USD"],["CA", "CAD"],])).toEqual({US:"USD",CA:"CAD"}); }); + + it("returns an empty object for an empty array",()=>{ expect(createLookup([])).toEqual({}) }); + + it("returns 'Invalid input' for non-array inputs",()=>{ + expect(createLookup("CYF")).toBe("Invalid input"); + expect(createLookup(123)).toBe("Invalid input"); + expect(createLookup(null)).toBe("Invalid input"); + }); + + it("overwrites repeated keys with the last value",()=> + {expect(createLookup([["US","USD"],["US","USD"]])).toEqual({US:"USD"}) }); +} ) /* From b815ce584c136d6a27fbfa29e923294f2d5b4272 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Fri, 28 Nov 2025 20:37:09 +0000 Subject: [PATCH 06/14] Implement a lookup function and ensure all tests pass --- Sprint-2/implement/lookup.js | 9 ++++++-- Sprint-2/implement/lookup.test.js | 37 ++++++++++++++++++++++--------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..ef14def58 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,10 @@ -function createLookup() { - // implementation here +function createLookup(myArray) { + if (!Array.isArray(myArray)) return "Invalid input"; + const myObject = {}; + for (let i = 0; i < myArray.length; i++) { + myObject[myArray[i][0]] = myArray[i][1]; + } + return myObject; } module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index c16ffbdc4..3bad8c29c 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,18 +1,33 @@ const createLookup = require("./lookup.js"); -describe("createLookup",()=>{ - it("creates an object from country/currency pairs", ()=>{ expect(createLookup([["US", "USD"],["CA", "CAD"],])).toEqual({US:"USD",CA:"CAD"}); }); +describe("createLookup", () => { + it("creates an object from country/currency pairs", () => { + expect( + createLookup([ + ["US", "USD"], + ["CA", "CAD"], + ]) + ).toEqual({ US: "USD", CA: "CAD" }); + }); + + it("returns an empty object for an empty array", () => { + expect(createLookup([])).toEqual({}); + }); - it("returns an empty object for an empty array",()=>{ expect(createLookup([])).toEqual({}) }); - - it("returns 'Invalid input' for non-array inputs",()=>{ + it("returns 'Invalid input' for non-array inputs", () => { expect(createLookup("CYF")).toBe("Invalid input"); - expect(createLookup(123)).toBe("Invalid input"); - expect(createLookup(null)).toBe("Invalid input"); + expect(createLookup(123)).toBe("Invalid input"); + expect(createLookup(null)).toBe("Invalid input"); + }); + + it("overwrites repeated keys with the last value", () => { + expect( + createLookup([ + ["US", "USDxx"], + ["US", "USD"], + ]) + ).toEqual({ US: "USD" }); }); - - it("overwrites repeated keys with the last value",()=> - {expect(createLookup([["US","USD"],["US","USD"]])).toEqual({US:"USD"}) }); -} ) +}); /* From 21ea6276d339589bd8fc69e46a365c35ec496919 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Fri, 28 Nov 2025 22:18:48 +0000 Subject: [PATCH 07/14] write a test that cover the acceptance criteria --- Sprint-2/implement/tally.test.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..16e1b38d2 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -14,6 +14,21 @@ const tally = require("./tally.js"); * tally(['a', 'a', 'b', 'c']), target output: { a : 2, b: 1, c: 1 } */ +describe("tally",()=>{ + + it("returns an object containing the count for each unique item when given array of function",()=>{ + 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}) + }) + + it("returns an empty object for an empty array", () => { + expect(tally([])).toEqual({}); + }); + it("throw an error for invalid input",()=>{ + expect(()=>tally("CYF")).toThrow("Invalid error") + }) +}) // Acceptance criteria: // Given a function called tally @@ -23,7 +38,7 @@ const tally = require("./tally.js"); // 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"); + // Given an array with duplicate items // When passed to tally From 4d5eef247aa610a18660445ee99972ff5a71f9f7 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Fri, 28 Nov 2025 22:33:52 +0000 Subject: [PATCH 08/14] implent a tally function that passes the tests --- Sprint-2/implement/tally.js | 10 +++++++++- Sprint-2/implement/tally.test.js | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..9ef22db11 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,11 @@ -function tally() {} +function tally(myArray) { + if (!Array.isArray(myArray)) throw new Error("Invalid input"); + if (myArray.length === 0) return {}; + const myObject = {}; + for (const item of myArray) { + myObject[item] = (myObject[item] || 0) + 1; + } + return myObject; +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 16e1b38d2..ebe72898d 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -26,7 +26,7 @@ describe("tally",()=>{ expect(tally([])).toEqual({}); }); it("throw an error for invalid input",()=>{ - expect(()=>tally("CYF")).toThrow("Invalid error") + expect(()=>tally("CYF")).toThrow("Invalid input") }) }) // Acceptance criteria: From 6e4dabe052f12ccc55bc4e55eac1bfedd67b7e44 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Sat, 29 Nov 2025 15:15:21 +0000 Subject: [PATCH 09/14] querystring has been solved --- Sprint-2/implement/querystring.js | 3 ++- Sprint-2/implement/querystring.test.js | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..1ae96e3d3 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -6,7 +6,8 @@ function parseQueryString(queryString) { const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); + const [key,...rest] = pair.split("="); + const value=rest.join("="); queryParams[key] = value; } diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3e218b789..23d131287 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -5,8 +5,21 @@ const parseQueryString = require("./querystring.js") +test("returns empty object for empty querystring", () => { + expect(parseQueryString("")).toEqual({}); +}); test("parses querystring values containing =", () => { expect(parseQueryString("equation=x=y+1")).toEqual({ "equation": "x=y+1", }); }); +test("handles key with no value", () => { + expect(parseQueryString("flag")).toEqual({ + flag: "", + }); +}); +test("parses multiple pairs when one value contains '='", () => { + expect(parseQueryString("user=ahmad&equation=x=y+1&mode=advanced")).toEqual({ + user: "ahmad", equation: "x=y+1", mode: "advanced", + }); +}); \ No newline at end of file From 7af05ac6b0470c2683163bee90b7048d86098088 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Sun, 30 Nov 2025 14:34:43 +0000 Subject: [PATCH 10/14] asnwer invert.js questions , fix implementation and add basic tests file --- Sprint-2/interpret/invert.js | 32 ++++++++++++++++++++++++------- Sprint-2/interpret/invert.test.js | 9 +++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 Sprint-2/interpret/invert.test.js diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..5e7b229b5 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -6,24 +6,42 @@ // E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"} -function invert(obj) { - const invertedObj = {}; +// function invert(obj) { +// const invertedObj = {}; - for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; - } +// for (const [key, value] of Object.entries(obj)) { +// invertedObj.key = value; +// } - return invertedObj; -} +// return invertedObj; +// } +// console.log(invert({a:1, b:2})) // 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} +// {"1":"a", "2":"b"} // c) What does Object.entries return? Why is it needed in this program? +//It turns an object into an array of [key, value] pairs. We need it so we can access the key and value for each pair in the loop. // d) Explain why the current return value is different from the target output +// because we use dot notation which sets a property called key that mean we are not using the variable key so it will overwrites the same "key" property each time with a new value // 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; +} + +module.exports = invert; diff --git a/Sprint-2/interpret/invert.test.js b/Sprint-2/interpret/invert.test.js new file mode 100644 index 000000000..a27d49db0 --- /dev/null +++ b/Sprint-2/interpret/invert.test.js @@ -0,0 +1,9 @@ +const invert = require("./invert.js"); + +test("inverts a two-key object", () => { + expect(invert({ a: 1, b: 2 })).toEqual({ 1: "a", 2: "b" }); +}); + +test("inverts a single-key object", () => { + expect(invert({ a: 1 })).toEqual({ 1: "a" }); +}); From a6be38f86b0466a26b1706f1f04991fcdf0418cb Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Sun, 30 Nov 2025 14:43:52 +0000 Subject: [PATCH 11/14] revert Sprint 1 changes from Sprint 2 branch --- Sprint-1/fix/median.js | 28 +++------------------------- Sprint-1/fix/median.test.js | 37 +++++++++++++++++++++---------------- 2 files changed, 24 insertions(+), 41 deletions(-) diff --git a/Sprint-1/fix/median.js b/Sprint-1/fix/median.js index c58f3f369..41a5e9c43 100644 --- a/Sprint-1/fix/median.js +++ b/Sprint-1/fix/median.js @@ -1,4 +1,4 @@ -// Fix this implementation + // Start by running the tests for this function // If you're in the Sprint-1 directory, you can run `npm test -- fix` to run the tests in the fix directory @@ -6,27 +6,5 @@ // or 'list' has mixed values (the function is expected to sort only numbers). function calculateMedian(list) { - // must be an array - if (!Array.isArray(list)) return null; - //filter out non-numeric values - - const numericList = list.filter( - (item) => typeof item === "number" && !isNaN(item) - ); - // return null if no valid numbers - if (numericList.length === 0) return null; - - sortedList = [...numericList]; - - sortedList.sort((a, b) => a - b); - if (sortedList.length % 2 === 0) { - let middleIndex = sortedList.length / 2; - return (sortedList[middleIndex] + sortedList[middleIndex - 1]) / 2; - } else { - const middleIndex = Math.floor(sortedList.length / 2); - const median = sortedList.splice(middleIndex, 1)[0]; - return median; - } -} - -module.exports = calculateMedian; + const middleIndex = Math.floor(list.length / 2); + const median = list.splice(middleIndex, 1)[0]; \ No newline at end of file diff --git a/Sprint-1/fix/median.test.js b/Sprint-1/fix/median.test.js index 21da654d7..d1fb2d6fa 100644 --- a/Sprint-1/fix/median.test.js +++ b/Sprint-1/fix/median.test.js @@ -1,9 +1,3 @@ -// median.test.js - -// Someone has implemented calculateMedian but it isn't -// passing all the tests... -// Fix the implementation of calculateMedian so it passes all tests - const calculateMedian = require("./median.js"); describe("calculateMedian", () => { @@ -13,7 +7,8 @@ describe("calculateMedian", () => { { input: [1, 2, 3, 4], expected: 2.5 }, { input: [1, 2, 3, 4, 5, 6], expected: 3.5 }, ].forEach(({ input, expected }) => - it(`returns the median for [${input}]`, () => expect(calculateMedian(input)).toEqual(expected)) + it(`returns the median for [${input}]`, () => + expect(calculateMedian(input)).toEqual(expected)) ); [ @@ -21,20 +16,29 @@ describe("calculateMedian", () => { { input: [5, 1, 3, 4, 2], expected: 3 }, { input: [4, 2, 1, 3], expected: 2.5 }, { input: [6, 1, 5, 3, 2, 4], expected: 3.5 }, - { input: [110, 20, 0], expected: 20 }, - { input: [6, -2, 2, 12, 14], expected: 6 }, ].forEach(({ input, expected }) => - it(`returns the correct median for unsorted array [${input}]`, () => expect(calculateMedian(input)).toEqual(expected)) + it(`returns the correct median for unsorted array [${input}]`, () => + expect(calculateMedian(input)).toEqual(expected)) ); - it("doesn't modify the input array [3, 1, 2]", () => { - const list = [3, 1, 2]; + it("doesn't modify the input array [1, 2, 3]", () => { + const list = [1, 2, 3]; calculateMedian(list); - expect(list).toEqual([3, 1, 2]); + + expect(list).toEqual([1, 2, 3]); }); - [ 'not an array', 123, null, undefined, {}, [], ["apple", null, undefined] ].forEach(val => - it(`returns null for non-numeric array (${val})`, () => expect(calculateMedian(val)).toBe(null)) + [ + "not an array", + 123, + null, + undefined, + {}, + [], + ["apple", null, undefined], + ].forEach((val) => + it(`returns null for non-numeric array (${val})`, () => + expect(calculateMedian(val)).toBe(null)) ); [ @@ -45,6 +49,7 @@ describe("calculateMedian", () => { { input: [3, "apple", 1, null, 2, undefined, 4], expected: 2.5 }, { input: ["banana", 5, 3, "apple", 1, 4, 2], expected: 3 }, ].forEach(({ input, expected }) => - it(`filters out non-numeric values and calculates the median for [${input}]`, () => expect(calculateMedian(input)).toEqual(expected)) + it(`filters out non-numeric values and calculates the median for [${input}]`, () => + expect(calculateMedian(input)).toEqual(expected)) ); }); From 6bd3e07aedff2f81f6a5a606b6ee91d5cf11ddd2 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Sun, 30 Nov 2025 17:55:16 +0000 Subject: [PATCH 12/14] Handling URL-encoded query string and add test to make sure I handle it correctly --- Sprint-2/implement/querystring.js | 8 ++++++-- Sprint-2/implement/querystring.test.js | 9 ++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 1ae96e3d3..4347e6d4a 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -6,12 +6,16 @@ function parseQueryString(queryString) { const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key,...rest] = pair.split("="); - const value=rest.join("="); + const [keyBeforeDecoding,...rest] = pair.split("="); + const valueBeforeDecoding=rest.join("="); + const key=decodeURIComponent(keyBeforeDecoding); + const value=decodeURIComponent(valueBeforeDecoding); + queryParams[key] = value; } return queryParams; } +console.log(parseQueryString("tags%5B%5D=hello%20world ")); module.exports = parseQueryString; diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 23d131287..97a2a5a7e 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -19,7 +19,10 @@ test("handles key with no value", () => { }); }); test("parses multiple pairs when one value contains '='", () => { - expect(parseQueryString("user=ahmad&equation=x=y+1&mode=advanced")).toEqual({ - user: "ahmad", equation: "x=y+1", mode: "advanced", + expect(parseQueryString("user=ahmad&equation=x=y+1&city=Manchester")).toEqual({ + user: "ahmad", equation: "x=y+1", city: "Manchester", }); -}); \ No newline at end of file +}); +test("Handling URL-encoded query string",()=>{ +expect(parseQueryString("tags%5B%5D=hello%20world")).toEqual({"tags[]":"hello world"}) +}) \ No newline at end of file From 8875e1c9509d713edc3e6b99c8d7f629f8b5ba21 Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Sun, 30 Nov 2025 18:01:39 +0000 Subject: [PATCH 13/14] Update the contains function --- Sprint-2/implement/contains.js | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cbed8cb63..e822b5ce9 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -5,7 +5,25 @@ function isObject(value) { function contains(obj, prop) { if(!isObject(obj)) throw new Error ("Invalid input"); - return Object.keys(obj).includes(prop); + // return Object.keys(obj).includes(prop); + return Object.hasOwn(obj, prop); } + console.log( contains({ a: 1, b: 2 }, 'toString')); module.exports = contains; + + +//Does the following function call returns what you expect? + + // contains({a: 1, b: 2}, 'toString'); +// returns false for inherited properties + + +//How to determine if an object's property is its own property or an inherited property in JavaScript? +// by using hasown method. + +//Does your test correctly check whether the function can detect the given object is an array? +//Yes, the test correctly checks that the function can detect when the input is an array. +//it("throws an error when the first parameter is not an object",()=>{ + // expect(()=> contains([],"a")).toThrow("Invalid input") + // }); \ No newline at end of file From 8dfca8910c05ee023ea793feb1c5a649ff2c8dde Mon Sep 17 00:00:00 2001 From: Ahmad Hmedan Date: Sun, 30 Nov 2025 18:11:29 +0000 Subject: [PATCH 14/14] Create an empty object with no inherited properties --- Sprint-2/implement/tally.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index 9ef22db11..a306879ca 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,7 +1,7 @@ function tally(myArray) { if (!Array.isArray(myArray)) throw new Error("Invalid input"); if (myArray.length === 0) return {}; - const myObject = {}; + const myObject =Object.create(null); for (const item of myArray) { myObject[item] = (myObject[item] || 0) + 1; } @@ -9,3 +9,4 @@ function tally(myArray) { } module.exports = tally; + console.log(tally(["toString", "toString"])); \ No newline at end of file