diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..66f1b1b32 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -1,4 +1,6 @@ // Predict and explain first... +/* To specify house number the console.log should use. address.houseNumber. +without it, It would show as undefined */ // This code should log out the houseNumber from the address object // but it isn't working... @@ -12,4 +14,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..461bf36bc 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -3,6 +3,14 @@ // 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 +/* The code wants to log the property value and is using a for...of loop +to make sure it logs everything, however Objects aren't in order and Javascript +doesn't know what you want. Author is an Object and objects are not +iterable which is the error. To fix this change (const value of author) to +(const value of object.values(author)) to specify we want the values (not properties) +in the Object which is 'author'. Using a loop allows up to add information in author +without needing to make changes anywhere else while getting an updated log */ + const author = { firstName: "Zadie", lastName: "Smith", @@ -11,6 +19,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..b2567a6d6 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -1,4 +1,9 @@ // Predict and explain first... +/* In the console.log the {recipe} doesn't specify ingredients so it will +show up as undefined. Changing it to {recipe.ingredients} should fix that issue. +To log each ingredient on a new line you can use (.join("\n")) which +separate the code by line */ + // 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 +15,7 @@ const recipe = { ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; -console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); +console.log(`${recipe.title} + serves ${recipe.serves} + ingredients: + ${recipe.ingredients.join("\n")}`); diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..487d3ecf3 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,9 @@ -function contains() {} +function contains(object, property) { + if (Array.isArray(object)) { + throw new Error("Invalid parameter"); + } + + return property in object; +} module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..d8eb34c36 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -16,20 +16,39 @@ as the object doesn't contains a key of 'c' // 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 +test("contains a passed object should return true, false otherwise",() => { + expect(contains({a: 1, b: 2}, 2)).toEqual(false); + expect(contains({a: 1, b: 2}, 'b')).toEqual(true); +}); // Given an empty object // When passed to contains // Then it should return false -test.todo("contains on empty object returns false"); +test("contains an empty object, returns false",() => { + expect(contains({})).toEqual(false); +}); // Given an object with properties // When passed to contains with an existing property name // Then it should return true +test("contains object with properties, return true when passed with existing property name",() => { + expect(contains({name: 'alice'}, 'name')).toEqual(true); +}); + // Given an object with properties // When passed to contains with a non-existent property name // Then it should return false +test("contains a passed object with non-existent property names return false",() => { + expect(contains({a: 1, b: 2}, 'c')).toEqual(false); + }); + // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error +test("contains passed invalid parameters like an array to throw error", () => { + expect(() => contains(['horse', 'dog', 'fish'], 'fish')) + .toThrow("Invalid parameter"); +}); + diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..66ccfc568 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,11 @@ -function createLookup() { - // implementation here +function createLookup(countryCurrencyPairs) { + const lookup = {}; + + countryCurrencyPairs.forEach((pair) => { + lookup[pair[0]] = pair[1]; + }); + + return lookup; } module.exports = createLookup; diff --git a/Sprint-2/implement/lookup.test.js b/Sprint-2/implement/lookup.test.js index 547e06c5a..93a03bd4e 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"); +test("creates a country currency code lookup for multiple codes", () => { + const countryCurrencyPairs = [ + ["US", "USD"], + ["CA", "CAD"], + ["EN", "GBP"], + ]; + + expect(createLookup(countryCurrencyPairs)).toEqual({ + US: "USD", + CA: "CAD", + EN: "GBP", + }); +}); /* diff --git a/Sprint-2/implement/querystring.js b/Sprint-2/implement/querystring.js index 45ec4e5f3..ed62cf529 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -3,10 +3,20 @@ function parseQueryString(queryString) { if (queryString.length === 0) { return queryParams; } - const keyValuePairs = queryString.split("&"); + let keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); + if (!pair) continue; // continue is to skip empty strings + let [key, ...values] = pair.split("="); + + key = decodeURIComponent(key.replace(/\+/g, " ")); + const value = decodeURIComponent(values.join("=").replace(/\+/g, " ")); + + /* decodeURIComponent function decodes percent encoded characters + "replace" swaps one character with another + (/../) means the begining and end of a regex pattern (better for characters) + '\+' is an escaped '+' because it has its own function in coding */ + queryParams[key] = value; } diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 328b8df61..b9d1d20a1 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -31,13 +31,13 @@ test("should decode percent-encoded characters", () => { }); }); -test("should replace '+' by ' '", () => { + test("should replace '+' by ' '", () => { expect(parseQueryString("full+name=John+Doe")).toEqual({ "full name": "John Doe", }); }); -// Stretch exercise: Handling query strings that contain identical keys +/* Stretch exercise: Handling query strings that contain identical keys // Delete this test if you are not working on this optional case test("should store values of a key in an array when the key has 2 or more values", () => { @@ -46,3 +46,4 @@ test("should store values of a key in an array when the key has 2 or more values foo: "bar", }); }); +*/ diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..dccec7039 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,23 @@ -function tally() {} +function tally(array) { + if (!Array.isArray(array)) { + throw new Error("Input must be an array"); + } + + if (array.length === 0) { + return {}; + } + + const result = {}; + + for (const item of array) { + if (result[item]) { + result[item]++; + } else { + result[item] = 1; + } + } + + return result; +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..05b2602ec 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -19,16 +19,27 @@ 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 should return an count of each item passed through an array ", () => { + expect(tally(["a", "b", "c"])).toEqual({ a: 1, b: 1, 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("tally on an empty array returns an empty object", () => { + expect(tally([])).toEqual({}); +}); // 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 return a count for each item ", () => { + expect(tally(["a", "a", "b", "c"])).toEqual({ a: 2, b: 1, c: 1 }); +}); // Given an invalid input like a string // When passed to tally // Then it should throw an error +test("tally with a invalid string should throw an error", () => { + expect(() => tally("car")).toThrow("Input must be an array"); +}); diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..4c57409f1 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -8,22 +8,29 @@ function invert(obj) { const invertedObj = {}; - for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj[value] = key; } 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? +// Object Entries return an array of key value pairs and it's needed so the for...of loop goes through each key and value individually // d) Explain why the current return value is different from the target output +// The current return value only shows {key: 2}. It doesn't show the first key and value only the second, +// and it doesn't specify the second key. Its just defined as 'key'. It also doesn't swap the key and value around as intended // e) Fix the implementation of invert (and write tests to prove it's fixed!) + +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..37af999b3 --- /dev/null +++ b/Sprint-2/interpret/invert.test.js @@ -0,0 +1,13 @@ +const invert = require("./invert.js"); + +test("when passed invert swaps single key-value pair", () => { + expect(invert({ a: 1 })).toEqual({ "1": "a" }); +}); + +test("When invert is passed, multiple keys and values in the object should be swapped ", () => { + expect(invert({ x: 10, y: 20 })).toEqual({ "10": "x", "20": "y" }) +}); + +test("when passed invert swaps string values", () => { + expect(invert({ first: "hello",second: "world" })).toEqual({ hello: "first", world: "second" }); +}); \ No newline at end of file