Skip to content

Commit aa7da66

Browse files
authored
Merge pull request #790 from cjyuan/todo-new
Update todo-list to demonstrate testing with ESM
2 parents 5aa1295 + 59006e0 commit aa7da66

14 files changed

+597
-250
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# What is JavaScript Modules?
2+
JavaScript modules let us organize code into separate files, making the code easier to manage and reuse. We can export parts of one file (like functions or variables) and import them into another to keep our code clean and modular.
3+
4+
## Different Module Systems
5+
6+
JavaScript has two main ways to handle modules:
7+
8+
- **CommonJS** is the older format used mostly in Node.js. It uses `require` and `module.exports`.
9+
10+
- **ES Modules** (ESM) are the modern, standard way for browsers and Node.js. They use `import` and `export`.
11+
12+
They are **not** fully compatible. At CYF, you should use ESM, not CommonJS.
13+
14+
## Where can I learn ESM?
15+
- [Modules, introduction](https://javascript.info/modules-intro)
16+
- [JavaScript modules -- JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Using ESM with Node.js, Jest, and `jsdom`
2+
3+
## Node.js
4+
5+
Node.js supports both CommonJS and ESM, with CommonJS being the default module system.
6+
7+
To use ESM, we can add `"type": "module"` to `package.json`, or we can name the JavaScript files
8+
with `.mjs` file extension.
9+
10+
**Important**:
11+
- Avoid mixing CommonJS and ESM in the same project. At CYF you should only use ESM.
12+
13+
14+
## Jest
15+
16+
[Jest’s support for ESM](https://jestjs.io/docs/ecmascript-modules) is still experimental, and may require additional configuration to work correctly.
17+
18+
One way to execute Jest test script that uses ESM is to
19+
20+
1. **Update the custom `test` script in `package.json`**:
21+
```javascript
22+
"scripts": {
23+
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
24+
}
25+
```
26+
27+
**Note**: On Windows, use **`set`** instead
28+
```javascript
29+
"scripts": {
30+
"test": "set NODE_OPTIONS=--experimental-vm-modules && jest"
31+
}
32+
```
33+
34+
35+
2. **Run a specific Jest test script using**:
36+
37+
```
38+
npm test -- <test_script_filename>
39+
```
40+
41+
**Note**: The `--` is optional if you do not have arguments to be forwarded to the underlying
42+
`jest` command.
43+
44+
45+
## `jsdom`
46+
47+
[**`jsdom`**](https://github.com/jsdom/jsdom), a pure-JavaScript implementation of DOM for
48+
use with Node.js, **does not yet support** `<script type="module">` tags in HTML.
49+
50+
Testing an ESM-based application with `jsdom` requires additional configuration and third-party tooling.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Why modularize code?
2+
3+
Modularizing code means breaking a program into smaller, self-contained pieces (modules),
4+
each responsible for a specific functionality. This approach offers several key advantages:
5+
6+
- Reusability – You can use the same code in different parts of a project or in other projects.
7+
- Maintainability – It's easier to fix bugs or update features when code is organized into smaller parts.
8+
- Separation of Concerns – Each part of the code handles a specific task, keeping things clear and organized.
9+
- Team Collaboration – Multiple people can work on different modules at the same time without conflict.
10+
- Scalability – You can add new features more easily as the project grows.
11+
- Testing – Smaller modules are easier to test individually.
12+
- Readability – Modular code is easier to read, understand, and navigate.
13+
14+
## How to break a program into smaller modules?
15+
16+
This is a relatively big topic and you will learn more about how to modularize a web app in the
17+
SDC course.
18+
19+
For starters, we recommend focusing on breaking a web app into the **non-UI part** and
20+
the **UI part**. Some of the advantages of doing so include:
21+
22+
1. Easier Testing
23+
- Non-UI code can be tested independently with unit tests.
24+
- You don't need browser environments or DOM simulations (e.g., `jsdom`) for testing logic.
25+
26+
2. Easier Collaboration
27+
- UI developers and business-logic developers can work more independently.
28+
- Clearer separation of concerns makes the codebase easier to maintain over time.
29+
30+
### The Non-UI Part of a Web App
31+
32+
This is the part of the app that works behind the scenes, without any user interface (UI).
33+
34+
It focuses on:
35+
- ✅ How to represent data in the app
36+
- ✅ What operations are needed to support data access and manipulation
37+
38+
### The UI Part of a Web App
39+
40+
This is the part of the app that interacts with the user interface (UI).
41+
42+
It focuses on:
43+
- ✅ How to collect user input
44+
- ✅ How to present data on the screen
45+
- ✅ Calling functions in the non-UI part to process the data
46+
47+
### Dependencies
48+
49+
The UI parts can depend on the non-UI parts (e.g. call functions from the non-UI parts). But the non-UI parts should not depend on the UI parts.
50+
51+
### Example: The ToDo App
52+
- The non-UI part is implemented in `todos.mjs`
53+
- The UI part is implemented in `script.mjs`
54+
55+
Note: For a larger codebase, each part could be divided into multiple modules or files.

Sprint-3/todo-list/README.md

Lines changed: 65 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,94 @@
1-
# Todo-list
1+
# ToDo List App
22

3-
## Explanation
3+
The files in this folder implements a ToDo List App that allows a user to
4+
- Create a new ToDo task
5+
- Delete a ToDo task
6+
- Display all ToDo tasks
7+
- Changing the "completed" status of a ToDo task
48

5-
This is a super handy, super simple to do list.
9+
Each ToDo task has two properties:
10+
- `task`: A string describing the task
11+
- `completed`: a Boolean value that indicates whether the task is completed or not
612

7-
You will be given a list of tasks which are "To Do". We call these tasks "ToDos"
13+
## Installation
814

9-
Each item in the list should have 2 buttons:
15+
Run the following command in this directory to install all required dependencies:
16+
```
17+
npm install
18+
```
19+
> This will install
20+
- `jest` - for running unix test
21+
- `http-server` - for serving `index.html` over HTTP
22+
23+
**Note:** If you are using a Windows CLI, replace `package.json` by `package.json-windows`.
1024

11-
- One to click when the ToDo has been completed - it will apply a line-through style to the text of the ToDo.
12-
- A second to delete the ToDo. This could be used to delete completed ToDos from the list, or remove ToDos that we are no longer interested in doing.
25+
## Running the App
1326

14-
We also want to be able to add ToDos to the list using an input field and a button. When ToDos are created this way they should be added to the list with the 2 above buttons.
27+
Since the app uses **ES modules**, the HTML file **must be loaded via HTTP/HTTPS** rather than
28+
directly from the file system.
1529

16-
More details for the implementation of this challenge can be found in `script.js`
30+
Make sure you run the server in this directory where `index.html` is located.
1731

18-
## Installation
32+
Two possible ways to serve `index.html` over HTTP:
1933

20-
To view the website, open index.html in a browser.
34+
#### Option 1: `http-server`
2135

22-
## Example Solution
36+
1. Run
37+
```
38+
npm run serve
39+
```
40+
> Here, `serve` is a shortcut defined in `package.json` for running `http-server`.
41+
42+
43+
2. Open one of the URLs shown in the terminal (e.g., `http://127.0.0.1:8080`).
2344

24-
A basic example of this can website can be found here
2545

26-
https://chrisowen101.github.io/ToDoListSolution/
46+
#### Option 2: Open `index.html` with Live Server in VSCode.
2747

28-
This covers only the basic tasks, not the advanced tasks.
2948

30-
## Instructions
49+
## Understanding how the code is organized as ES modules
3150

32-
The `populateTodoList()` function should iterate over the list of todos that we are given at the start, it should create a `<li>` for the todo along with some other stuff that you can find in index.html and below.
51+
- [What is ES Modules?](00-what_is_ES_modules.md)
52+
- [How to use ES modules with Node.js and Jest?](01-using_esm_with_nodejs_and_jest.md)
53+
- [A guide to modularize a web app](02-guide_to_modularize_code.md)
3354

34-
The items in the todo list are currently hard-coded into the HTML, refactor the code so that this function creates them and adds the following functionality to them:
55+
---
3556

36-
Each todo should have this HTML inside it:
57+
## Exercise Instructions
3758

38-
```html
39-
<span class="badge bg-primary rounded-pill">
40-
<i class="fa fa-check" aria-hidden="true"></i>
41-
<i class="fa fa-trash" aria-hidden="true"></i>
42-
</span>
43-
```
59+
In this exercise, your objective is to extend the ToDo app by implementing new features.
60+
Start with the main feature and then try the stretch goals if you have extra time.
61+
62+
### Main Feature: Mass delete of completed ToDos
63+
64+
Add a button that deletes all completed tasks at once.
65+
66+
Steps:
67+
1. In `index.html`, add a "Delete completed tasks" button.
4468

45-
The first `<i>` tag needs an event listener that applies a line-through text-decoration styling to the text of the todo. It should remove the styling if it is clicked again.
69+
2. In `todos.mjs`, implement a function `deleteCompleted(todoList)` that removes all completed
70+
ToDos from the given list.
4671

47-
The second `<i>` tag needs an event listener that deletes the parent `<li>` element from the `<ul>`.
72+
3. In `todos.test.mjs`, write a Jest test that verifies `deleteCompleted()` works correctly.
4873

49-
## Advanced Challenge
74+
4. In `script.js`, call `deleteCompleted()` whenever the new button is clicked.
75+
- ⚠️ You should not need to modify the `render()` function.
5076

51-
### Mass delete of completed ToDos
77+
### Stretch 1: Add deadlines for ToDos
5278

53-
Develop the ToDo list further and allow users to delete all completed ToDos.
79+
Allow users to set and view deadlines for their tasks.
80+
- When creating a ToDo, let the user select a deadline using an HTML **datepicker** input.
81+
- If no date is selected, the ToDo has **no deadline**.
82+
- When rendering a ToDo in the list, display the deadline only if it exists.
5483

55-
Add a button that users can click that will iterate through the list of ToDos and then delete them only if they have been completed.
84+
### Stretch 2: Extra Challenge – Show time remaining
5685

57-
## Extra Advanced Challenge
86+
Instead of showing the deadline as a date, display how many days are left until the
87+
deadline (relative to today).
88+
- Decide how overdue ToDos should be handled and then implement your chosen solution.
5889

59-
### Set deadlines for ToDos
90+
👉 Hint: You can use the [JavaScript Date API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
91+
to calculate the difference.
6092

61-
We want users to be able to set, and see, deadlines for their ToDos.
6293

63-
When creating ToDos we want the user to be able to use a datepicker input so they can see when they need to complete the ToDo. The date can be added to the ToDo in the list. If there is no date set when the ToDo is created then this can be skipped.
6494

65-
EXTRA CHALLENGE: instead of displaying the date on the ToDo, implement a countdown of days left until the deadline. You can use the Javascript Date reference to accomplish this:
66-
https://www.w3schools.com/jsref/jsref_obj_date.asp
-72.6 KB
Binary file not shown.

Sprint-3/todo-list/index.html

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,40 @@
11
<!DOCTYPE html>
22
<html lang="en">
3-
<head>
4-
<meta charset="UTF-8" />
5-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6-
<title>Title here</title>
7-
<link rel="stylesheet" href="style.css" />
8-
</head>
9-
<body>
10-
<form>
11-
<div>
12-
<input type="text" placeholder="New todo..." />
13-
</div>
14-
<div>
15-
<button type="submit">Add Todo</button>
16-
<button
17-
type="button"
18-
id="remove-all-completed"
19-
class="btn btn-primary mb-3"
20-
>
21-
Remove all completed
22-
</button>
23-
</div>
24-
</form>
25-
<script src="script.js"></script>
26-
</body>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6+
<title>ToDo List</title>
7+
<link rel="stylesheet" href="style.css" />
8+
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
9+
10+
<script type="module" src="script.mjs"></script>
11+
</head>
12+
<body>
13+
<div class="todo-container">
14+
<h1>My ToDo List</h1>
15+
16+
<div class="todo-input">
17+
<input type="text" id="new-task-input" placeholder="Enter a new task..." />
18+
<button id="add-task-btn">Add</button>
19+
</div>
20+
21+
<ul id="todo-list" class="todo-list">
22+
</ul>
23+
24+
<!--
25+
This is a template for the To-do list item.
26+
It can simplify the creation of list item node in JS script.
27+
-->
28+
<template id="todo-item-template">
29+
<li class="todo-item"> <!-- include class "completed" if the task completed state is true -->
30+
<span class="description">Task description</span>
31+
<div class="actions">
32+
<button class="complete-btn"><span class="fa-solid fa-check" aria-hidden="true"></span></button>
33+
<button class="delete-btn"><span class="fa-solid fa-trash" aria-hidden="true"></span></button>
34+
</div>
35+
</li>
36+
</template>
37+
38+
</div>
39+
</body>
2740
</html>

Sprint-3/todo-list/package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
"version": "1.0.0",
44
"license": "CC-BY-SA-4.0",
55
"description": "You must update this package",
6+
"type": "module",
67
"scripts": {
7-
"test": "jest --config=../jest.config.js todo-list"
8+
"serve": "http-server",
9+
"test": "NODE_OPTIONS=--experimental-vm-modules jest"
810
},
911
"repository": {
1012
"type": "git",
@@ -13,5 +15,9 @@
1315
"bugs": {
1416
"url": "https://github.com/CodeYourFuture/CYF-Coursework-Template/issues"
1517
},
16-
"homepage": "https://github.com/CodeYourFuture/CYF-Coursework-Template#readme"
18+
"homepage": "https://github.com/CodeYourFuture/CYF-Coursework-Template#readme",
19+
"devDependencies": {
20+
"http-server": "^14.1.1",
21+
"jest": "^30.0.4"
22+
}
1723
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "todo-list",
3+
"version": "1.0.0",
4+
"license": "CC-BY-SA-4.0",
5+
"description": "You must update this package",
6+
"type": "module",
7+
"scripts": {
8+
"serve": "http-server",
9+
"test": "set NODE_OPTIONS=--experimental-vm-modules && jest"
10+
},
11+
"repository": {
12+
"type": "git",
13+
"url": "git+https://github.com/CodeYourFuture/CYF-Coursework-Template.git"
14+
},
15+
"bugs": {
16+
"url": "https://github.com/CodeYourFuture/CYF-Coursework-Template/issues"
17+
},
18+
"homepage": "https://github.com/CodeYourFuture/CYF-Coursework-Template#readme",
19+
"devDependencies": {
20+
"http-server": "^14.1.1",
21+
"jest": "^30.0.4"
22+
}
23+
}

Sprint-3/todo-list/script.js

Lines changed: 0 additions & 25 deletions
This file was deleted.

0 commit comments

Comments
 (0)