From caa5bb021f119ae5bf412a1fc02803dc37fccf62 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Mon, 9 Nov 2026 15:25:07 +0000 Subject: [PATCH 01/22] Fix address object property access to log house number correctly --- Sprint-2/debug/address.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..55a11873d 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -1,5 +1,9 @@ // Predict and explain first... +// I predict that the code will give undefined result, because objects access properties using the key names not indexes +// And the square bracket will generate a reference error because the houseNumber will be treated +// as a variable name not property key + // This code should log out the houseNumber from the address object // but it isn't working... // Fix anything that isn't working @@ -12,4 +16,4 @@ const address = { postcode: "XYZ 123", }; -console.log(`My house number is ${address[0]}`); +console.log(`My house number is ${address.houseNumber}`); From e2397d8cbe6d665c96cc6ce2ec1c8954cdf630e9 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Mon, 9 Nov 2026 15:27:36 +0000 Subject: [PATCH 02/22] Fix for loop to correctly iterate over object properties in author.js --- Sprint-2/debug/author.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..46072c262 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -1,5 +1,8 @@ // Predict and explain first... +// I predict the code will generate error, because it has used for of loop which is for looping array, +// instead of for in loop that is for looping objects + // 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 +14,6 @@ const author = { alive: true, }; -for (const value of author) { +for (const value in author) { console.log(value); } From df238c960edc8a9d8da1c0a78ac24d31aee739db Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Mon, 9 Nov 2026 15:40:24 +0000 Subject: [PATCH 03/22] Fix recipe.js to correctly log ingredients and improve comments --- Sprint-2/debug/recipe.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 6cbdd22cd..07b11eeee 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -1,5 +1,8 @@ // Predict and explain first... +// I predict the code will not print the ingredients, because the array is not referenced, +// and it does not have loop to go through each element of the array + // 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? @@ -10,6 +13,8 @@ const recipe = { ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; -console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); +for (const cookingIngredients of recipe.ingredients) { + console.log(cookingIngredients); +} + +console.log(`${recipe.title} serves ${recipe.serves}`); From 345b355ab69ee42227365b99d13c13f7ce271128 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Tue, 10 Nov 2026 15:06:18 +0000 Subject: [PATCH 04/22] Add tests for contains function to validate object property checks and error handling --- Sprint-2/implement/contains.test.js | 37 ++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 719272787..72864b82c 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -1,4 +1,5 @@ const contains = require("./contains.js"); +/// /* Implement a function called contains that checks an object contains a @@ -23,18 +24,52 @@ as an array isn't an object // 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 name on object returns true", () => { + expect(contains({ a: 1, b: 2, c: 3 }, "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 name not on object returns false", () => { + expect(contains({ a: 1, b: 2, c: 3 }, "e")).toBe(false); +}); // Given a value that isn't an object - an array, a string, a number, // null, or no argument at all // When passed to contains // Then it should throw Error("contains requires an object") // (careful: typeof [] and typeof null are both "object") + +describe("when the argument is not an object", () => { + test("throws an error when receiving a string", () => { + expect(() => { + contains("Hello World", "e"); + }).toThrow("contains requires an object"); + }); + + test("throws an error when receiving a number", () => { + expect(() => { + contains(1234, "a"); + }).toThrow("contains requires an object"); + }); + + test("throws an error when receiving an array", () => { + expect(() => { + contains(["a", "b", "c"], "a"); + }).toThrow("contains requires an object"); + }); + + test("throws an error when receiving null", () => { + expect(() => { + contains(null, "a"); + }).toThrow("contains requires an object"); + }); +}); From 2ae731203fb2cdb9f268c7ab6a1dc0a82fd3b38b Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Tue, 10 Nov 2026 15:06:25 +0000 Subject: [PATCH 05/22] Implement contains function to check for property existence in an object --- 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..e2c7fe4d6 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,12 @@ -function contains() {} +function contains(object, name) { + if (typeof object !== "object" || Array.isArray(object) || object === null) { + throw new Error("contains requires an object"); + } + + if (name in object) { + return true; + } + return false; +} module.exports = contains; From fd4f6f57111ce280ae773342770d9f289f158ad9 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Tue, 10 Nov 2026 15:06:44 +0000 Subject: [PATCH 06/22] Add jsconfig.json and update package.json for Jest type definitions --- Sprint-2/jsconfig.json | 6 + Sprint-2/package-lock.json | 405 +++++++++++++++++++++++++++---------- Sprint-2/package.json | 1 + 3 files changed, 307 insertions(+), 105 deletions(-) create mode 100644 Sprint-2/jsconfig.json diff --git a/Sprint-2/jsconfig.json b/Sprint-2/jsconfig.json new file mode 100644 index 000000000..f1ce55706 --- /dev/null +++ b/Sprint-2/jsconfig.json @@ -0,0 +1,6 @@ +{ + "compilerOptions": { + "types": ["jest"] + }, + "exclude": ["node_modules"] +} diff --git a/Sprint-2/package-lock.json b/Sprint-2/package-lock.json index 9b4c725d6..933a0f14c 100644 --- a/Sprint-2/package-lock.json +++ b/Sprint-2/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "devDependencies": { + "@types/jest": "^30.0.0", "jest": "^29.7.0" } }, @@ -27,14 +28,15 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", - "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/highlight": "^7.25.7", - "picocolors": "^1.0.0" + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" @@ -182,9 +184,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", - "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -215,100 +217,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", - "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { "version": "7.25.8", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", @@ -713,6 +621,16 @@ } } }, + "node_modules/@jest/diff-sequences": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.5.0.tgz", + "integrity": "sha512-OsqBjHXCn8cadasoAZBP6nWYvMsRhpMzGXTpxJ5aO04NlbdhIz+FVe3q49l0AwVhsz/cEmIpBes6gAFl1/dWQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", @@ -774,6 +692,16 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/get-type": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.5.0.tgz", + "integrity": "sha512-9/2VUPitAjmBzbvDvqrxmvB7BzWsBW0WmkkojX1ODuxX1NLGxx9gfaZpHB0z8DtJ9uhGNmZG/VXBhf8uO0OV8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@jest/globals": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", @@ -790,6 +718,46 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/pattern": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.5.0.tgz", + "integrity": "sha512-HdNQYSdRTEBNrginaqzQtTjG0HRMfrra/z6Ok7uL3S87vSlarIVohEsJsSj5edu3MiHoHjAkvPROz5ZjoKai+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-regex-util": "30.5.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/pattern/node_modules/jest-regex-util": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.5.0.tgz", + "integrity": "sha512-Mg0WK7A6xRHLSA1udJ8y9f3lM0uUhFTBnLKzwPmqB9AylvpleJ6BLemR8K9dK27DY+cesDryoA7yLZCAHsPG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@jest/react-is-18": { + "name": "react-is", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jest/react-is-19": { + "name": "react-is", + "version": "19.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.3.1.tgz", + "integrity": "sha512-RRieF6IyxQBkcK6pP8xOHprLTPW6QjRkbGdImtqNme+/hYVwCZkLQLdlZGOhUqXwkS9IEynaGvPJtv6XB/cz0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@jest/reporters": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", @@ -1101,6 +1069,233 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/jest": { + "version": "30.0.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz", + "integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^30.0.0", + "pretty-format": "^30.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/expect-utils": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.5.2.tgz", + "integrity": "sha512-d/HOLSrJUlBIl6n3LzOa7cjW3xdePm5H5gQw2lixZ/0h157l9sw3mLblzFqnPcTbhDzhRQdBOX3A3KcG73nm5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.5.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/schemas": { + "version": "30.5.0", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.5.0.tgz", + "integrity": "sha512-/hunigyNpc4RCjC0VaW3f5RCUZVM2+WQ65qP7z083Gmvac7or2LI50XVNOtE4YPgBpV0yxYiAgorAPGniCoJmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.34.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@jest/types": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.5.1.tgz", + "integrity": "sha512-LvVYn83nnXPl+Rg98nvcFgjx6nRMTArhSn6RAX/w3ELn54S8A42TYZvsCMdGUqTM8S0wyXbtlQdU6Hi6dykj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/pattern": "30.5.0", + "@jest/schemas": "30.5.0", + "@types/istanbul-lib-coverage": "^2.0.6", + "@types/istanbul-reports": "^3.0.4", + "@types/node": "*", + "@types/yargs": "^17.0.33", + "chalk": "^4.1.2" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/@sinclair/typebox": { + "version": "0.34.52", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.52.tgz", + "integrity": "sha512-XiMQh7qqVlxZzcVD+kkGMNGMzcTrDMLWI7S4x7z1MkCkbDPrekpZXEUK0eZqZFMuHQg2a2DZOcDIh9o5v3Gonw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/ci-info": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.5.0.tgz", + "integrity": "sha512-d1uM8k5UZEyPza1n/MG3ko8nKupKN0KJpFsipgPcgaCCvV+IqIfJ+NzTjetlLM+UcXZx3+cLrNr76+eAO7G1Mw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@types/jest/node_modules/expect": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-30.5.2.tgz", + "integrity": "sha512-0LNuMvs8/5mRYhnCR4k+lGV7fqPMs6Bnksda4S3zsCUmdxBpAn4zU4NNzXdq1pMKe/H4W5t/zVIDSJ/H3e0vDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.5.2", + "@jest/get-type": "30.5.0", + "jest-matcher-utils": "30.5.2", + "jest-message-util": "30.5.1", + "jest-mock": "30.5.2", + "jest-util": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-diff": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.5.2.tgz", + "integrity": "sha512-rBtHnI6BWTiWj3lM7fOLVfChx7R9B0u9VV3PRHawKs79x6ZjW1QoSrKenaigNGWlvhtoi2BqvDbABDie+Os3xQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/diff-sequences": "30.5.0", + "@jest/get-type": "30.5.0", + "chalk": "^4.1.2", + "pretty-format": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-matcher-utils": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.5.2.tgz", + "integrity": "sha512-lFkB365PTIHOhPzwrb9T6gvlDnPpOZ7/c3ewOKKB7bzztqjVrtlyRL2MkyfJXpyY2u2SKw001JKrTx14fBUFcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/get-type": "30.5.0", + "chalk": "^4.1.2", + "jest-diff": "30.5.2", + "pretty-format": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-message-util": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.5.1.tgz", + "integrity": "sha512-UdQlLdd9wL/Ys7xRErckqwD6wPlSZYueosSWuHc1r2ztGLwlgPvtSJq2+BPEgaEY13WLvfFbmhTj8pba0Sd1jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@jest/types": "30.5.1", + "@types/stack-utils": "^2.0.3", + "chalk": "^4.1.2", + "graceful-fs": "^4.2.11", + "jest-util": "30.5.1", + "picomatch": "^4.0.3", + "pretty-format": "30.5.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.6" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-mock": { + "version": "30.5.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.5.2.tgz", + "integrity": "sha512-KTHb37Fhj8xY8qPFvTFaFJHcdsumQp+ExsUlgoX232Agmc706gagBs53+CYvulV7MVQo9AgXOUxsqzzVBoJlrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "30.5.2", + "@jest/types": "30.5.1", + "@types/node": "*", + "jest-util": "30.5.1" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/jest-util": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.5.1.tgz", + "integrity": "sha512-yKuxmNy2rSbTXw+3SIPanJo+nV4/BS1p26v44IYBFMsswSQySfMMcPHErnOncda7i9HEz0q605rIhSTBVgrZTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "30.5.1", + "@types/node": "*", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "graceful-fs": "^4.2.11", + "picomatch": "^4.0.3" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, + "node_modules/@types/jest/node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "30.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.5.1.tgz", + "integrity": "sha512-byhRAPguVKMQIj4kjJwJ5lAskVhfuiSdiYl/aLTWpgkGEmic2jYhJh1yE9ih8Ox44Xg9ccCT11/S6QrzSJuNrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/react-is-18": "npm:react-is@^18.3.1", + "@jest/react-is-19": "npm:react-is@^19.2.5", + "@jest/schemas": "30.5.0", + "ansi-styles": "^5.2.0" + }, + "engines": { + "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" + } + }, "node_modules/@types/node": { "version": "22.7.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", @@ -3153,9 +3348,9 @@ "license": "MIT" }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, diff --git a/Sprint-2/package.json b/Sprint-2/package.json index 80c16780f..9ed6915b3 100644 --- a/Sprint-2/package.json +++ b/Sprint-2/package.json @@ -10,6 +10,7 @@ "author": "", "license": "ISC", "devDependencies": { + "@types/jest": "^30.0.0", "jest": "^29.7.0" } } From a5c908d9de873d6951b1f15905b7bfd2dbce2d7c Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Tue, 10 Nov 2026 15:10:53 +0000 Subject: [PATCH 07/22] Remove unnecessary TypeScript reference from contains.test.js --- Sprint-2/implement/contains.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 72864b82c..6fdaa9caf 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -1,5 +1,4 @@ const contains = require("./contains.js"); -/// /* Implement a function called contains that checks an object contains a From 3a2f2132ca339361af1cc9b2601e258cdbba9b71 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Tue, 10 Nov 2026 16:02:48 +0000 Subject: [PATCH 08/22] Refactor tests in lookup.test.js to validate createLookup function behavior and error handling --- Sprint-2/implement/lookup.test.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..d0b561575 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,28 @@ const createLookup = require("./lookup.js"); -test.todo("creates a country currency code lookup for multiple codes"); +test("returns an object of country currency pair", () => { + expect( + createLookup([ + ["US", "USD"], + ["CA", "CAD"], + ]) + ).toEqual({ US: "USD", CA: "CAD" }); +}); + +test("Throws an error if the input is not array of an array", () => { + expect(() => { + createLookup(["usd", "cad", "euro"]); + }).toThrow("createLookup requires array of an array"); +}); + +test("Throws an error if the input is not array of an array with string elements", () => { + expect(() => { + createLookup([ + [23, "USD"], + ["CA", 67], + ]); + }).toThrow("createLookup requires array of an array"); +}); /* From 4563f09c5a1948c84ed80aba1bbbe4e38bc18645 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Tue, 10 Nov 2026 16:02:59 +0000 Subject: [PATCH 09/22] Implement createLookup function to transform country-currency pairs into an object --- Sprint-2/implement/lookup.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..47849dfdb 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,25 @@ -function createLookup() { - // implementation here -} +function createLookup(countryCurrencyPairs) { + if ( + !Array.isArray(countryCurrencyPairs) || + !countryCurrencyPairs.every( + (item) => + Array.isArray(item) && + item.every((element) => typeof element === "string") + ) + ) { + throw new Error("createLookup requires array of an array"); + } + let currencyObject = {}; + for (const arrayCurrency of countryCurrencyPairs) { + currencyObject[arrayCurrency[0]] = arrayCurrency[1]; + } + return currencyObject; +} +/*console.log( + createLookup([ + ["US", "USD"], + ["CA", "CAD"], + ]) +);*/ module.exports = createLookup; From 64405b5901574efde302319fba0883bb50a63f60 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Wed, 11 Nov 2026 13:21:18 +0000 Subject: [PATCH 10/22] Implement tally function to count occurrences of items in an array --- Sprint-2/implement/tally.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..116da3a24 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,16 @@ -function tally() {} +function tally(array) { + if (!Array.isArray(array)) { + throw new Error("tally requires an array"); + } + objectItem = {}; + for (const item of array) { + if (objectItem[item]) { + objectItem[item] = objectItem[item] + 1; + } else { + objectItem[item] = 1; + } + } + return objectItem; +} module.exports = tally; From c4e3c368e3485f97dd296c08e62bf9035f53123d Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Wed, 11 Nov 2026 13:21:27 +0000 Subject: [PATCH 11/22] Refactor tally tests to improve clarity and coverage --- 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 ca763c296..cea341aa8 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("returns count for each unique item in the array", () => { + expect(tally(["a", "b", "b", "a", "c"])).toEqual({ a: 2, b: 2, 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("returns empty object for given 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("returns count for each unique item in the array", () => { + expect(tally(["a", "b", 3, "a", "c"])).toEqual({ a: 2, b: 1, 3: 1, c: 1 }); +}); // Given an invalid input like a string, a number, or no argument at all // When passed to tally // Then it should throw Error("tally requires an array") +test("throws an error when not given an array", () => { + expect(() => { + tally("apple"); + }).toThrow("tally requires an array"); +}); From 6a4db13af16e3ad204470972eedd41200b5a67c0 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Wed, 11 Nov 2026 16:21:38 +0000 Subject: [PATCH 12/22] Refactor parseQueryString function to improve query parameter handling and readability --- Sprint-2/implement/querystring.js | 33 +++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..08e36c122 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -3,11 +3,40 @@ function parseQueryString(queryString) { if (queryString.length === 0) { return queryParams; } + if (queryString.includes("%")) { + queryString = decodeURIComponent(queryString); + } + if (queryString.includes("+")) { + queryString = queryString.replaceAll("+", " "); + } + //const arrayValue = []; + let key = ""; + let value = ""; + const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); - queryParams[key] = value; + if (pair.length === 0) { + continue; + } + const separatorIndex = pair.indexOf("="); + if (separatorIndex === 0) { + value = pair.slice(separatorIndex + 1); + } else if (separatorIndex === pair.length - 1) { + key = pair.slice(0, separatorIndex); + } else if (!pair.includes("=")) { + key = pair; + } else { + key = pair.slice(0, separatorIndex); + value = pair.slice(separatorIndex + 1); + } + if (!queryParams[key]) { + queryParams[key] = value; + } else if (Array.isArray(queryParams[key])) { + queryParams[key].push(value); + } else { + queryParams[key] = [queryParams[key], value]; + } } return queryParams; From 7aae0360852edbe6963d26e035c7633f515dc2e5 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Wed, 11 Nov 2026 16:21:45 +0000 Subject: [PATCH 13/22] Fix syntax error in querystring.test.js by adding missing semicolon --- 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 328b8df61..e9e0e9abd 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -3,7 +3,7 @@ // Below are some test cases the implementation doesn't handle well. // Fix the implementation for these tests, 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("should parse values containing '='", () => { expect(parseQueryString("equation=a=b-2")).toEqual({ From dc40ffc7062695ad5c111c31b3f4eb36c96fa17f Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Wed, 11 Nov 2026 17:09:16 +0000 Subject: [PATCH 14/22] Fix invert function implementation to correctly swap keys and values in the object --- Sprint-2/interpret/invert.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..1216f000a 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -10,20 +10,35 @@ function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj[value] = key; } return invertedObj; } +//console.log(invert({ f: 34, h: 45, j: "rf" })); +module.exports = invert; // 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: 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 return the key and value of an object, and in this program we used it to go through each key value pair and to put them in an array + // d) Explain why the current return value is different from the target output +// ===> first it used the dot notation instead of square bracket which is accessing the property using a literal name +// ===> second it is not inverted it still uses key value instead of value key so that it returns the inverted one + // e) Fix the implementation of invert (and write tests to prove it's fixed!) + +// ===> I have fixed the program From 2ebc9d0f79d063542d76bfb351c68d886a1d1e1b Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Wed, 11 Nov 2026 17:09:22 +0000 Subject: [PATCH 15/22] Add tests for invert function to verify key-value inversion --- Sprint-2/interpret/invert.test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) 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..ea41b0a4c --- /dev/null +++ b/Sprint-2/interpret/invert.test.js @@ -0,0 +1,10 @@ +const invert = require("./invert.js"); + +test("checking inversion ", () => { + expect(invert({ x: 10, y: 20 })).toEqual({ 10: "x", 20: "y" }); + expect(invert({ f: 34, h: 45, j: "rf" })).toEqual({ + 34: "f", + 45: "h", + rf: "j", + }); +}); From 69d91eef4d6c71f3fb1d70e34f35076b8990afed Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Thu, 12 Nov 2026 13:22:45 +0000 Subject: [PATCH 16/22] Fix author.js to correctly log property values instead of keys --- Sprint-2/debug/author.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 46072c262..22a61dbf3 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -6,6 +6,9 @@ // 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 +// when we run it, it logs out the property key instead of its value because for...in iterates over the property keys (names), not the property values. +// we need to use square brackets [] to access the value associated with that property name + const author = { firstName: "Zadie", lastName: "Smith", @@ -15,5 +18,5 @@ const author = { }; for (const value in author) { - console.log(value); + console.log(author[value]); } From 7ee71050f4d75eaef4a6da96e3b4adef7c8ed7eb Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Thu, 12 Nov 2026 13:48:04 +0000 Subject: [PATCH 17/22] Refactor contains function to use Object.hasOwn for property checking --- Sprint-2/implement/contains.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index e2c7fe4d6..0a7a42895 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -2,11 +2,8 @@ function contains(object, name) { if (typeof object !== "object" || Array.isArray(object) || object === null) { throw new Error("contains requires an object"); } - - if (name in object) { - return true; - } - return false; + // the in Checks own and inherited properties so that is why it returned true when the name is 'toString' + return Object.hasOwn(object, name); } - +//console.log(contains({ a: 1 }, "toString")); module.exports = contains; From 30f84035d3e12ae30cfd45f6a6eaf9fc2d61b9ac Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Thu, 12 Nov 2026 14:11:38 +0000 Subject: [PATCH 18/22] Refactor recipe.js to log ingredients in a single console statement --- Sprint-2/debug/recipe.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Sprint-2/debug/recipe.js b/Sprint-2/debug/recipe.js index 07b11eeee..87f46278c 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -12,9 +12,6 @@ const recipe = { serves: 2, ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; - -for (const cookingIngredients of recipe.ingredients) { - console.log(cookingIngredients); -} - -console.log(`${recipe.title} serves ${recipe.serves}`); +console.log( + recipe.title + " serves " + recipe.serves + recipe.ingredients.join("\n") +); From 1d3281e351545f3d14b6389ece3e041f88fe9b4d Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Thu, 12 Nov 2026 15:35:19 +0000 Subject: [PATCH 19/22] Refactor createLookup function to improve input validation and error handling --- Sprint-2/implement/lookup.js | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index 47849dfdb..3d1f21bfa 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,13 +1,15 @@ function createLookup(countryCurrencyPairs) { - if ( - !Array.isArray(countryCurrencyPairs) || - !countryCurrencyPairs.every( - (item) => - Array.isArray(item) && - item.every((element) => typeof element === "string") - ) - ) { - throw new Error("createLookup requires array of an array"); + if (!Array.isArray(countryCurrencyPairs)) { + throw new Error("createLookup requires an array"); + } + for (const keyVlauePairs of countryCurrencyPairs) { + if (!Array.isArray(keyVlauePairs)) { + throw new Error("createLookup requires an array of key value pair"); + } else if (keyVlauePairs.length !== 2) { + throw new Error("createLookup requires key value pair"); + } else if (keyVlauePairs.some((element) => typeof element !== "string")) { + throw new Error("createLookup requires a string of key value pair"); + } } let currencyObject = {}; @@ -16,10 +18,5 @@ function createLookup(countryCurrencyPairs) { } return currencyObject; } -/*console.log( - createLookup([ - ["US", "USD"], - ["CA", "CAD"], - ]) -);*/ + module.exports = createLookup; From 32d131409b43cf3e18d67cd1a17b8558f3f0f62d Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Thu, 12 Nov 2026 15:35:25 +0000 Subject: [PATCH 20/22] Refactor tests in lookup.test.js for clarity and accuracy in error messages --- Sprint-2/implement/lookup.test.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index d0b561575..4798967f6 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -9,19 +9,28 @@ test("returns an object of country currency pair", () => { ).toEqual({ US: "USD", CA: "CAD" }); }); -test("Throws an error if the input is not array of an array", () => { +test("Throws an error when there are more strings than key value pairs", () => { + expect(() => { + createLookup([ + ["US", "USD", "EURO"], + ["CA", "CAD"], + ]); + }).toThrow("createLookup requires key value pair"); +}); + +test("Throws an error if the input is not an array", () => { expect(() => { createLookup(["usd", "cad", "euro"]); - }).toThrow("createLookup requires array of an array"); + }).toThrow("createLookup requires an array"); }); -test("Throws an error if the input is not array of an array with string elements", () => { +test("Throws an error if an array has elements that are not string key value pairs", () => { expect(() => { createLookup([ [23, "USD"], ["CA", 67], ]); - }).toThrow("createLookup requires array of an array"); + }).toThrow("createLookup requires a string of key value pair"); }); /* From fba5a724744e37ea45f603b840071f4c8f42fb36 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Thu, 12 Nov 2026 15:42:40 +0000 Subject: [PATCH 21/22] Update test descriptions in tally.test.js for clarity and accuracy --- Sprint-2/implement/tally.test.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index cea341aa8..6a982f377 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -33,7 +33,7 @@ test("returns empty object for given empty array", () => { // Given an array with duplicate items // When passed to tally // Then it should return counts for each unique item -test("returns count for each unique item in the array", () => { +test("returns count for each unique item with different type in the array", () => { expect(tally(["a", "b", 3, "a", "c"])).toEqual({ a: 2, b: 1, 3: 1, c: 1 }); }); @@ -44,4 +44,12 @@ test("throws an error when not given an array", () => { expect(() => { tally("apple"); }).toThrow("tally requires an array"); + + expect(() => { + tally(234); + }).toThrow("tally requires an array"); + + expect(() => { + tally(); + }).toThrow("tally requires an array"); }); From fae81859573692fc87ea50cfacede22668f1a2f4 Mon Sep 17 00:00:00 2001 From: Aklilu Mihtsun Date: Thu, 12 Nov 2026 15:43:00 +0000 Subject: [PATCH 22/22] Fix variable declaration in tally function to use const for objectItem --- 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 116da3a24..189e186f7 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -2,7 +2,7 @@ function tally(array) { if (!Array.isArray(array)) { throw new Error("tally requires an array"); } - objectItem = {}; + const objectItem = {}; for (const item of array) { if (objectItem[item]) { objectItem[item] = objectItem[item] + 1;