Skip to content

Commit 4df89d3

Browse files
committed
Modernize testing: migrate from Jest to node:test
Add a testing modernization plan and migrate test layout and CI to the new approach. Remove the legacy Jest config and delete legacy __tests__ artifacts, add a new top-level test/ suite with helpers (including test/helpers/env.js) and route test files, and update docs and CI to run the consolidated npm script (allTests) and expose targeted scripts (coreTests, existsTests, functionalTests). Dev dependencies and package metadata were adjusted to support the new runner/coverage tools.
1 parent 4aaff91 commit 4df89d3

28 files changed

Lines changed: 1641 additions & 5374 deletions

.github/workflows/cd_dev.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
- name: Install dependencies and run the test
5353
run: |
5454
npm install
55-
npm run functionalTests
55+
npm run allTests
5656
deploy:
5757
if: github.event.pull_request.draft == false
5858
needs:

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,14 @@ OPEN_API_CORS = false
3838

3939
Now, you can run tests
4040
```shell
41-
npm run runtest
41+
npm run allTests
42+
```
43+
44+
For fast local checks, run targeted suites:
45+
```shell
46+
npm run coreTests
47+
npm run existsTests
48+
npm run functionalTests
4249
```
4350

4451
And start the app

TESTING_MODERNIZATION_PLAN.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# TinyNode Testing Modernization Plan
2+
3+
## Goals
4+
5+
1. Move from Jest to Node's built-in test runner (`node:test`) without experimental VM flags.
6+
2. Keep ESM native across app and tests.
7+
3. Preserve existing test intent (`__core`, `__e2e`, `__exists`, `__mock_functions`) with a cleaner selection model.
8+
4. Separate API availability checks from API functionality checks.
9+
5. Convert `.testcase.md` descriptions into executable tests, then remove the markdown artifacts.
10+
6. Provide a reusable model for other repositories.
11+
12+
## Recommended Stack
13+
14+
- Test runner: `node:test`
15+
- Assertions/mocks: `node:assert/strict`, `node:test` mocks, plus explicit fakes
16+
- HTTP endpoint testing (in-memory app): `supertest`
17+
- Upstream HTTP mocking for `fetch`: `undici` `MockAgent` (preferred) or manual fetch stubs
18+
- Browser/UI tests: `playwright` (preferred over Puppeteer)
19+
- Coverage: `c8` (stable and CI-friendly)
20+
- Optional snapshots/matchers (only if needed): keep minimal, avoid framework lock-in
21+
22+
## Why Playwright Over Puppeteer
23+
24+
1. Better multi-browser support (Chromium, Firefox, WebKit).
25+
2. Strong test reliability features (auto-waiting, robust locators).
26+
3. Excellent CI support and diagnostics (trace viewer, screenshots, videos).
27+
4. Works cleanly with custom runners (including `node:test`) if desired.
28+
29+
## Target Test Architecture
30+
31+
Create a top-level `test/` folder and phase out `routes/__tests__/` over time:
32+
33+
- `test/unit/`:
34+
- Pure logic tests (`rest.js`, `tokens.js`, helper functions)
35+
- `test/integration/`:
36+
- Route behavior tests using `supertest` with app/router instances in memory
37+
- Strong mocking for upstream RERUM/network behavior
38+
- `test/contract/`:
39+
- API response shape and header contracts
40+
- Includes route registration/availability checks
41+
- `test/e2e/`:
42+
- Browser and user-flow checks (Playwright)
43+
- Minimal critical-path scenarios
44+
- `test/smoke/`:
45+
- Availability tests (is app up? are endpoints mounted?)
46+
- `test/fixtures/`:
47+
- Reusable payloads and canned upstream responses
48+
- `test/helpers/`:
49+
- App factories, env setup, temporary server lifecycle, mock helpers
50+
51+
## Important Architecture Adjustments
52+
53+
### 1) Dependency injection at router/app boundary
54+
55+
To avoid brittle module-level mocking, export route builders that accept dependencies.
56+
57+
Current pattern (hard import):
58+
- route imports `fetchRerum`, `checkAccessToken` directly.
59+
60+
Preferred pattern:
61+
- `buildCreateRouter({ fetchRerum, checkAccessToken, verifyJsonContentType })`
62+
- default export still uses production dependencies.
63+
- tests inject fake dependencies without test-runner-specific magic.
64+
65+
This is the highest-value structural change for reliable, portable tests.
66+
67+
### 2) Distinguish availability vs functionality
68+
69+
- Availability tests:
70+
- verify endpoint exists and returns expected method guards (e.g., 405 on wrong method)
71+
- should not depend on upstream services
72+
- Functionality tests:
73+
- verify request transformation, upstream call behavior, response body/headers/status
74+
- use mocked upstream behavior exhaustively
75+
76+
### 3) Keep environment control explicit
77+
78+
- Add dedicated test env setup (`test/helpers/env.js`) to set deterministic env vars.
79+
- Never rely on local `.env` for test behavior.
80+
- Ensure tests do not modify user `.env` files.
81+
82+
### 4) Reduce side effects in token handling tests
83+
84+
- Keep token-refresh behavior injectable or guarded so route tests do not fail due to malformed token state.
85+
86+
## Mapping Existing Tags to New Commands
87+
88+
Use path-based scripts and optional name filtering.
89+
90+
Suggested categories:
91+
92+
- `test:all` -> all suites
93+
- `test:core` -> `test/unit` + core integration contract tests
94+
- `test:exists` -> route registration + smoke availability tests
95+
- `test:functional` -> mocked integration tests
96+
- `test:e2e` -> browser tests and true end-to-end flows
97+
98+
For quick local runs, rely on folder-level script filters, not test framework internals.
99+
100+
## Migration Strategy (Incremental)
101+
102+
### Phase 1: Foundation
103+
104+
1. Add `test/` directory with helpers and one migrated sample suite.
105+
2. Add `node:test` scripts alongside existing Jest scripts.
106+
3. Add `c8` coverage command for new suites.
107+
108+
### Phase 2: Route Suite Migration
109+
110+
1. Migrate existing route tests from Jest to `node:test` one file at a time.
111+
2. Keep test names preserving current semantic tags during migration.
112+
3. Validate parity by running old/new suites together temporarily.
113+
114+
### Phase 3: Convert `.testcase.md` to Executable Specs
115+
116+
1. For each testcase markdown file, create corresponding test suite in `test/contract` or `test/integration`.
117+
2. Keep markdown as source-of-truth only during conversion.
118+
3. Remove `.testcase.md` once executable equivalent is merged.
119+
120+
### Phase 4: UI Coverage
121+
122+
1. Add Playwright and minimal smoke UI checks (page load, critical controls visible).
123+
2. Add one interaction test per major user action.
124+
3. Expand only for high-value user journeys.
125+
126+
### Phase 5: Decommission Jest
127+
128+
1. Remove Jest scripts/config/deps after parity is complete.
129+
2. Update docs and contributor workflow.
130+
131+
## CI/GitHub Actions Model
132+
133+
### Pull requests
134+
135+
Run fast and deterministic checks:
136+
137+
1. `test:core`
138+
2. `test:exists`
139+
3. `test:functional` (mocked only)
140+
141+
### Main branch / nightly
142+
143+
Run full quality gates:
144+
145+
1. `test:all`
146+
2. `test:e2e`
147+
3. coverage publish/report
148+
149+
### Suggested safeguards
150+
151+
- Fail fast on lint/type issues if enabled.
152+
- Upload Playwright traces on failure.
153+
- Keep browser tests isolated from unit/integration timing budgets.
154+
155+
## Proposed NPM Script Direction
156+
157+
(illustrative, final command syntax can be adjusted during implementation)
158+
159+
- `test:all` -> `node --test test/**/*.test.js`
160+
- `test:core` -> `node --test test/unit/**/*.test.js test/integration/**/*core*.test.js`
161+
- `test:exists` -> `node --test test/smoke/**/*.test.js test/contract/**/*exists*.test.js`
162+
- `test:functional` -> `node --test test/integration/**/*.test.js`
163+
- `test:e2e` -> `node --test test/e2e/**/*.test.js`
164+
- `coverage` -> `c8 node --test test/**/*.test.js`
165+
166+
## Risks and Mitigations
167+
168+
1. Risk: Migration churn while preserving behavior.
169+
- Mitigation: side-by-side execution and parity checks per suite.
170+
2. Risk: Mocking complexity around upstream fetch and token middleware.
171+
- Mitigation: dependency injection and helper factories.
172+
3. Risk: Browser test flakiness.
173+
- Mitigation: Playwright locators, fixed test data, no arbitrary sleeps.
174+
175+
## Immediate Next Steps
176+
177+
1. Implement Phase 1 scaffolding and scripts.
178+
2. Migrate one representative route suite (`create`) to validate architecture.
179+
3. Add CI job that runs both old and new tests until parity is complete.
180+
4. Begin converting `.testcase.md` files into executable suites.

0 commit comments

Comments
 (0)