diff --git a/.prettierrc b/.prettierrc
index 59bb3b44f..264aee094 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -12,7 +12,7 @@
"requirePragma": false,
"semi": true,
"singleQuote": false,
- "tabWidth": 2,
+ "tabWidth": 4,
"trailingComma": "es5",
"useTabs": false,
"vueIndentScriptAndStyle": false
diff --git a/Sprint-3/todo-list/README.md b/Sprint-3/todo-list/README.md
index 4415697fd..edd6d2f89 100644
--- a/Sprint-3/todo-list/README.md
+++ b/Sprint-3/todo-list/README.md
@@ -1,28 +1,33 @@
# ToDo List App
The files in this folder implements a ToDo List App that allows a user to
-- Create a new ToDo task
-- Delete a ToDo task
-- Display all ToDo tasks
-- Changing the "completed" status of a ToDo task
+
+- Create a new ToDo task
+- Delete a ToDo task
+- Display all ToDo tasks
+- Changing the "completed" status of a ToDo task
Each ToDo task has two properties:
- - `task`: A string describing the task
- - `completed`: a Boolean value that indicates whether the task is completed or not
+
+- `task`: A string describing the task
+- `completed`: a Boolean value that indicates whether the task is completed or not
## Installation
-Run the following command in this directory to install all required dependencies:
+Run the following command in this directory to install all required dependencies:
+
```
npm install
```
+
> This will install
-- `jest` - for running unix test
-- `http-server` - for serving `index.html` over HTTP
-
+
+- `jest` - for running unix test
+- `http-server` - for serving `index.html` over HTTP
+
**Note:** If you are using a Windows CLI, replace `package.json` by `package.json-windows`.
-## Running the App
+## Running the App
Since the app uses **ES modules**, the HTML file **must be loaded via HTTP/HTTPS** rather than
directly from the file system.
@@ -33,30 +38,29 @@ Two possible ways to serve `index.html` over HTTP:
#### Option 1: `http-server`
-1. Run
- ```
- npm run serve
- ```
- > Here, `serve` is a shortcut defined in `package.json` for running `http-server`.
-
-
-2. Open one of the URLs shown in the terminal (e.g., `http://127.0.0.1:8080`).
+1. Run
+ ```
+ npm run serve
+ ```
-#### Option 2: Open `index.html` with Live Server in VSCode.
+ > Here, `serve` is a shortcut defined in `package.json` for running `http-server`.
+2. Open one of the URLs shown in the terminal (e.g., `http://127.0.0.1:8080`).
+
+#### Option 2: Open `index.html` with Live Server in VSCode.
## Understanding how the code is organized as ES modules
-- [What is ES Modules?](00-what_is_ES_modules.md)
-- [How to use ES modules with Node.js and Jest?](01-using_esm_with_nodejs_and_jest.md)
-- [A guide to modularize a web app](02-guide_to_modularize_code.md)
+- [What is ES Modules?](00-what_is_ES_modules.md)
+- [How to use ES modules with Node.js and Jest?](01-using_esm_with_nodejs_and_jest.md)
+- [A guide to modularize a web app](02-guide_to_modularize_code.md)
---
## Exercise Instructions
-In this exercise, your objective is to extend the ToDo app by implementing new features.
+In this exercise, your objective is to extend the ToDo app by implementing new features.
Start with the main feature and then try the stretch goals if you have extra time.
### Main Feature: Mass delete of completed ToDos
@@ -64,9 +68,10 @@ Start with the main feature and then try the stretch goals if you have extra tim
Add a button that deletes all completed tasks at once.
Steps:
+
1. In `index.html`, add a "Delete completed tasks" button.
-2. In `todos.mjs`, implement a function `deleteCompleted(todoList)` that removes all completed
+2. In `todos.mjs`, implement a function `deleteCompleted(todoList)` that removes all completed
ToDos from the given list.
3. In `todos.test.mjs`, write a Jest test that verifies `deleteCompleted()` works correctly.
@@ -76,19 +81,12 @@ Steps:
### Stretch 1: Add deadlines for ToDos
-Allow users to set and view deadlines for their tasks.
- - When creating a ToDo, let the user select a deadline using an HTML **datepicker** input.
- - If no date is selected, the ToDo has **no deadline**.
- - When rendering a ToDo in the list, display the deadline only if it exists.
+Allow users to set and view deadlines for their tasks. - When creating a ToDo, let the user select a deadline using an HTML **datepicker** input. - If no date is selected, the ToDo has **no deadline**. - When rendering a ToDo in the list, display the deadline only if it exists.
### Stretch 2: Extra Challenge – Show time remaining
-Instead of showing the deadline as a date, display how many days are left until the
-deadline (relative to today).
- - Decide how overdue ToDos should be handled and then implement your chosen solution.
+Instead of showing the deadline as a date, display how many days are left until the
+deadline (relative to today). - Decide how overdue ToDos should be handled and then implement your chosen solution.
👉 Hint: You can use the [JavaScript Date API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
to calculate the difference.
-
-
-
diff --git a/Sprint-3/todo-list/index.html b/Sprint-3/todo-list/index.html
index 4d12c4654..c2fbe8a3d 100644
--- a/Sprint-3/todo-list/index.html
+++ b/Sprint-3/todo-list/index.html
@@ -1,40 +1,60 @@
-
-
-
- ToDo List
-
-
+
+
+
+ ToDo List
+
+
-
-
-
-
-
My ToDo List
+
+
+
+
+
My ToDo List
-
-
-
-
+
+
+
+
-
-
+
-
-
-
- Task description
-
-
-
+
+
+
+ Task description
+
+
+
+
+
+
-
-
-
-
-
+
diff --git a/Sprint-3/todo-list/package.json b/Sprint-3/todo-list/package.json
index ce181158a..2262f3d00 100644
--- a/Sprint-3/todo-list/package.json
+++ b/Sprint-3/todo-list/package.json
@@ -5,8 +5,8 @@
"description": "You must update this package",
"type": "module",
"scripts": {
- "serve": "http-server",
- "test": "NODE_OPTIONS=--experimental-vm-modules jest"
+ "serve": "http-server",
+ "test": "set NODE_OPTIONS=--experimental-vm-modules && jest"
},
"repository": {
"type": "git",
@@ -17,7 +17,7 @@
},
"homepage": "https://github.com/CodeYourFuture/CYF-Coursework-Template#readme",
"devDependencies": {
- "http-server": "^14.1.1",
+ "http-server": "^14.1.1",
"jest": "^30.0.4"
}
}
diff --git a/Sprint-3/todo-list/package.json-windows b/Sprint-3/todo-list/package.json-backup
similarity index 79%
rename from Sprint-3/todo-list/package.json-windows
rename to Sprint-3/todo-list/package.json-backup
index 2262f3d00..ce181158a 100644
--- a/Sprint-3/todo-list/package.json-windows
+++ b/Sprint-3/todo-list/package.json-backup
@@ -5,8 +5,8 @@
"description": "You must update this package",
"type": "module",
"scripts": {
- "serve": "http-server",
- "test": "set NODE_OPTIONS=--experimental-vm-modules && jest"
+ "serve": "http-server",
+ "test": "NODE_OPTIONS=--experimental-vm-modules jest"
},
"repository": {
"type": "git",
@@ -17,7 +17,7 @@
},
"homepage": "https://github.com/CodeYourFuture/CYF-Coursework-Template#readme",
"devDependencies": {
- "http-server": "^14.1.1",
+ "http-server": "^14.1.1",
"jest": "^30.0.4"
}
}
diff --git a/Sprint-3/todo-list/script.mjs b/Sprint-3/todo-list/script.mjs
index ba0b2ceae..f9cfdacaa 100644
--- a/Sprint-3/todo-list/script.mjs
+++ b/Sprint-3/todo-list/script.mjs
@@ -1,4 +1,4 @@
-// Store everything imported from './todos.mjs' module as properties of an object named Todos
+// Store everything imported from './todos.mjs' module as properties of an object named Todos
import * as Todos from "./todos.mjs";
// To store the todo tasks
@@ -6,27 +6,28 @@ const todos = [];
// Set up tasks to be performed once on page load
window.addEventListener("load", () => {
- document.getElementById("add-task-btn").addEventListener("click", addNewTodo);
+ document
+ .getElementById("add-task-btn")
+ .addEventListener("click", addNewTodo);
- // Populate sample data
- Todos.addTask(todos, "Wash the dishes", false);
- Todos.addTask(todos, "Do the shopping", true);
+ // Populate sample data
+ Todos.addTask(todos, "Wash the dishes", false);
+ Todos.addTask(todos, "Do the shopping", true);
- render();
+ render();
});
-
-// A callback that reads the task description from an input field and
+// A callback that reads the task description from an input field and
// append a new task to the todo list.
function addNewTodo() {
- const taskInput = document.getElementById("new-task-input");
- const task = taskInput.value.trim();
- if (task) {
- Todos.addTask(todos, task, false);
- render();
- }
-
- taskInput.value = "";
+ const taskInput = document.getElementById("new-task-input");
+ const task = taskInput.value.trim();
+ if (task) {
+ Todos.addTask(todos, task, false);
+ render();
+ }
+
+ taskInput.value = "";
}
// Note:
@@ -37,40 +38,45 @@ const todoListEl = document.getElementById("todo-list");
// Render the whole todo list
function render() {
- todoListEl.innerHTML = "";
+ todoListEl.innerHTML = "";
- todos.forEach((todo, index) => {
- const todoListItem = createListItem(todo, index);
- todoListEl.append(todoListItem);
- });
+ todos.forEach((todo, index) => {
+ const todoListItem = createListItem(todo, index);
+ todoListEl.append(todoListItem);
+ });
}
-
// Note:
// - First child of #todo-item-template is a
element.
// We will create each ToDo list item as a clone of this node.
// - This variable is declared here to be close to the only function that uses it.
-const todoListItemTemplate =
- document.getElementById("todo-item-template").content.firstElementChild;
+const todoListItemTemplate =
+ document.getElementById("todo-item-template").content.firstElementChild;
// Create a
element for the given todo task
function createListItem(todo, index) {
- const li = todoListItemTemplate.cloneNode(true); // true => Do a deep copy of the node
+ const li = todoListItemTemplate.cloneNode(true); // true => Do a deep copy of the node
- li.querySelector(".description").textContent = todo.task;
- if (todo.completed) {
- li.classList.add("completed");
- }
+ li.querySelector(".description").textContent = todo.task;
+ if (todo.completed) {
+ li.classList.add("completed");
+ }
- li.querySelector('.complete-btn').addEventListener("click", () => {
- Todos.toggleCompletedOnTask(todos, index);
- render();
- });
-
- li.querySelector('.delete-btn').addEventListener("click", () => {
- Todos.deleteTask(todos, index);
- render();
- });
+ li.querySelector(".complete-btn").addEventListener("click", () => {
+ Todos.toggleCompletedOnTask(todos, index);
+ render();
+ });
+
+ li.querySelector(".delete-btn").addEventListener("click", () => {
+ Todos.deleteTask(todos, index);
+ render();
+ });
+
+ return li;
+}
- return li;
-}
\ No newline at end of file
+// Connected the delete-completed button
+document.getElementById("delete-completed").addEventListener("click", () => {
+ Todos.deleteCompleted(todos);
+ render();
+});
diff --git a/Sprint-3/todo-list/style.css b/Sprint-3/todo-list/style.css
index 535e91227..b6ee8e611 100644
--- a/Sprint-3/todo-list/style.css
+++ b/Sprint-3/todo-list/style.css
@@ -1,107 +1,117 @@
* {
- box-sizing: border-box;
- margin: 0;
- padding: 0;
- font-family: Arial, sans-serif;
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ font-family: Arial, sans-serif;
}
body {
- background-color: #f4f4f4;
- padding: 40px;
+ background-color: #f4f4f4;
+ padding: 40px;
}
.todo-container {
- max-width: 500px;
- margin: 0 auto;
- background: white;
- border-radius: 10px;
- padding: 20px;
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
+ max-width: 500px;
+ margin: 0 auto;
+ background: white;
+ border-radius: 10px;
+ padding: 20px;
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}
h1 {
- text-align: center;
- margin-bottom: 20px;
+ text-align: center;
+ margin-bottom: 20px;
}
.todo-input {
- display: flex;
- gap: 10px;
- margin-bottom: 20px;
+ display: flex;
+ gap: 10px;
+ margin-bottom: 20px;
}
.todo-input input {
- flex: 1;
- padding: 10px;
- font-size: 16px;
- border-radius: 6px;
- border: 1px solid #ccc;
+ flex: 1;
+ padding: 10px;
+ font-size: 16px;
+ border-radius: 6px;
+ border: 1px solid #ccc;
}
.todo-input button {
- padding: 10px 20px;
- font-size: 16px;
- background-color: #4CAF50;
- color: white;
- border: none;
- border-radius: 6px;
- cursor: pointer;
+ padding: 10px 20px;
+ font-size: 16px;
+ background-color: #4caf50;
+ color: white;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
}
.todo-input button:hover {
- background-color: #45a049;
+ background-color: #45a049;
}
.todo-list {
- list-style-type: none;
- padding-left: 0;
+ list-style-type: none;
+ padding-left: 0;
}
.todo-item {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 12px 10px;
- margin-bottom: 10px;
- border: 1px solid #ddd;
- border-radius: 6px;
- background-color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 12px 10px;
+ margin-bottom: 10px;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ background-color: #fff;
}
.description {
- flex: 1;
- margin-right: 10px;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
+ flex: 1;
+ margin-right: 10px;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
.actions {
- display: flex;
- gap: 10px;
+ display: flex;
+ gap: 10px;
}
.actions button {
- background: none;
- border: none;
- cursor: pointer;
- font-size: 18px;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 32px;
- height: 32px;
+ background: none;
+ border: none;
+ cursor: pointer;
+ font-size: 18px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
}
.complete-btn i {
- color: green;
+ color: green;
}
.delete-btn i {
- color: red;
+ color: red;
}
.todo-item.completed .description {
- text-decoration: line-through;
- color: gray;
+ text-decoration: line-through;
+ color: gray;
+}
+
+#delete-completed {
+ padding: 10px 20px;
+ font-size: 16px;
+ background-color: rgb(250, 77, 77);
+ color: white;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
}
diff --git a/Sprint-3/todo-list/todos.mjs b/Sprint-3/todo-list/todos.mjs
index f17ab6a25..a098a915a 100644
--- a/Sprint-3/todo-list/todos.mjs
+++ b/Sprint-3/todo-list/todos.mjs
@@ -11,19 +11,32 @@
// Append a new task to todos[]
export function addTask(todos, task, completed = false) {
- todos.push({ task, completed });
+ todos.push({ task, completed });
}
// Delete todos[taskIndex] if it exists
export function deleteTask(todos, taskIndex) {
- if (todos[taskIndex]) {
- todos.splice(taskIndex, 1);
- }
+ if (todos[taskIndex]) {
+ todos.splice(taskIndex, 1);
+ }
}
// Toggle the "completed" property of todos[taskIndex] if the task exists.
export function toggleCompletedOnTask(todos, taskIndex) {
- if (todos[taskIndex]) {
- todos[taskIndex].completed = !todos[taskIndex].completed;
- }
-}
\ No newline at end of file
+ if (todos[taskIndex]) {
+ todos[taskIndex].completed = !todos[taskIndex].completed;
+ }
+}
+
+export function deleteCompleted(todos) {
+ const todosNotDone = []; // Empty array to put the not done tasks
+ for (let i = 0; i < todos.length; i++) {
+ // Looping in the array to find
+ if (todos[i].completed === false) {
+ // the tasks that are not yet done
+ todosNotDone.push(todos[i]); // and add them in out empty array
+ }
+ }
+ todos.length = 0; // Clears our original array of tasks
+ todos.push(...todosNotDone); // Push all the content of the not done array one by one to the previously cleared array
+}
diff --git a/Sprint-3/todo-list/todos.test.mjs b/Sprint-3/todo-list/todos.test.mjs
index d6bf96414..dd1e88a25 100644
--- a/Sprint-3/todo-list/todos.test.mjs
+++ b/Sprint-3/todo-list/todos.test.mjs
@@ -9,124 +9,157 @@ import * as Todos from "./todos.mjs";
// Return a mock ToDo List data with exactly 4 elements.
function createMockTodos() {
- return [
- { task: "Task 1 description", completed: true },
- { task: "Task 2 description", completed: false },
- { task: "Task 3 description", completed: true },
- { task: "Task 4 description", completed: false },
- ];
+ return [
+ { task: "Task 1 description", completed: true },
+ { task: "Task 2 description", completed: false },
+ { task: "Task 3 description", completed: true },
+ { task: "Task 4 description", completed: false },
+ ];
}
// A mock task to simulate user input
const theTask = { task: "The Task", completed: false };
describe("addTask()", () => {
- test("Add a task to an empty ToDo list", () => {
- let todos = [];
- Todos.addTask(todos, theTask.task, theTask.completed);
- expect(todos).toHaveLength(1);
- expect(todos[0]).toEqual(theTask);
- });
-
- test("Should append a new task to the end of a ToDo list", () => {
-
- const todos = createMockTodos();
- const lengthBeforeAddition = todos.length;
- Todos.addTask(todos, theTask.task, theTask.completed);
- // todos should now have one more task
- expect(todos).toHaveLength(lengthBeforeAddition + 1);
-
- // New task should be appended to the todos
- expect(todos[todos.length - 1]).toEqual(theTask);
- });
+ test("Add a task to an empty ToDo list", () => {
+ let todos = [];
+ Todos.addTask(todos, theTask.task, theTask.completed);
+ expect(todos).toHaveLength(1);
+ expect(todos[0]).toEqual(theTask);
+ });
+
+ test("Should append a new task to the end of a ToDo list", () => {
+ const todos = createMockTodos();
+ const lengthBeforeAddition = todos.length;
+ Todos.addTask(todos, theTask.task, theTask.completed);
+ // todos should now have one more task
+ expect(todos).toHaveLength(lengthBeforeAddition + 1);
+
+ // New task should be appended to the todos
+ expect(todos[todos.length - 1]).toEqual(theTask);
+ });
});
describe("deleteTask()", () => {
-
- test("Delete the first task", () => {
- const todos = createMockTodos();
- const todosBeforeDeletion = [...todos];
- const lengthBeforeDeletion = todos.length;
- Todos.deleteTask(todos, 0);
-
- expect(todos).toHaveLength(lengthBeforeDeletion - 1);
-
- expect(todos[0]).toEqual(todosBeforeDeletion[1]);
- expect(todos[1]).toEqual(todosBeforeDeletion[2]);
- expect(todos[2]).toEqual(todosBeforeDeletion[3]);
- });
-
- test("Delete the second task (a middle task)", () => {
- const todos = createMockTodos();
- const todosBeforeDeletion = [...todos];
- const lengthBeforeDeletion = todos.length;
- Todos.deleteTask(todos, 1);
-
- expect(todos).toHaveLength(lengthBeforeDeletion - 1);
-
- expect(todos[0]).toEqual(todosBeforeDeletion[0]);
- expect(todos[1]).toEqual(todosBeforeDeletion[2]);
- expect(todos[2]).toEqual(todosBeforeDeletion[3]);
- });
-
- test("Delete the last task", () => {
- const todos = createMockTodos();
- const todosBeforeDeletion = [...todos];
- const lengthBeforeDeletion = todos.length;
- Todos.deleteTask(todos, todos.length - 1);
-
- expect(todos).toHaveLength(lengthBeforeDeletion - 1);
-
- expect(todos[0]).toEqual(todosBeforeDeletion[0]);
- expect(todos[1]).toEqual(todosBeforeDeletion[1]);
- expect(todos[2]).toEqual(todosBeforeDeletion[2]);
- });
-
- test("Delete a non-existing task", () => {
- const todos = createMockTodos();
- const todosBeforeDeletion = [...todos];
- Todos.deleteTask(todos, 10);
- expect(todos).toEqual(todosBeforeDeletion);
-
- Todos.deleteTask(todos, -1);
- expect(todos).toEqual(todosBeforeDeletion);
- });
+ test("Delete the first task", () => {
+ const todos = createMockTodos();
+ const todosBeforeDeletion = [...todos];
+ const lengthBeforeDeletion = todos.length;
+ Todos.deleteTask(todos, 0);
+
+ expect(todos).toHaveLength(lengthBeforeDeletion - 1);
+
+ expect(todos[0]).toEqual(todosBeforeDeletion[1]);
+ expect(todos[1]).toEqual(todosBeforeDeletion[2]);
+ expect(todos[2]).toEqual(todosBeforeDeletion[3]);
+ });
+
+ test("Delete the second task (a middle task)", () => {
+ const todos = createMockTodos();
+ const todosBeforeDeletion = [...todos];
+ const lengthBeforeDeletion = todos.length;
+ Todos.deleteTask(todos, 1);
+
+ expect(todos).toHaveLength(lengthBeforeDeletion - 1);
+
+ expect(todos[0]).toEqual(todosBeforeDeletion[0]);
+ expect(todos[1]).toEqual(todosBeforeDeletion[2]);
+ expect(todos[2]).toEqual(todosBeforeDeletion[3]);
+ });
+
+ test("Delete the last task", () => {
+ const todos = createMockTodos();
+ const todosBeforeDeletion = [...todos];
+ const lengthBeforeDeletion = todos.length;
+ Todos.deleteTask(todos, todos.length - 1);
+
+ expect(todos).toHaveLength(lengthBeforeDeletion - 1);
+
+ expect(todos[0]).toEqual(todosBeforeDeletion[0]);
+ expect(todos[1]).toEqual(todosBeforeDeletion[1]);
+ expect(todos[2]).toEqual(todosBeforeDeletion[2]);
+ });
+
+ test("Delete a non-existing task", () => {
+ const todos = createMockTodos();
+ const todosBeforeDeletion = [...todos];
+ Todos.deleteTask(todos, 10);
+ expect(todos).toEqual(todosBeforeDeletion);
+
+ Todos.deleteTask(todos, -1);
+ expect(todos).toEqual(todosBeforeDeletion);
+ });
});
describe("toggleCompletedOnTask()", () => {
-
- test("Expect the 'completed' property to toggle on an existing task", () => {
- const todos = createMockTodos();
- const taskIndex = 1;
- const completedStateBeforeToggle = todos[taskIndex].completed;
- Todos.toggleCompletedOnTask(todos, taskIndex);
- expect(todos[taskIndex].completed).toEqual(!completedStateBeforeToggle);
-
- // Toggle again
- Todos.toggleCompletedOnTask(todos, taskIndex);
- expect(todos[taskIndex].completed).toEqual(completedStateBeforeToggle);
- });
-
- test("Expect toggling on a task does not affect other tasks", () => {
- const todos = createMockTodos();
- const todosBeforeToggle = [...todos];
- Todos.toggleCompletedOnTask(todos, 1);
-
- expect(todos[0]).toEqual(todosBeforeToggle[0]);
- expect(todos[2]).toEqual(todosBeforeToggle[2]);
- expect(todos[3]).toEqual(todosBeforeToggle[3]);
- });
-
-
- test("Expect no change when toggling on a non-existing task", () => {
- const todos = createMockTodos();
- const todosBeforeToggle = [...todos];
-
- Todos.toggleCompletedOnTask(todos, 10);
- expect(todos).toEqual(todosBeforeToggle);
-
- Todos.toggleCompletedOnTask(todos, -1);
- expect(todos).toEqual(todosBeforeToggle);
- });
+ test("Expect the 'completed' property to toggle on an existing task", () => {
+ const todos = createMockTodos();
+ const taskIndex = 1;
+ const completedStateBeforeToggle = todos[taskIndex].completed;
+ Todos.toggleCompletedOnTask(todos, taskIndex);
+ expect(todos[taskIndex].completed).toEqual(!completedStateBeforeToggle);
+
+ // Toggle again
+ Todos.toggleCompletedOnTask(todos, taskIndex);
+ expect(todos[taskIndex].completed).toEqual(completedStateBeforeToggle);
+ });
+
+ test("Expect toggling on a task does not affect other tasks", () => {
+ const todos = createMockTodos();
+ const todosBeforeToggle = [...todos];
+ Todos.toggleCompletedOnTask(todos, 1);
+
+ expect(todos[0]).toEqual(todosBeforeToggle[0]);
+ expect(todos[2]).toEqual(todosBeforeToggle[2]);
+ expect(todos[3]).toEqual(todosBeforeToggle[3]);
+ });
+
+ test("Expect no change when toggling on a non-existing task", () => {
+ const todos = createMockTodos();
+ const todosBeforeToggle = [...todos];
+
+ Todos.toggleCompletedOnTask(todos, 10);
+ expect(todos).toEqual(todosBeforeToggle);
+
+ Todos.toggleCompletedOnTask(todos, -1);
+ expect(todos).toEqual(todosBeforeToggle);
+ });
});
+describe("deleteCompleted()", () => {
+ test("Deletes all completed tasks", () => {
+ const todos = createMockTodos();
+ Todos.deleteCompleted(todos);
+ expect(todos.every((todo) => todo.completed === false)).toBe(true); // Only keeps notdone tasks
+ expect(todos).toHaveLength(2); // 2 tasks not completed, that's what should remain after the function run
+ expect(todos).toEqual([
+ { task: "Task 2 description", completed: false },
+ { task: "Task 4 description", completed: false },
+ ]);
+ });
+
+ test("Nothing changes if no task is completed", () => {
+ const todos = [
+ { task: "task A", completed: false },
+ { task: "task B", completed: false },
+ ];
+ const before = [...todos];
+ Todos.deleteCompleted(todos);
+ expect(todos).toEqual(before);
+ });
+
+ test("Deletes all tasks if are completed", () => {
+ const todos = [
+ { task: "task A", completed: true },
+ { task: "task B", completed: true },
+ ];
+ Todos.deleteCompleted(todos);
+ expect(todos).toHaveLength(0);
+ });
+
+ test("On an empty array, it returns the empty array", () => {
+ const todos = [];
+ Todos.deleteCompleted(todos);
+ expect(todos).toHaveLength(0);
+ });
+});
diff --git a/prep/exercise-1.js b/prep/exercise-1.js
new file mode 100644
index 000000000..be0bc25ea
--- /dev/null
+++ b/prep/exercise-1.js
@@ -0,0 +1,14 @@
+// Can you fix this code?
+function doubleAllNumbers(numbers) {
+ let doubledNumbers = [];
+
+ for (let n of numbers) {
+ doubledNumbers.push(n * 2);
+ }
+
+ return doubledNumbers;
+}
+
+const myNums = [10, 20, 30];
+const double = doubleAllNumbers(myNums);
+console.log(double);
diff --git a/prep/exercise-1.test.js b/prep/exercise-1.test.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/prep/exercise-2.js b/prep/exercise-2.js
new file mode 100644
index 000000000..fa228871a
--- /dev/null
+++ b/prep/exercise-2.js
@@ -0,0 +1,13 @@
+// Write a function which takes an array as a parameter
+// and swaps the first element with the last element
+
+function swapFirstAndLast(arr) {
+ const first = arr[0]; //Indivates the first digit location of the array
+ const last = arr[arr.length - 1]; //Indicates the lst digit location of the array
+ arr[0] = last; //Because I can't reassign a new value to a const and we want the first position to hold the value of the last
+ arr[arr.length - 1] = first;
+}
+
+const myArray = [5, 2, 3, 4, 1];
+swapFirstAndLast(myArray);
+console.log(myArray); // what output should we expect?
diff --git a/prep/exercise-2.test.js b/prep/exercise-2.test.js
new file mode 100644
index 000000000..e69de29bb
diff --git a/prep/mean.js b/prep/mean.js
new file mode 100644
index 000000000..f9ec4bdae
--- /dev/null
+++ b/prep/mean.js
@@ -0,0 +1,20 @@
+function calculateMean(list) {
+ let total = 0;
+ for (const item of list) {
+ total += item;
+ }
+}
+
+function calculateMedian(list) {
+ const middleIndex = Math.floor(list.length / 2);
+ const median = list.splice(middleIndex, 1)[0];
+
+ return median;
+}
+
+const list = [10, 20, 30];
+const copy = list;
+copy.push(60, 70);
+
+console.log(list);
+console.log(copy);
diff --git a/prep/mean.test.js b/prep/mean.test.js
new file mode 100644
index 000000000..7a057e17d
--- /dev/null
+++ b/prep/mean.test.js
@@ -0,0 +1,6 @@
+test("calculates the median of a list of odd length", () => {
+ const list = [10, 20, 30, 50, 60];
+ const currentOutput = calculateMedian(list);
+ const targetOutput = 30;
+ expect(currentOutput).toEqual(targetOutput);
+});