🌐 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选项,所以依赖它的测试需要单独处理。