Skip to content

Commit 5a79654

Browse files
committed
tests: add JSDOM test env, comprehensive unit tests for frontend utils/state, and e2e screenshots
- Add JSDOM-based test environment to support browser APIs in Node: - tests/unit/setup.mjs - Creates a JSDOM document and exposes window/document/globals - Provides a minimal crypto implementation (randomUUID + getRandomValues) - Cleans up dom.window on process exit - Enable ESM for unit tests: - tests/unit/package.json ({"type":"module"}) - Add extensive unit tests for frontend state management: - tests/unit/test-state.mjs - Verifies state object shape (historicalEntries, predefinedSuggestions, activeTimers, timerInterval, activeChartInstances) - Tests calculateElapsedMs for paused/running timers, accumulated time, clock skew, very long durations - Tests hasRunningTimers in multiple scenarios - Tests clearTimerInterval behavior and safety - Add extensive unit tests for utility functions: - tests/unit/test-utils.mjs - formatDuration: many cases (seconds, minutes, hours, large values) - sanitizeInput: trimming, removal of dangerous chars, length limiting, unicode and edge cases - generateUUID: v4 format validation and uniqueness checks - getRunningTasksKey: normalization/casing tests - getDistinctColors: output shape, hex format, counts and behavior for large requests - showNotification presence check (DOM dependent) - Add e2e screenshot fixtures: - tests/screenshots/e2e/12-error-handling.png - tests/screenshots/e2e/13-csv-export.png - tests/screenshots/e2e/14-final-state.png - (binary images added to support visual regression / CI screenshot comparisons) Notes: - Tests are written using Node's builtin test/assert (node:test + node:assert). - setup.mjs should be imported before test modules that depend on browser globals. - This commit focuses on test infra and coverage; no production source changes included.
1 parent 097bf8a commit 5a79654

43 files changed

Lines changed: 2787 additions & 889 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/test.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: Test Suite
2+
3+
on:
4+
push:
5+
branches: [main, local_node_refactor]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
node-version: [18.x, 20.x]
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
21+
- name: Setup Node.js ${{ matrix.node-version }}
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: ${{ matrix.node-version }}
25+
26+
- name: Install dependencies
27+
run: npm install
28+
29+
- name: Run unit tests
30+
run: npm run test:unit
31+
32+
- name: Start server
33+
run: |
34+
npm start &
35+
echo $! > server.pid
36+
37+
- name: Wait for server
38+
run: |
39+
for i in {1..30}; do
40+
if curl -s http://localhost:13331/api/health > /dev/null; then
41+
echo "Server is ready"
42+
exit 0
43+
fi
44+
echo "Waiting for server... ($i/30)"
45+
sleep 2
46+
done
47+
echo "Server failed to start"
48+
exit 1
49+
50+
- name: Run backend API tests
51+
run: npm run test:api
52+
53+
- name: Run E2E tests
54+
run: HEADLESS=true npm run test:e2e
55+
56+
- name: Upload screenshots
57+
if: always()
58+
uses: actions/upload-artifact@v4
59+
with:
60+
name: test-screenshots-node-${{ matrix.node-version }}
61+
path: tests/screenshots/
62+
retention-days: 7
63+
64+
- name: Stop server
65+
if: always()
66+
run: |
67+
if [ -f server.pid ]; then
68+
kill $(cat server.pid) || true
69+
rm server.pid
70+
fi
71+
72+
- name: Upload test results
73+
if: failure()
74+
uses: actions/upload-artifact@v4
75+
with:
76+
name: test-failures-node-${{ matrix.node-version }}
77+
path: |
78+
mtt-*.json
79+
tests/**/*.log
80+
retention-days: 7

assets/010-ui_initial_load.png

79.4 KB
Loading

assets/020-ui_timer_with_notes.png

75.2 KB
Loading

assets/030-ui_error_validation.png

43.6 KB
Loading

assets/040-ui_reports_view.png

50.2 KB
Loading

docs/architecture.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,16 @@
124124

125125
- The system provides robust controls to handle `real-world workflow` interruptions
126126
- **Pause/Resume:**
127+
127128
- **Mechanism:** When paused, the `startTime` is nullified, and the elapsed time is stored in `accumulatedMs`
128129
- When resumed, `startTime` is set back to `Date.now()`
129130
- The state is saved to the server on each toggle
130131
- **UX:** Paused timers receive a visual indicator (`orange border`) and their buttons switch to `Resume`
132+
133+
- ![](/assets/020-ui_timer_with_notes.png)
134+
_Active timers display real-time duration and control buttons_
135+
_Paused timers show orange border and resume option_
136+
131137
- **Delete (Discard):** Allows users to remove accidental or incomplete timers from the active list without generating a permanent record
132138
- This action also syncs with the server
133139
- **Notes/Comments:** Each timer includes a textarea for adding detailed notes or comments
@@ -162,6 +168,15 @@
162168
- **Daily Time Logged (Bar Chart):** Shows total time logged for the last 7 days
163169
- **Color Consistency:** The `utils.js` module provides deterministic color generation ensuring the same project always gets the same color across charts
164170

171+
### 3.6. Input Validation & Error Handling
172+
173+
- The application provides clear, actionable error messages for invalid input
174+
- Empty or whitespace-only task names are rejected with helpful guidance
175+
- Error messages use color-coded styling (red for errors) for immediate recognition
176+
177+
![Error Validation](/assets/030-ui_error_validation.png)
178+
_Clear error messages guide users to correct input issues_
179+
165180
## 4. Implementation Details
166181

167182
### 4.1. Modular Frontend Architecture

docs/setup.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
- The **Multi-Task Time Tracker (MTTT)** runs as a local application on your machine using Node.js
44
- The application features a modular architecture with robust error handling to ensure your data remains private and provides a consistent experience across all browsers
55

6+
![](/assets/010-ui_initial_load.png)
7+
_The clean, Material Design-inspired interface after setup_
8+
69
## 1. Prerequisites
710

811
- **Node.js:** You must have Node.js installed on your system (v13 or higher recommended)
@@ -99,3 +102,9 @@ npm run backup
99102
- Save the file and simply refresh your browser window
100103
- The new suggestions will appear in the input dropdown
101104
- No server restart is required
105+
106+
## 7. Using the Application
107+
108+
Once running, you can track time across multiple projects simultaneously:
109+
110+
- ![](/assets/020-ui_timer_with_notes.png)

js/utils.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export const generateUUID = () => crypto.randomUUID();
4747
*/
4848
export const formatDuration = (seconds) => {
4949
const h = Math.floor(
50-
seconds / CONSTANTS.MS_PER_HOUR / CONSTANTS.MS_PER_SECOND
50+
seconds / (CONSTANTS.MS_PER_HOUR / CONSTANTS.MS_PER_SECOND)
5151
);
5252
const m = Math.floor(
5353
(seconds % (CONSTANTS.MS_PER_HOUR / CONSTANTS.MS_PER_SECOND)) /

mtt-active-state.json

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,18 @@
1-
{}
1+
{
2+
"fb7d1a5f-4489-4ad9-9a60-d4ec726b18df": {
3+
"project": "Demo Project",
4+
"task": "Task with Notes",
5+
"startTime": null,
6+
"accumulatedMs": 195282,
7+
"isPaused": true,
8+
"notes": "Mellow World!"
9+
},
10+
"753d9ee8-1cac-4784-b41c-f46349684c16": {
11+
"project": "Test Project",
12+
"task": "Test Task",
13+
"startTime": "2025-10-31T12:16:10.980Z",
14+
"accumulatedMs": 0,
15+
"isPaused": false,
16+
"notes": "Hello World!"
17+
}
18+
}

0 commit comments

Comments
 (0)