diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..c8d86db83 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -4,6 +4,20 @@ // but it isn't working... // Fix anything that isn't working +// const address = { +// houseNumber: 42, +// street: "Imaginary Road", +// city: "Manchester", +// country: "England", +// postcode: "XYZ 123", +// }; +// +// console.log(`My house number is ${address[0]}`); + +// => in line 15, the object is being called, but the index, instead of a key +// is put inside the square brackets. This should result in undefined value, since +// we are treating object as an array. + const address = { houseNumber: 42, street: "Imaginary Road", @@ -12,4 +26,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..8d57e8e46 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -3,6 +3,24 @@ // 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 +// const author = { +// firstName: "Zadie", +// lastName: "Smith", +// occupation: "writer", +// age: 40, +// alive: true, +// }; +// +// for (const value of author) { +// console.log(value); +// } + +// The script will result in an error because we are trying to loop through the elements +// of the object, more precisely, through the values of the key-value pairs. +// The solution written like this would work if author would have been an array. +// For an object, we need to do an extra specification of the data we want to,b, +// loop through. + const author = { firstName: "Zadie", lastName: "Smith", @@ -11,6 +29,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..cea0615ee 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -4,6 +4,19 @@ // Each ingredient should be logged on a new line // How can you fix it? +// const recipe = { +// title: "bruschetta", +// serves: 2, +// ingredients: ["olive oil", "tomatoes", "salt", "pepper"], +// }; +// +// console.log(`${recipe.title} serves ${recipe.serves} +// ingredients: +// ${recipe}`); + +// there's an error in line 15. Instead of logging all the ingredients, line by line, the code is telling to give the whole object +// and the representation of it will be logged into the console. + const recipe = { title: "bruschetta", serves: 2, @@ -11,5 +24,8 @@ const recipe = { }; console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); +ingredients:`); + +for (const ingredient of recipe.ingredients) { + console.log(ingredient); +} diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..834b1b6f2 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,8 @@ -function contains() {} +function contains(obj, searchKey) { + if (Array.isArray(obj)) { + throw new Error("Invalid parameters"); + } + return Object.keys(obj).includes(searchKey); +} module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..0147ab9f3 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -12,24 +12,39 @@ as the object doesn't contains a key of 'c' */ // Acceptance criteria: - -// Given a contains function -// When passed an object and a property name -// Then it should return true if the object contains the property, false otherwise - -// 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 -// Then it should return true - -// Given an object with properties -// When passed to contains with a non-existent property name -// Then it should return false - -// Given invalid parameters like an array -// When passed to contains -// Then it should return false or throw an error +describe("contains function", () => { + // Given a contains function + // When passed an object and a property name + // Then it should return true if the object contains the property, false otherwise + it("given an object and a property name, returns true if the object contains the property, false otherwise", () => { + expect(contains({ first: 1, second: 2 }, "first")).toEqual(true); + expect(contains({ first: 1, second: 2 }, "third")).toEqual(false); + }); + // Given an empty object + // When passed to contains + // Then it should return false + it("contains on empty object returns false", () => { + expect(contains({}, "a")).toBeFalsy(); + }); + + // Given an object with properties + // When passed to contains with an existing property name + // Then it should return true + + it("given an object and a property name, returns true if the object contains the property", () => { + expect(contains({ a: 1, b: 2 }, "a")).toBeTruthy(); + }); + // Given an object with properties + // When passed to contains with a non-existent property name + // Then it should return false + it("given an object and a property name, returns false if the object does not contain the property", () => { + expect(contains({ a: 1, b: 2 }, "c")).toBeFalsy(); + }); + // Given invalid parameters like an array + // When passed to contains + // Then it should return false or throw an error + it("given and invalid parameters, returns false or throws an error", () => { + expect(() => contains([1, 2, 3], 3)).toThrow("Invalid parameters"); + expect(contains({ a: 100, b: 200 }, [100, 200])).toBeFalsy(); + }); +}); diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..f06854541 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,10 @@ -function createLookup() { - // implementation here +function createLookup(pairs) { + const countryCurrencyObj = {}; + + pairs.forEach(([countryCode, currencyCode]) => { + countryCurrencyObj[countryCode] = currencyCode; + }); + return countryCurrencyObj; } module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..09f969c25 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,7 +1,5 @@ const createLookup = require("./lookup.js"); -test.todo("creates a country currency code lookup for multiple codes"); - /* Create a lookup object of key value pairs from an array of code pairs @@ -33,3 +31,25 @@ It should return: 'CA': 'CAD' } */ + +test("creates a country currency code lookup for single code pair", () => { + expect(createLookup([["US", "USD"]])).toEqual({ + US: "USD", + }); + + expect(createLookup([["CA", "CAD"]])).toEqual({ + CA: "CAD", + }); +}); + +test("creates a country currency code lookup for multiple codes", () => { + expect( + createLookup([ + ["US", "USD"], + ["CA", "CAD"], + ]) + ).toEqual({ + US: "USD", + CA: "CAD", + }); +}); diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..86a731a29 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -6,11 +6,35 @@ function parseQueryString(queryString) { const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); - queryParams[key] = value; + if (!pair) continue; + const equalIndex = pair.indexOf("="); + if (equalIndex === -1) { + const key = pair; + queryParams[decodeURIComponent(key) ?? ""] = ""; + continue; + } + + let key = pair.substring(0, equalIndex).replace("+", " "); + let value = pair.substring(equalIndex + 1).replace("+", " "); + + key = decodeURIComponent(key); + value = decodeURIComponent(value); + if (queryParams[key] !== undefined) { + if (Array.isArray(queryParams[key])) { + queryParams[key].push(value); + } else { + queryParams[key] = [queryParams[key], value]; + } + } else { + queryParams[key] = value; + } } return queryParams; } +console.log(parseQueryString("=value")); +console.log(parseQueryString("key")); +console.log(parseQueryString("key=")); +console.log(parseQueryString("=")); module.exports = parseQueryString; 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({ diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..f0da8bc2e 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,16 @@ -function tally() {} +function tally(items) { + if (!Array.isArray(items)) { + throw new Error("Input must be an array"); + } + const counts = {}; + for (const item of items) { + if (counts[item]) { + counts[item]++; + } else { + counts[item] = 1; + } + } + return counts; +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..61bc2ce6d 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -19,16 +19,33 @@ const tally = require("./tally.js"); // Given a function called tally // When passed an array of items // Then it should return an object containing the count for each unique item +test("tally on an array returns an object containing the count for each unique item", () => { + const items = ["a", "b", "c"]; + const expected = { a: 1, b: 1, c: 1 }; + expect(tally(items)).toEqual(expected); +}); // Given an empty array // When passed to tally // Then it should return an empty object -test.todo("tally on an empty array returns an empty object"); +test("tally on an empty array returns an empty object", () => { + const items = []; + const expected = {}; + expect(tally(items)).toEqual(expected); +}); // Given an array with duplicate items // When passed to tally // Then it should return counts for each unique item +test("tally on an array with duplicate items returns counts for each unique item", () => { + const items = ["a", "a", "a"]; + const expected = { a: 3 }; + expect(tally(items)).toEqual(expected); +}); // Given an invalid input like a string // When passed to tally // Then it should throw an error +test("tally on an invalid input like a string throws an error", () => { + expect(() => tally("a")).toThrow("Input must be an array"); +}); diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..3f1ca0dd4 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -6,24 +6,38 @@ // 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; +// } // 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 returns an array of key-value pairs. +// It's needed because it allows us to iterate over the keys and values of the object. // d) Explain why the current return value is different from the target output +// In line 9 we are assigning the value to the key "key" instead of the value of the key variable. // 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..433c9a72a --- /dev/null +++ b/Sprint-2/interpret/invert.test.js @@ -0,0 +1,24 @@ +const invert = require("./invert"); + +// Let's define how invert should work +// Given an object +// When invert is passed this object +// Then it should swap the keys and values in the object + +// E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"} + +describe("invert", () => { + it("should swap the keys and values in an object", () => { + expect(invert({ a: 1, b: 2 })).toEqual({ 1: "a", 2: "b" }); + expect(invert({ a: 1 })).toEqual({ 1: "a" }); + expect(invert({ x: 10, y: 20 })).toEqual({ 10: "x", 20: "y" }); + expect(invert({ name: "Tom", age: 30 })).toEqual({ + Tom: "name", + 30: "age", + }); + }); + + it("should handle empty objects", () => { + expect(invert({})).toEqual({}); + }); +});