Skip to content
Open
2 changes: 1 addition & 1 deletion Sprint-2/debug/address.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}`);
4 changes: 2 additions & 2 deletions Sprint-2/debug/author.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ const author = {
alive: true,
};

for (const value of author) {
console.log(value);
for (const key in author) {
console.log(author[key]);
}
2 changes: 1 addition & 1 deletion Sprint-2/debug/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ const recipe = {

console.log(`${recipe.title} serves ${recipe.serves}
ingredients:
${recipe}`);
${recipe.ingredients}`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The requirement is to output each ingredient on a new line.

18 changes: 17 additions & 1 deletion Sprint-2/implement/contains.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
function contains() {}
function contains(object, property) {
if (typeof object !== "object" || object === null || Array.isArray(object)) {
throw new Error("contains requires an object");
}

return Object.prototype.hasOwnProperty.call(object, property);
}

module.exports = contains;

// Implement a function called contains that checks an object contains a
// particular property

// 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'
// */
84 changes: 59 additions & 25 deletions Sprint-2/implement/contains.test.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,74 @@
const contains = require("./contains.js");

/*
Implement a function called contains that checks an object contains a
particular property

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'

E.g. contains([1, 2, 3], 'a') throws Error("contains requires an object")
as an array isn't an object
*/

// 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");
test("returns false for an empty object", () => {
const currentOutput = contains({});
const targetOutput = false;

expect(currentOutput).toEqual(targetOutput);
});

// Given an object with properties
// When passed to contains with an existing property name
// Then it should return true
test("returns true when the property exists", () => {
const currentOutput = contains({ a: 1, b: 2 }, "a");
const targetOutput = true;

expect(currentOutput).toEqual(targetOutput);
});

// Given an object with properties
// When passed to contains with a non-existent property name
// Then it should return false
test("returns false when the property does not exist", () => {
const currentOutput = contains({ a: 1, b: 2 }, "c");
const targetOutput = false;

expect(currentOutput).toEqual(targetOutput);
});

// Given an array
// When passed to contains
// Then it should throw an error
test("throws an error when passed an array", () => {
expect(() => contains([1, 2, 3], "a")).toThrow(
new Error("contains requires an object")
);
});

// Given a string
// When passed to contains
// Then it should throw an error
test("throws an error when passed a string", () => {
expect(() => contains("hello", "a")).toThrow(
new Error("contains requires an object")
);
});

// Given a number
// When passed to contains
// Then it should throw an error
test("throws an error when passed a number", () => {
expect(() => contains(42, "a")).toThrow(
new Error("contains requires an object")
);
});

// Given null
// When passed to contains
// Then it should throw an error
test("throws an error when passed null", () => {
expect(() => contains(null, "a")).toThrow(
new Error("contains requires an object")
);
});

// Given a value that isn't an object - an array, a string, a number,
// null, or no argument at all
// Given no argument
// When passed to contains
// Then it should throw Error("contains requires an object")
// (careful: typeof [] and typeof null are both "object")
// Then it should throw an error
test("throws an error when passed no argument", () => {
expect(() => contains()).toThrow(new Error("contains requires an object"));
});
23 changes: 21 additions & 2 deletions Sprint-2/implement/querystring.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
function parseQueryString(queryString) {
const queryParams = {};
if (queryString === "") {
return queryString;
}
if (queryString.length === 0) {
return queryParams;
}
Comment on lines +3 to 8

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the if statements seems unnecessary.

const keyValuePairs = queryString.split("&");

const keyValuePairs = queryString.split("&").filter((pair) => pair !== "");

for (const pair of keyValuePairs) {
const [key, value] = pair.split("=");
const indexFirstEqual = pair.indexOf("=");

let key;
let value;

if (indexFirstEqual === -1) {
key = pair;
value = "";
} else {
key = pair.slice(0, indexFirstEqual);
value = pair.slice(indexFirstEqual + 1);
}

key = decodeURIComponent(key.replace(/\+/g, " "));
value = decodeURIComponent(value.replace(/\+/g, " "));

queryParams[key] = value;
}

Expand Down
55 changes: 40 additions & 15 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 All @@ -12,17 +12,30 @@ test("should parse values containing '='", () => {
});

test("should ignore empty key-value pairs", () => {
expect(parseQueryString("key1=value1&&key2=value2&")).toEqual({
const input = "key1=value1&&key2=value2&";

const currentOutput = parseQueryString(input);

const targetOutput = {
key1: "value1",
key2: "value2",
});
};

expect(currentOutput).toEqual(targetOutput);
});

test("should accept empty string as key or as value", () => {
expect(parseQueryString("=value")).toEqual({ "": "value" });
expect(parseQueryString("key")).toEqual({ key: "" });
expect(parseQueryString("key=")).toEqual({ key: "" });
expect(parseQueryString("=")).toEqual({ "": "" });
expect(parseQueryString("=value")).toEqual({
"": "value",
});

expect(parseQueryString("key=")).toEqual({
key: "",
});

expect(parseQueryString("=")).toEqual({
"": "",
});
});

test("should decode percent-encoded characters", () => {
Expand All @@ -32,17 +45,29 @@ test("should decode percent-encoded characters", () => {
});

test("should replace '+' by ' '", () => {
expect(parseQueryString("full+name=John+Doe")).toEqual({
const input = "full+name=John+Doe";

const currentOutput = parseQueryString(input);

const expectedOutput = {
"full name": "John Doe",
});
};

expect(currentOutput).toEqual(expectedOutput);
});

// 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",
});
});
// test("should store values of a key in an array when the key has 2 or more values", () => {
// const input = "key=value1&key=value2&key=value3&foo=bar";

// const currentOutput = parseQueryString(input);

// const expectedOutput = {
// key: ["value1", "value2", "value3"],
// foo: "bar",
// };

// expect(currentOutput).toEqual(expectedOutput);
// });
32 changes: 31 additions & 1 deletion Sprint-2/implement/tally.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
function tally() {}
function tally(list) {
if (!Array.isArray(list)) {
throw new Error("tally requires an array");
}

const result = {};

for (const item of list) {
if (result[item]) {
result[item]++;
} else {
result[item] = 1;
}
}

return result;
}

module.exports = tally;

/**
* tally array
*
* In this task, you'll need to implement a function called tally
* that will take a list of items and count the frequency of each item
* in an array
*
* For example:
*
* tally(['a']), target output: { a: 1 }
* tally(['a', 'a', 'a']), target output: { a: 3 }
* tally(['a', 'a', 'b', 'c']), target output: { a : 2, b: 1, c: 1 }
*/
43 changes: 36 additions & 7 deletions Sprint-2/implement/tally.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,53 @@ const tally = require("./tally.js");
*
* tally(['a']), target output: { a: 1 }
* tally(['a', 'a', 'a']), target output: { a: 3 }
* tally(['a', 'a', 'b', 'c']), target output: { a : 2, b: 1, c: 1 }
* tally(['a', 'a', 'b', 'c']), target output: { a: 2, b: 1, c: 1 }
*/

// Acceptance criteria:

// 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("returns the count for one item", () => {
expect(tally(["a"])).toEqual({
a: 1,
});
});

test("returns the correct count for duplicate items", () => {
expect(tally(["a", "a", "a"])).toEqual({
a: 3,
});
});

test("returns the correct count for multiple unique items", () => {
expect(tally(["a", "a", "b", "c"])).toEqual({
a: 2,
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");

// Given an array with duplicate items
// When passed to tally
// Then it should return counts for each unique item
test("returns an empty object when given an empty array", () => {
expect(tally([])).toEqual({});
});

// Given an invalid input like a string, a number, or no argument at all
// When passed to tally
// Then it should throw Error("tally requires an array")

test("throws an error when given a string", () => {
expect(() => tally("hello")).toThrow(new Error("tally requires an array"));
});

test("throws an error when given a number", () => {
expect(() => tally(42)).toThrow(new Error("tally requires an array"));
});

test("throws an error when given no argument", () => {
expect(() => tally()).toThrow(new Error("tally requires an array"));
});
18 changes: 17 additions & 1 deletion Sprint-2/interpret/invert.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,36 @@ function invert(obj) {
const invertedObj = {};

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

return invertedObj;
}

module.exports = invert;

// 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?
//
//[
// ["a", 1],
//["b", 2]
//]

// d) Explain why the current return value is different from the target output
//invertedObj.key = value; means "create a property named key".
//It does not mean "use the variable key as the property name."
//invertedObj[value] = key; Square brackets allow the variable's value to become the property name.

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