Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Sprint-3/todo-list/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ <h1>My ToDo List</h1>
<button id="add-task-btn">Add</button>
</div>

<button id="delete-completed-btn">Delete Completed</button>

<ul id="todo-list" class="todo-list">
</ul>

Expand Down
4 changes: 2 additions & 2 deletions Sprint-3/todo-list/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "module",
"scripts": {
"serve": "http-server",
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
"test": "set NODE_OPTIONS=--experimental-vm-modules && jest"
},
"repository": {
"type": "git",
Expand All @@ -20,4 +20,4 @@
"http-server": "^14.1.1",
"jest": "^30.0.4"
}
}
}
7 changes: 7 additions & 0 deletions Sprint-3/todo-list/script.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ const todos = [];
window.addEventListener("load", () => {
document.getElementById("add-task-btn").addEventListener("click", addNewTodo);

document
.getElementById("delete-completed-btn")
.addEventListener("click", () => {
Todos.deleteCompleted(todos);
render();
});

// Populate sample data
Todos.addTask(todos, "Wash the dishes", false);
Todos.addTask(todos, "Do the shopping", true);
Expand Down
23 changes: 23 additions & 0 deletions Sprint-3/todo-list/todos.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Add a new task
export function addTask(todos, task, completed) {
todos.push({ task, completed });
}

// Delete a task by index
export function deleteTask(todos, index) {
if (index < 0 || index >= todos.length) return;
todos.splice(index, 1);
}

// Toggle completed status
export function toggleCompletedOnTask(todos, index) {
if (index < 0 || index >= todos.length) return;
todos[index].completed = !todos[index].completed;
}

// Delete all completed tasks
export function deleteCompleted(todos) {
const remaining = todos.filter((todo) => !todo.completed);
todos.length = 0;
todos.push(...remaining);
}
169 changes: 169 additions & 0 deletions Sprint-3/todo-list/todos.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// The tests is prepared to demonstrate we can test the functions
// in a module independently.

// Command to execute this script:
// npm test todos.test.mjs

// Import all the exported members through an object
import * as Todos from "./todos.js";

// 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 },
];
}

// 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);
});
});

describe("deleteTask()", () => {

test("Delete the first task", () => {
const todos = createMockTodos();
const todosBeforeDeletion = createMockTodos();
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 = createMockTodos();
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 = createMockTodos();
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 = createMockTodos();
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 = createMockTodos();
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 = createMockTodos();

Todos.toggleCompletedOnTask(todos, 10);
expect(todos).toEqual(todosBeforeToggle);

Todos.toggleCompletedOnTask(todos, -1);
expect(todos).toEqual(todosBeforeToggle);
});
});

describe("deleteCompleted()", () => {
test("removes all completed tasks from the list", () => {
const todos = createMockTodos();

Todos.deleteCompleted(todos);

expect(todos).toEqual([
{ task: "Task 2 description", completed: false },
{ task: "Task 4 description", completed: false },
]);
});

test("does nothing if no tasks are completed", () => {
const todos = [
{ task: "Task A", completed: false },
{ task: "Task B", completed: false },
];

Todos.deleteCompleted(todos);

expect(todos).toEqual([
{ task: "Task A", completed: false },
{ task: "Task B", completed: false },
]);
});

test("removes all tasks if all are completed", () => {
const todos = [
{ task: "Task A", completed: true },
{ task: "Task B", completed: true },
];

Todos.deleteCompleted(todos);

expect(todos).toEqual([]);
});
});
Loading