Skip to content

test: migrate from jest to node:test runner#265

Merged
arb merged 2 commits into
masterfrom
test/260-migrate-jest-to-node-test
May 1, 2026
Merged

test: migrate from jest to node:test runner#265
arb merged 2 commits into
masterfrom
test/260-migrate-jest-to-node-test

Conversation

@arb

@arb arb commented May 1, 2026

Copy link
Copy Markdown
Owner

Tracks #260. First step in evaluating a move off Jest, prompted by Jest's slowing release cadence. This PR keeps the framework decision narrow: swap the harness with the smallest possible test-body churn, document the tradeoffs, and let the rest of #260 weigh whether to stick with node:test or revisit Vitest as a follow-up.

What changed

  • Runner: node --test (Node's built-in test runner; no --experimental-vm-modules flag needed anymore).
  • Assertions: the standalone expect package — the same code Jest ships internally — so the ~240 existing expect(...) call sites stay verbatim.
  • Mocks: jest.fn()mock.fn() from node:test. The 10 .toHaveBeenCalled() sites became .mock.callCount() checks because the standalone expect matchers expect Jest-mock shape that node:test mocks don't provide.
  • Parameterization: 4 describe.each template-literal tables rewritten as plain for...of loops.
  • Snapshots: 4 toMatchSnapshot() sites inlined as literal expect(...).toEqual(...) assertions. The Map snapshot was rewritten as targeted .message assertions instead of a structural equality check, because joi.ValidationError instances carry internal state that makes deep equality fragile.
  • is-ci-cli is preserved — the local-watch / CI-one-shot UX is unchanged.

Coverage tooling (key #260 data point)

node --test doesn't enforce coverage thresholds and the existing coverage job in .github/workflows/ci.yml consumes ./coverage/lcov.info for Codecov. To preserve both today's 100% threshold gate and the lcov upload, this PR adds c8 as a devDep and runs c8 --reporter=lcov --reporter=text --100 node --test test/ under test:ci.

This is the single biggest gap between node:test and Jest for this repo: Jest had threshold enforcement built in; node:test requires a separate tool (c8) or a custom parser to get the same gate. Worth weighing in #260 against alternatives like Vitest, which bundles coverage + thresholds natively.

Net dep change

  • Removed: jest (and its tree)
  • Added: expect@30.x.x, c8@10.x.x
  • node_modules net change: -178 packages, +6 packages

Support matrix

Unchanged. engines: ">=20" stays, .github/workflows/ci.yml matrix (Node 20.x/22.x/24.x/25.x × Express 4/5) stays. Verified locally on Node 20.19 (matrix floor): 62 tests pass, 100% coverage, coverage/lcov.info produced, eslint clean.

Made with Cursor

Swap the test harness from Jest to Node's built-in test runner. Tests
are kept close to verbatim by using the standalone `expect` package for
assertions; coverage moves to `c8` to preserve the existing 100% gate
and lcov output for the Codecov upload.

- Imports updated to node:test + expect across both test files
- describe.each blocks rewritten as for...of loops
- jest.fn() / .toHaveBeenCalled() converted to mock.fn() / mock.callCount()
- 4 toMatchSnapshot calls inlined as literal assertions; .snap deleted
- Net -178 / +6 packages in node_modules
- engines, support matrix, and runtime API unchanged

Refs #260

Co-authored-by: Cursor <cursoragent@cursor.com>
@arb arb added this to the 16.0.0 milestone May 1, 2026
Node 22.x changed how the test runner CLI handles directory args:
passing `test/` is interpreted as a single module path instead of
recursing, breaking with `Cannot find module '.../test'`. Switch to
`test/*.test.js` (shell-expanded) which works consistently across
Node 20.x through 25.x.

Co-authored-by: Cursor <cursoragent@cursor.com>
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (b36068f) to head (7dad645).
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##            master      #265    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files            4         5     +1     
  Lines          100       263   +163     
  Branches        14         0    -14     
==========================================
+ Hits           100       263   +163     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@arb arb merged commit c07d3c1 into master May 1, 2026
9 checks passed
@cjihrig

cjihrig commented May 2, 2026

Copy link
Copy Markdown
Contributor

@arb is my hero.

By the way, node:test does support snapshots and code coverage (it's listed as experimental, but that is mostly just in name at this point).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants