🌐 Mocha to Node.js Test Runner
将 Mocha 8.x 测试套件迁移到内置的 Node.js 测试运行器 (node:test,在 Node.js 22.x 和 24.x 中可用)。它会为文件使用的全局变量添加所需的 node:test 导入 (describe, it, before, after, beforeEach, afterEach),将 done 回调转换为 (t, done) 签名,把 this.skip() 重写为 t.skip(),this.timeout(N) 重写为 { timeout: N } 选项,并保留原有函数风格(它不会在 function() 和箭头函数之间转换)。同时支持 CommonJS 和 ESM 文件,并且之后会从 package.json 中移除 mocha 和 @types/mocha 依赖。
🌐 Migrates Mocha 8.x test suites to the built-in Node.js test runner (node:test, available in Node.js 22.x and 24.x). It adds the required node:test imports for the globals a file uses (describe, it, before, after, beforeEach, afterEach), converts done callbacks to the (t, done) signature, rewrites this.skip() to t.skip() and this.timeout(N) to { timeout: N } options, and preserves the original function style (it never converts between function() and arrow functions). Both CommonJS and ESM files are supported, and the mocha and @types/mocha dependencies are removed from package.json afterwards.
🌐 Usage
使用这个 codemod 运行:
🌐 Run this codemod with:
npx codemod @nodejs/mocha-to-node-test-runner🌐 Examples
🌐 Adding node:test imports (CommonJS)
一旦插入匹配的 require('node:test'),全局 describe/it 的使用就会继续有效;像 describe.skip 这样的修饰符已经兼容。
🌐 Global describe/it usage keeps working once the matching require('node:test') is inserted; modifiers like describe.skip are already compatible.
const assert = require('assert');
+const { describe, it } = require('node:test');
describe('Array', function() {
describe.skip('#indexOf()', function() {
it('should return -1 when the value is not present', function() {
const arr = [1, 2, 3];
assert.strictEqual(arr.indexOf(4), -1);
});
});
});🌐 Adding node:test imports (ESM)
在 ESM 文件中,改为插入一个 import 语句。
🌐 In ESM files an import statement is inserted instead.
import assert from 'assert';
+import { describe, it } from 'node:test';
describe('Array', function() {
describe.skip('#indexOf()', function() {
it('should return -1 when the value is not present', function() {🌐 Hooks
只有文件中实际使用的钩子会被添加到导入列表里。
🌐 Only the hooks actually used in the file are added to the import list.
const assert = require('assert');
const fs = require('fs');
+const { describe, before, after, it } = require('node:test');
describe('File System', () => {
before(function() {
fs.writeFileSync('test.txt', 'Hello, World!');
});
after(() => {
fs.unlinkSync('test.txt');
});🌐 done callbacks
Mocha 把 done 作为第一个回调参数传递;node:test 则先传递测试上下文,所以 (done) 就变成了 (t, done)。
🌐 Mocha passes done as the first callback argument; node:test passes the test context first, so (done) becomes (t, done).
const assert = require('assert');
+const { describe, it } = require('node:test');
describe('Callback Test', function() {
- it('should call done when complete', function(done) {
+ it('should call done when complete', function(t, done) {
setTimeout(() => {
assert.strictEqual(1 + 1, 2);
done();
}, 100);
});
});🌐 Skipping with this.skip()
this.skip() 变成 t.skip(),根据需要在回调签名中添加测试上下文参数 t。
const assert = require('assert');
+const { describe, it } = require('node:test');
describe('Skipped Test', () => {
it.skip('should not run this test', () => {
assert.strictEqual(1 + 1, 3);
});
- it('should also be skipped', () => {
- this.skip();
+ it('should also be skipped', (t) => {
+ t.skip();
assert.strictEqual(1 + 1, 3);
});
- it('should also be skipped 2', (done) => {
- this.skip();
+ it('should also be skipped 2', (t, done) => {
+ t.skip();
assert.strictEqual(1 + 1, 3);
});
});🌐 Timeouts
this.timeout(N) 调用套件和测试会移到 { timeout: N } 的选项参数里。
const assert = require('assert');
+const { describe, it } = require('node:test');
-describe('Timeout Test', function() {
- this.timeout(500);
+describe('Timeout Test', { timeout: 500 }, function() {
- it('should complete within 100ms', (done) => {
- this.timeout(100);
+ it('should complete within 100ms', { timeout: 100 }, (t, done) => {
setTimeout(done, 500); // This will fail
});
- it('should complete within 200ms', function(done) {
- this.timeout(200);
+ it('should complete within 200ms', { timeout: 200 }, function(t, done) {
setTimeout(done, 100); // This will pass
});
});🌐 Notes
- 转换完成后,codemod 会检测你的包管理器,并从
package.json中移除mocha和@types/mocha依赖。
🌐 Limitations
node:test不支持 Mocha 的retry选项,所以依赖它的测试需要单独处理。