Skip to content

Commit ea97e4c

Browse files
committed
feat(blog): add mocha-to-node-test-runner migration guide
1 parent 0492dea commit ea97e4c

1 file changed

Lines changed: 137 additions & 0 deletions

File tree

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
---
2+
date: '2026-08-06T00:00:00.000Z'
3+
category: migrations
4+
title: Mocha to Node.js Test Runner
5+
layout: blog-post
6+
author: Xstoudi
7+
---
8+
9+
# Migrate from Mocha to the Node.js Test Runner
10+
11+
This codemod helps migrate test suites from [Mocha](https://mochajs.org/) to the built-in [Node.js test runner](https://nodejs.org/api/test.html). It updates common Mocha globals, imports the equivalent APIs from `node:test`, and helps projects reduce their dependency on an external test framework.
12+
13+
## Why doing this?
14+
15+
- **Native Support**: The Node.js test runner is built into Node.js, so many projects can run tests without installing Mocha.
16+
- **Lower Maintenance**: Removing Mocha can reduce dependency updates and framework-specific configuration.
17+
- **Standard Assertions**: The migration pairs naturally with `node:assert/strict`, which is also available in Node.js.
18+
- **Built-in CLI**: Tests can be run with `node --test`, including support for filtering, watch mode, concurrency, and reporters.
19+
20+
## Node.js Version Requirements
21+
22+
- Node.js v18.0.0 or later (Node.js test runner is available but marked experimental)
23+
- Node.js v20.0.0 or later (Node.js test runner is stable)
24+
25+
> If your package currently supports Node.js versions earlier than v18.0.0, you cannot migrate to the Node.js test runner without dropping support for those versions.
26+
> This requires bumping the major version of your package AND updating the engines field in your package.json to require Node.js >= v18.0.0.
27+
28+
## Supported Transformations
29+
30+
The codemod supports the most common Mocha testing APIs and converts them to their `node:test` equivalents:
31+
32+
- `describe()`
33+
- `it()`
34+
- `before()`
35+
- `after()`
36+
- `beforeEach()`
37+
- `afterEach()`
38+
- `.skip()`
39+
- `.only()`
40+
41+
It also inserts imports from `node:test` when a file relies on Mocha globals.
42+
43+
It also convert `this.timeout(N)` to `{ timeout: N }` options.
44+
45+
## Usage
46+
47+
The source code for this codemod can be found in the [mocha-to-node-test-runner directory](https://github.com/nodejs/userland-migrations/tree/main/recipes/mocha-to-node-test-runner).
48+
49+
You can find this codemod in the [Codemod Registry](https://app.codemod.com/registry/@nodejs/mocha-to-node-test-runner).
50+
51+
```bash
52+
npx codemod @nodejs/mocha-to-node-test-runner
53+
```
54+
55+
After running the codemod, update your test script to use the Node.js test runner:
56+
57+
```diff
58+
{
59+
"scripts": {
60+
- "test": "mocha"
61+
+ "test": "node --test"
62+
}
63+
}
64+
```
65+
66+
## Examples
67+
68+
### Basic Test Suite
69+
70+
```diff
71+
+ import { describe, it } from 'node:test';
72+
import assert from 'node:assert/strict';
73+
import { sum } from './sum.js';
74+
75+
describe('sum', () => {
76+
it('adds two numbers', () => {
77+
assert.equal(sum(2, 3), 5);
78+
});
79+
});
80+
```
81+
82+
### Lifecycle Hooks
83+
84+
```diff
85+
+ import { after, before, beforeEach, describe, it } from 'node:test';
86+
import assert from 'node:assert/strict';
87+
import { createServer } from './server.js';
88+
89+
describe('server', () => {
90+
let server;
91+
92+
before(async () => {
93+
server = await createServer();
94+
});
95+
96+
beforeEach(() => {
97+
server.reset();
98+
});
99+
100+
after(async () => {
101+
await server.close();
102+
});
103+
104+
it('responds with health status', async () => {
105+
const response = await server.inject('/health');
106+
107+
assert.equal(response.statusCode, 200);
108+
});
109+
});
110+
```
111+
112+
### Skipped and Focused Tests
113+
114+
```diff
115+
+ import { describe, it } from 'node:test';
116+
import assert from 'node:assert/strict';
117+
118+
describe('feature flags', () => {
119+
it.skip('handles a disabled flag', () => {
120+
assert.equal(isEnabled('new-flow'), false);
121+
});
122+
123+
it.only('handles an enabled flag', () => {
124+
assert.equal(isEnabled('stable-flow'), true);
125+
});
126+
});
127+
```
128+
129+
## Unsupported APIs
130+
131+
The codemod does not yet cover every Mocha feature. Projects that rely on custom reporters, root hook plugins, retries, `this.slow()`, or advanced Mocha configuration should review the transformed tests manually.
132+
133+
Mocha and the Node.js test runner also differ in their execution model, CLI options, and reporter configuration. After running the codemod, run the full test suite and review any project-specific test setup.
134+
135+
## Recognition
136+
137+
We would like to thank the maintainers of [Mocha](https://mochajs.org/) for their long-standing work on JavaScript testing and their contributions to the ecosystem.

0 commit comments

Comments
 (0)