Skip to content

Commit 608badb

Browse files
committed
feat(sprint-2): Restore Sprint 2 work into fresh subtree
1 parent 2c5d12f commit 608badb

File tree

12 files changed

+283
-26
lines changed

12 files changed

+283
-26
lines changed

Sprint-2/debug/address.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
// Predict and explain first...
22

3+
// This outputs undefined because address[0] tries to access an object like an array.
4+
// Objects use property names, not numeric indices.
5+
// References:
6+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors
7+
38
// This code should log out the houseNumber from the address object
49
// but it isn't working...
510
// Fix anything that isn't working
@@ -12,4 +17,5 @@ const address = {
1217
postcode: "XYZ 123",
1318
};
1419

15-
console.log(`My house number is ${address[0]}`);
20+
// Fix: Dot notation accesses the property correctly
21+
console.log(`My house number is ${address.houseNumber}`);

Sprint-2/debug/author.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
// Predict and explain first...
22

3+
// This throws a TypeError because plain objects cannot be used with for...of directly.
4+
// References:
5+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
6+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values
7+
38
// This program attempts to log out all the property values in the object.
49
// But it isn't working. Explain why first and then fix the problem
510

@@ -11,6 +16,7 @@ const author = {
1116
alive: true,
1217
};
1318

14-
for (const value of author) {
19+
// Fix: Object.values() returns an array that can be looped over
20+
for (const value of Object.values(author)) {
1521
console.log(value);
1622
}

Sprint-2/debug/recipe.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
// Predict and explain first...
22

3+
// This outputs [object Object] because putting an object in a template string calls toString().
4+
// The default toString() for objects just returns "[object Object]".
5+
// References:
6+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
7+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join
8+
39
// This program should log out the title, how many it serves and the ingredients.
410
// Each ingredient should be logged on a new line
511
// How can you fix it?
@@ -10,6 +16,7 @@ const recipe = {
1016
ingredients: ["olive oil", "tomatoes", "salt", "pepper"],
1117
};
1218

19+
// Fix: Accesses each property directly and uses join() to format the ingredients
1320
console.log(`${recipe.title} serves ${recipe.serves}
1421
ingredients:
15-
${recipe}`);
22+
${recipe.ingredients.join("\n")}`);

Sprint-2/implement/contains.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1-
function contains() {}
1+
// Checks if an object has a specific property.
2+
// References:
3+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
4+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/typeof
5+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
6+
7+
function contains(obj, propertyName) {
8+
// Returns false for invalid inputs (null, arrays, or non-objects)
9+
if (typeof obj !== "object" || obj === null || Array.isArray(obj)) {
10+
return false;
11+
}
12+
13+
return obj.hasOwnProperty(propertyName);
14+
}
215

316
module.exports = contains;

Sprint-2/implement/contains.test.js

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ E.g. contains({a: 1, b: 2}, 'a') // returns true
88
as the object contains a key of 'a'
99
1010
E.g. contains({a: 1, b: 2}, 'c') // returns false
11-
as the object doesn't contains a key of 'c'
11+
as the object doesn't contain a key of 'c'
1212
*/
1313

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

20+
// Returns true when the property exists
21+
test("contains returns true if the property exists", () => {
22+
expect(contains({ a: 1, b: 2 }, "a")).toBe(true);
23+
});
24+
2025
// Given an empty object
2126
// When passed to contains
2227
// Then it should return false
23-
test.todo("contains on empty object returns false");
28+
29+
// An empty object has no properties
30+
test("contains returns false for an empty object", () => {
31+
expect(contains({}, "a")).toBe(false);
32+
});
2433

2534
// Given an object with properties
2635
// When passed to contains with an existing property name
2736
// Then it should return true
2837

38+
// Finds a named property in a typical object
39+
test("contains returns true for another property that exists", () => {
40+
expect(contains({ name: "Lisa", age: 73 }, "name")).toBe(true);
41+
});
42+
2943
// Given an object with properties
30-
// When passed to contains with a non-existent property name
44+
// When passed to contains with a property name that does not exist
45+
// Then it should return false
46+
47+
// Returns false for a missing property
48+
test("contains returns false for a property that does not exist", () => {
49+
expect(contains({ name: "Leo", age: 19 }, "height")).toBe(false);
50+
});
51+
52+
// Given an object
53+
// When passed to contains with a property that does not exist
3154
// Then it should return false
3255

56+
// Returns false for a property not in the object
57+
test("contains returns false when the property is not present", () => {
58+
expect(contains({ a: 1, b: 2 }, "c")).toBe(false);
59+
});
60+
3361
// Given invalid parameters like an array
3462
// When passed to contains
3563
// Then it should return false or throw an error
64+
65+
// Handles invalid inputs gracefully
66+
test("contains handles invalid parameters", () => {
67+
expect(contains([], "a")).toBe(false);
68+
expect(contains(null, "a")).toBe(false);
69+
expect(contains(undefined, "a")).toBe(false);
70+
});

Sprint-2/implement/lookup.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
1-
function createLookup() {
2-
// implementation here
1+
// Converts an array of pairs into a lookup object.
2+
// References:
3+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
4+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors#bracket_notation
5+
6+
function createLookup(arrayOfPairs) {
7+
const lookupObject = {};
8+
9+
for (const pair of arrayOfPairs) {
10+
const key = pair[0];
11+
const value = pair[1];
12+
13+
// Bracket notation allows using a variable as the property name
14+
lookupObject[key] = value;
15+
}
16+
17+
return lookupObject;
318
}
419

520
module.exports = createLookup;

Sprint-2/implement/lookup.test.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
const createLookup = require("./lookup.js");
22

3-
test.todo("creates a country currency code lookup for multiple codes");
4-
53
/*
64
75
Create a lookup object of key value pairs from an array of code pairs
@@ -33,3 +31,18 @@ It should return:
3331
'CA': 'CAD'
3432
}
3533
*/
34+
35+
// Converts multiple pairs into a lookup object
36+
test("creates a country currency code lookup for multiple codes", () => {
37+
const input = [
38+
["US", "USD"],
39+
["CA", "CAD"],
40+
];
41+
42+
const expectedOutput = {
43+
US: "USD",
44+
CA: "CAD",
45+
};
46+
47+
expect(createLookup(input)).toEqual(expectedOutput);
48+
});

Sprint-2/implement/querystring.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
1+
// Parses a query string into an object.
2+
// References:
3+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/split
4+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf
5+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/slice
6+
17
function parseQueryString(queryString) {
28
const queryParams = {};
9+
10+
// Returns early if the string is empty
311
if (queryString.length === 0) {
412
return queryParams;
513
}
14+
615
const keyValuePairs = queryString.split("&");
716

817
for (const pair of keyValuePairs) {
9-
const [key, value] = pair.split("=");
18+
// Finds only the first "=" since values may contain "=" too
19+
const firstEqualsIndex = pair.indexOf("=");
20+
21+
const key = pair.slice(0, firstEqualsIndex);
22+
const value = pair.slice(firstEqualsIndex + 1);
23+
1024
queryParams[key] = value;
1125
}
1226

Sprint-2/implement/querystring.test.js

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,54 @@
33
// Below is one test case for an edge case the implementation doesn't handle well.
44
// Fix the implementation for this test, and try to think of as many other edge cases as possible - write tests and fix those too.
55

6-
const parseQueryString = require("./querystring.js")
6+
const parseQueryString = require("./querystring.js");
77

8+
// Handles values containing "="
89
test("parses querystring values containing =", () => {
910
expect(parseQueryString("equation=x=y+1")).toEqual({
10-
"equation": "x=y+1",
11+
equation: "x=y+1",
12+
});
13+
});
14+
15+
// Parses a simple key-value pair
16+
test("parses a simple key-value pair", () => {
17+
expect(parseQueryString("name=John")).toEqual({
18+
name: "Samantha",
19+
});
20+
});
21+
22+
// Parses multiple pairs separated by "&"
23+
test("parses multiple key-value pairs", () => {
24+
expect(parseQueryString("name=John&age=25")).toEqual({
25+
name: "Samantha",
26+
age: "33",
27+
});
28+
});
29+
30+
// Returns an empty object for an empty string
31+
test("returns an empty object for an empty string", () => {
32+
expect(parseQueryString("")).toEqual({});
33+
});
34+
35+
// Handles keys with empty values
36+
test("parses a key with no value after the equals sign", () => {
37+
expect(parseQueryString("name=")).toEqual({
38+
name: "",
39+
});
40+
});
41+
42+
// Preserves multiple "=" in values
43+
test("parses querystring with multiple = signs in value", () => {
44+
expect(parseQueryString("formula=a=b=c")).toEqual({
45+
formula: "a=b=c",
46+
});
47+
});
48+
49+
// Handles a mix of simple and complex values
50+
test("parses mixed simple and complex key-value pairs", () => {
51+
expect(parseQueryString("name=John&equation=1+1=2&city=London")).toEqual({
52+
name: "Samantha",
53+
equation: "1+1=2",
54+
city: "London",
1155
});
1256
});

Sprint-2/implement/tally.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
1-
function tally() {}
1+
// Counts how often each item appears in an array.
2+
// References:
3+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
4+
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of
5+
6+
function tally(arrayOfItems) {
7+
// Checks the input is actually an array
8+
const inputIsNotAnArray = !Array.isArray(arrayOfItems);
9+
10+
if (inputIsNotAnArray) {
11+
throw new Error("Input must be an array");
12+
}
13+
14+
const countObject = {};
15+
16+
for (const item of arrayOfItems) {
17+
// If the item is already counted, add 1; otherwise start at 1
18+
const itemAlreadyCounted = countObject[item] !== undefined;
19+
20+
if (itemAlreadyCounted) {
21+
countObject[item] = countObject[item] + 1;
22+
} else {
23+
countObject[item] = 1;
24+
}
25+
}
26+
27+
return countObject;
28+
}
229

330
module.exports = tally;

0 commit comments

Comments
 (0)