diff --git a/Sprint-2/debug/address.js b/Sprint-2/debug/address.js index 940a6af83..7eda7d64b 100644 --- a/Sprint-2/debug/address.js +++ b/Sprint-2/debug/address.js @@ -1,4 +1,7 @@ // Predict and explain first... +//if you run this code with console.log('My house number is ${address[0]}'); it well log out 'My house number is undefined' becouse adress is an object and not an array. +// to fix this we need to remove (`My house number is ${address[0]}`); and chnage it to (adress.houseNumber) becouse we need to access the houseNumber property of the address object. +// Then it well log out 42 as expected. // This code should log out the houseNumber from the address object // but it isn't working... @@ -12,4 +15,4 @@ const address = { postcode: "XYZ 123", }; -console.log(`My house number is ${address[0]}`); +console.log(address.houseNumber); diff --git a/Sprint-2/debug/author.js b/Sprint-2/debug/author.js index 8c2125977..7ba8f4c75 100644 --- a/Sprint-2/debug/author.js +++ b/Sprint-2/debug/author.js @@ -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..2abc7c72d 100644 --- a/Sprint-2/debug/recipe.js +++ b/Sprint-2/debug/recipe.js @@ -10,6 +10,8 @@ const recipe = { ingredients: ["olive oil", "tomatoes", "salt", "pepper"], }; -console.log(`${recipe.title} serves ${recipe.serves} - ingredients: -${recipe}`); +console.log(recipe.title); +console.log(`Serves: ${recipe.serves}`); +console.log("Ingredients:"); +console.log(recipe.ingredients.join("\n")); + diff --git a/Sprint-2/implement/contains.js b/Sprint-2/implement/contains.js index cd779308a..61fdab87b 100644 --- a/Sprint-2/implement/contains.js +++ b/Sprint-2/implement/contains.js @@ -1,3 +1,13 @@ -function contains() {} +function contains(obj, prop) { + if (typeof obj !== "object" || obj === null) { + return false; + } + + if (Array.isArray(obj)) { + return false; + } + return obj.hasOwnProperty(prop); +} + module.exports = contains; diff --git a/Sprint-2/implement/contains.test.js b/Sprint-2/implement/contains.test.js index 326bdb1f2..bc3dd30f1 100644 --- a/Sprint-2/implement/contains.test.js +++ b/Sprint-2/implement/contains.test.js @@ -20,16 +20,27 @@ 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"); +test("contains an empty object returns false", function () { + 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 returns true when property exists", function () { + expect(contains({ a: 1, b: 2 }, "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 returns false when property does not exist", function () { + expect(contains({ a: 1, b: 2 }, "c")).toBe(false); +}); // Given invalid parameters like an array // When passed to contains // Then it should return false or throw an error +test("contains returns false when passed an array", function () { + expect(contains([1, 2, 3], "0")).toBe(false); +}); diff --git a/Sprint-2/implement/lookup.js b/Sprint-2/implement/lookup.js index a6746e07f..0ea659e0c 100644 --- a/Sprint-2/implement/lookup.js +++ b/Sprint-2/implement/lookup.js @@ -1,5 +1,10 @@ -function createLookup() { - // implementation here +function createLookup(countryCurrencyPairs) { + const lookup = {}; + + for (const pair of countryCurrencyPairs) { + 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..5ab551142 100644 --- a/Sprint-2/implement/lookup.test.js +++ b/Sprint-2/implement/lookup.test.js @@ -1,6 +1,9 @@ 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", function() { + 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..395e27790 100644 --- a/Sprint-2/implement/querystring.js +++ b/Sprint-2/implement/querystring.js @@ -1,12 +1,19 @@ function parseQueryString(queryString) { const queryParams = {}; + if (queryString.length === 0) { return queryParams; } + const keyValuePairs = queryString.split("&"); for (const pair of keyValuePairs) { - const [key, value] = pair.split("="); + if (!pair) continue; + + const firstEqualsIndex = pair.indexOf("="); + const key = pair.slice(0, firstEqualsIndex); + const value = pair.slice(firstEqualsIndex + 1); + queryParams[key] = value; } diff --git a/Sprint-2/implement/querystring.test.js b/Sprint-2/implement/querystring.test.js index 3e218b789..c972ab099 100644 --- a/Sprint-2/implement/querystring.test.js +++ b/Sprint-2/implement/querystring.test.js @@ -8,5 +8,23 @@ const parseQueryString = require("./querystring.js") test("parses querystring values containing =", () => { expect(parseQueryString("equation=x=y+1")).toEqual({ "equation": "x=y+1", + + }); +}); + +test("parses empty querystring", () => { + expect(parseQueryString("")).toEqual({}); +}); + +test("parses querystring with multiple key value pairs", () => { + expect(parseQueryString("name=Karim&age=20")).toEqual({ + "name": "Karim", + "age": "20" }); }); + +test("parses querystring with empty value", () => { + expect(parseQueryString("name=")).toEqual({ + "name": "" + }); +}); \ No newline at end of file diff --git a/Sprint-2/implement/tally.js b/Sprint-2/implement/tally.js index f47321812..27e3b772b 100644 --- a/Sprint-2/implement/tally.js +++ b/Sprint-2/implement/tally.js @@ -1,3 +1,13 @@ -function tally() {} +function tally(items) { + if (!Array.isArray(items)) { + throw new Error('Items must be an array'); + } + const counts = Object.create(null); + for (const item of items) { + counts[item] = (counts[item] || 0) + 1; + } + return counts; + +} module.exports = tally; diff --git a/Sprint-2/implement/tally.test.js b/Sprint-2/implement/tally.test.js index 2ceffa8dd..82062d24b 100644 --- a/Sprint-2/implement/tally.test.js +++ b/Sprint-2/implement/tally.test.js @@ -23,12 +23,21 @@ 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"); +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 counts unique items", () => { + 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 throws an error for invalid input", () => { + expect(() => tally("not an array")).toThrow("Items must be an array"); +}); + diff --git a/Sprint-2/interpret/invert.js b/Sprint-2/interpret/invert.js index bb353fb1f..f6df76b3f 100644 --- a/Sprint-2/interpret/invert.js +++ b/Sprint-2/interpret/invert.js @@ -10,7 +10,7 @@ function invert(obj) { const invertedObj = {}; for (const [key, value] of Object.entries(obj)) { - invertedObj.key = value; + invertedObj[value] = key; } return invertedObj; @@ -18,12 +18,41 @@ function invert(obj) { // a) What is the current return value when invert is called with { a : 1 } +// It returns { key: 1 } because invertedObj.key always writes the word "key" + +//---------------------------------------------------------------------------------------// + // b) What is the current return value when invert is called with { a: 1, b: 2 } +// It returns { key: 2 } because it keeps overwriting the same "key" each time + +//---------------------------------------------------------------------------------------// + // c) What is the target return value when invert is called with {a : 1, b: 2} +// It should return { "1": "a", "2": "b" } because the keys and values are swapped + +//---------------------------------------------------------------------------------------// + // c) What does Object.entries return? Why is it needed in this program? +// Object.entries turns the object into an array like [["a", 1], ["b", 2]] +// We need it so we can loop through each key and value one by one + +//---------------------------------------------------------------------------------------// + // d) Explain why the current return value is different from the target output +// Because invertedObj.key writes the word "key" literally +// instead of using the actual value as the key +// changing it to invertedObj[value] = key fixes this + +//---------------------------------------------------------------------------------------// + // e) Fix the implementation of invert (and write tests to prove it's fixed!) + +// Fixed by changing invertedObj.key = value to invertedObj[value] = key +// Tests are written in invert.test.js + + +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..752d559d7 --- /dev/null +++ b/Sprint-2/interpret/invert.test.js @@ -0,0 +1,16 @@ +const invert = require("./invert.js"); + +// Test 1 swaps the keys and values +test("invert swaps keys and values", () => { + expect(invert({ a: 1, b: 2 })).toEqual({ "1": "a", "2": "b" }); +}); + +// Test 2 empty object should return empty object +test("invert on an empty object returns an empty object", () => { + expect(invert({})).toEqual({}); +}); + +// Test 3 single key value pair +test("invert works with a single pair", () => { + expect(invert({ x: 10 })).toEqual({ "10": "x" }); +}); \ No newline at end of file