Skip to content
4 changes: 2 additions & 2 deletions Sprint-2/debug/address.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Predict and explain first...

// This code should log out the houseNumber from the address object
// This code should log out the houseNumber from the address object,
// but it isn't working...
// Fix anything that isn't working

Expand All @@ -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"]}`);
6 changes: 3 additions & 3 deletions Sprint-2/debug/author.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const author = {
age: 40,
alive: true,
};

for (const value of author) {
console.log(value);
//An object is not directly iterable, if we want to log out the values we can use a for in loop
for (const value in author) {
console.log(`${author[value]}`);
}
6 changes: 4 additions & 2 deletions Sprint-2/debug/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ const recipe = {
};

console.log(`${recipe.title} serves ${recipe.serves}
ingredients:
${recipe}`);
ingredients:`);
for (const value of Object.values(recipe.ingredients)) {
console.log(value);
}
13 changes: 11 additions & 2 deletions Sprint-2/implement/contains.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
function contains() {}

function contains(object, property) {
if (Array.isArray(object)) {
throw new Error("Expected an object, received an array");
}
const obj = Object.keys(object);
if (obj.length === 0) {
return false;
}
return obj.includes(property);
}
console.log(contains({ 1: "o", 2: "k" }, 1));
module.exports = contains;
50 changes: 48 additions & 2 deletions Sprint-2/implement/contains.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ E.g. contains({a: 1, b: 2}, 'a') // returns true
as the object contains a key of 'a'

E.g. contains({a: 1, b: 2}, 'c') // returns false
as the object doesn't contains a key of 'c'
as the object doesn't contain a key of 'c'
*/

// Acceptance criteria:
Expand All @@ -17,19 +17,65 @@ as the object doesn't contains a key of 'c'
// When passed an object and a property name
// Then it should return true if the object contains the property, false otherwise

test(
"when passed an object and a property name, should return true if the object " +
"contains the property",
() => {
const obj1 = {
name: "dami",
age: 34,
height: 5.3,
location: "London",
};
const propertyNameCheck1 = "name";
const expected1 = true;
const result1 = contains(obj1, propertyNameCheck1);
expect(result1).toBe(expected1);
}
);

// Given an empty object
// When passed to contains
// Then it should return false
test.todo("contains on empty object returns false");

test("given an empty object, should return false", () => {
const obj2 = {};
const propertyNameCheck2 = "a";
const expected2 = false;
const result2 = contains(obj2, propertyNameCheck2);
expect(result2).toBe(expected2);
});
// Given an object with properties
// When passed to contains with an existing property name
// Then it should return true
//this test requirement is covered on line 21

// Given an object with properties
// When passed to contains with a non-existent property name
// Then it should return false
test(
"when passed an object and a property name, should return false if the object " +
"does not contain the property.",
() => {
const obj3 = {
title: "Things fall apart",
year: 1958,
publisher: "pan-macmillan",
};
const propertyNameCheck3 = "location";
const expected3 = false;
const result3 = contains(obj3, propertyNameCheck3);
expect(result3).toBe(expected3);
}
);

// Given invalid parameters like an array
// When passed to contains
// Then it should return false or throw an error
test("when passed a data type other than an object, throw an error", () => {
const arr = [];
const propertyNameCheck4 = "name";
expect(() => {
contains(arr, propertyNameCheck4);
}).toThrow("Expected an object, received an array");
});
29 changes: 26 additions & 3 deletions Sprint-2/implement/lookup.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
function createLookup() {
// implementation here
}
function createLookup(arr) {
if (!Array.isArray(arr)) {
throw new Error("invalid data type entered");
}
if (arr.length === 0) {
throw new Error("country and currency code not entered");
}

const objectLookup = {};

for (const pair of arr) {
if (!Array.isArray(pair)) {
throw new Error("Each item must be an array.");
}
if (pair.length !== 2) {
throw new Error(
"Each inner array must contain exactly two elements: a key and a value"
);
}
const [country, currency] = pair;
if (country === currency) {
throw new Error("Country code and currency code cannot be the same");
}
objectLookup[country] = currency;
}
return objectLookup;
}
module.exports = createLookup;
47 changes: 45 additions & 2 deletions Sprint-2/implement/lookup.test.js
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -33,3 +31,48 @@ It should return:
'CA': 'CAD'
}
*/

test("when passed an empty array, throw an error", () => {
expect(() => {
createLookup([]);
}).toThrow("country and currency code not entered");
});

test("when given an array of arrays containing two elements, returns an object of key-value pairs", () => {
const input = [
["US", "USD"],
["CA", "CAD"],
["NG", "NIG"],
];
const expected = {
US: "USD",
CA: "CAD",
NG: "NIG",
};
const result = createLookup(input);
expect(result).toEqual(expected);
});

test.each(["hello", 123, true, null, undefined, {}])(
"throws an error when input is %p",
(input) => {
expect(() => {
createLookup(input);
}).toThrow("invalid data type entered");
}
);

test("when given an array containing more than 2 elements, throw error", () => {
const input = [["US", "USD", "U"]];
expect(() => {
createLookup(input);
}).toThrow(
"Each inner array must contain exactly two elements: a key and a value"
);
});

test("when given an array, if country code !=== currency code, throw an error", () => {
expect(() => {
createLookup([["US", "US"]]);
}).toThrow("Country code and currency code cannot be the same");
});
15 changes: 12 additions & 3 deletions Sprint-2/implement/querystring.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,19 @@ function parseQueryString(queryString) {
const keyValuePairs = queryString.split("&");

for (const pair of keyValuePairs) {
const [key, value] = pair.split("=");
queryParams[key] = value;
const indexOfFirst = pair.indexOf("=");
if (indexOfFirst === -1) {
queryParams[pair] = "";
} else {
let key = decodeURIComponent(
pair.slice(0, indexOfFirst).replaceAll("+", " ")
);
let value = decodeURIComponent(
pair.slice(indexOfFirst + 1).replaceAll("+", " ")
);
queryParams[key] = value;
}
}

return queryParams;
}

Expand Down
12 changes: 1 addition & 11 deletions Sprint-2/implement/querystring.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -36,13 +36,3 @@ test("should replace '+' by ' '", () => {
"full name": "John Doe",
});
});

// 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", () => {
expect(parseQueryString("key=value1&key=value2&key=value3&foo=bar")).toEqual({
key: ["value1", "value2", "value3"],
foo: "bar",
});
});
14 changes: 12 additions & 2 deletions Sprint-2/implement/tally.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
function tally() {}

function tally(arr) {
if (!Array.isArray(arr)) {
throw new Error('Invalid data type entered"');
}
if (arr.length === 0) {
return {};
}
return arr.reduce((acc, cur) => {
acc[cur] = (acc[cur] || 0) + 1;
return acc;
}, {});
}
module.exports = tally;
30 changes: 28 additions & 2 deletions Sprint-2/implement/tally.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,42 @@ 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("", () => {
const input = ["hey", "hi", "hello", "hi", "word", "picnic", "book"];
const expected = {
hey: 1,
hi: 2,
hello: 1,
word: 1,
picnic: 1,
book: 1,
};
const result = tally(input);
expect(result).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 input = [];
const expected = {};
const result = tally(input);
expect(result).toEqual(expected);
});

// Given an array with duplicate items
// When passed to tally
// Then it should return counts for each unique item
//Test on line 22 covers this

// Given an invalid input like a string
// When passed to tally
// Then it should throw an error
test.each([undefined, null, {}, "hello", 123, true])(
"throws when input is %p",
(input) => {
expect(() => {
tally(input).toThrow("Invalid data type entered");
});
}
);
26 changes: 21 additions & 5 deletions Sprint-2/interpret/invert.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,39 @@
// E.g. invert({x : 10, y : 20}), target output: {"10": "x", "20": "y"}

function invert(obj) {
const invertedObj = {};

for (const [key, value] of Object.entries(obj)) {
invertedObj.key = value;
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
throw new Error("Enter a valid object");
}
if (Object.keys(obj).length === 0) {
return {};
}

const invertedObj = {};
for (let [key, value] of Object.entries(obj)) {
invertedObj[value] = key;
}
return invertedObj;
}

module.exports = invert;
// a) What is the current return value when invert is called with { a : 1 }
// The current value is: { key: 1 }

// b) What is the current return value when invert is called with { a: 1, b: 2 }
// The current value is: { key: 2 }

// c) What is the target return value when invert is called with {a : 1, b: 2}
// The target return value should be:
//{ "1" : "a", "2" : "b"}

// c) What does Object.entries return? Why is it needed in this program?
//Object.entries returns an array of a key-value pair. we need object.entries
// because we cannot directly loop over an object, so by using the method
// it turns it into an array we can loop over

// d) Explain why the current return value is different from the target output
//The current return uses a dot notation with the variable 'key', when we use a
// dot notation with a variable it doesn't get the value of the variable but
// instead uses the literal word as the key. when we change it to a bracket notation
// it reads the variable and uses that for the key, we however need to swap the return around and return value = key.

// e) Fix the implementation of invert (and write tests to prove it's fixed!)
Loading
Loading