diff --git a/Sprint-1/fix/median.test.js b/Sprint-1/fix/median.test.js index 21da654d7..8d948fd46 100644 --- a/Sprint-1/fix/median.test.js +++ b/Sprint-1/fix/median.test.js @@ -47,4 +47,4 @@ describe("calculateMedian", () => { ].forEach(({ input, expected }) => it(`filters out non-numeric values and calculates the median for [${input}]`, () => expect(calculateMedian(input)).toEqual(expected)) ); -}); + }); 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..9b3e356a7 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 @@ -10,6 +11,8 @@ const recipe = { ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; +const ingredientsList=recipe.ingredients.join("\n"); console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); + ingredients:\n${ingredientsList}`); + + diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..e822b5ce9 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,29 @@ -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); + 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 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)); + }); +}); diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..25798767e 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 (const pairs of myArray) { + myObject[pairs[0]] = pairs[1]; + } + return myObject; } module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..3bad8c29c 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,33 @@ 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", "USDxx"], + ["US", "USD"], + ]) + ).toEqual({ US: "USD" }); + }); +}); /* diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..4347e6d4a 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -6,11 +6,16 @@ function parseQueryString(queryString) { const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); + 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 3e218b789..97a2a5a7e 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -5,8 +5,24 @@ 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&city=Manchester")).toEqual({ + user: "ahmad", equation: "x=y+1", city: "Manchester", + }); +}); +test("Handling URL-encoded query string",()=>{ +expect(parseQueryString("tags%5B%5D=hello%20world")).toEqual({"tags[]":"hello world"}) +}) \ No newline at end of file diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..a306879ca 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,12 @@ -function tally() {} +function tally(myArray) { + if (!Array.isArray(myArray)) throw new Error("Invalid input"); + if (myArray.length === 0) return {}; + const myObject =Object.create(null); + for (const item of myArray) { + myObject[item] = (myObject[item] || 0) + 1; + } + return myObject; +} module.exports = tally; + console.log(tally(["toString", "toString"])); \ No newline at end of file diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..ebe72898d 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 input") + }) +}) // 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 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" }); +});