ECMAScript 模块
本页面由 PageTurner AI 翻译(测试版)。未经项目官方认可。 发现错误? 报告问题 →
了解上述警告后,以下是启用测试中 ESM 支持的方法。
-
确保通过传递
transform: {}禁用代码转换,或者将转换器配置 为输出 ESM 而非默认的 CommonJS(CJS)。 -
使用
--experimental-vm-modules参数执行node,例如:
node --experimental-vm-modules node_modules/jest/bin/jest.js
或
NODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules" npx jest等。在 Windows 系统中,可使用
cross-env设置环境变量。若使用 Yarn,可执行:
yarn node --experimental-vm-modules $(yarn bin jest)。
此命令同样适用于 Yarn Plug'n'Play 环境。若代码库包含从
*.wasm文件进行的 ESM 导入,则无需向node传递--experimental-wasm-modules。Jest 当前对 WebAssembly 导入的实现依赖于实验性 VM 模块,但这在未来可能改变。 -
此外,我们会尝试遵循
node激活 "ESM 模式" 的逻辑(例如检查package.json中的type字段或.mjs文件),详见其官方文档。 -
若需将其他文件扩展名(如
.jsx或.ts)视为 ESM,请使用extensionsToTreatAsEsm选项。
ESM 与 CommonJS 的差异
主要差异已在 Node.js 文档中说明。除文档提及的内容外,Jest 会向所有执行文件注入一个特殊变量 —— jest 对象。在 ESM 中访问此对象时,需从 @jest/globals 模块导入或使用 import.meta。
import {jest} from '@jest/globals';
jest.useFakeTimers();
// etc.
// alternatively
import.meta.jest.useFakeTimers();
// jest === import.meta.jest => true
ESM 中的模块模拟
由于 ESM 在解析代码前会先处理静态 import 语句,CommonJS 中 jest.mock 调用的提升机制在 ESM 中无效。要在 ESM 中模拟模块,需在 jest.mock 调用后使用 require 或动态 import() 加载被模拟模块 —— 此规则同样适用于加载被模拟模块的依赖模块。
ESM 模拟通过 jest.unstable_mockModule 实现。顾名思义,该 API 仍在开发中,请关注此问题获取更新。
jest.unstable_mockModule 的用法与 jest.mock 基本相同,主要区别在于:必须提供工厂函数,且该函数可以是同步或异步的:
import {jest} from '@jest/globals';
jest.unstable_mockModule('node:child_process', () => ({
execSync: jest.fn(),
// etc.
}));
const {execSync} = await import('node:child_process');
// etc.
ESM 中的模块取消模拟
export default () => {
return 'default';
};
export const namedFn = () => {
return 'namedFn';
};
import {jest, test} from '@jest/globals';
test('test esm-module', async () => {
jest.unstable_mockModule('./esm-module.js', () => ({
default: () => 'default implementation',
namedFn: () => 'namedFn implementation',
}));
const mockModule = await import('./esm-module.js');
console.log(mockModule.default()); // 'default implementation'
console.log(mockModule.namedFn()); // 'namedFn implementation'
jest.unstable_unmockModule('./esm-module.js');
const originalModule = await import('./esm-module.js');
console.log(originalModule.default()); // 'default'
console.log(originalModule.namedFn()); // 'namedFn'
/* !!! WARNING !!! Don`t override */
jest.unstable_mockModule('./esm-module.js', () => ({
default: () => 'default override implementation',
namedFn: () => 'namedFn override implementation',
}));
const mockModuleOverride = await import('./esm-module.js');
console.log(mockModuleOverride.default()); // 'default implementation'
console.log(mockModuleOverride.namedFn()); // 'namedFn implementation'
});
模拟 CommonJS 模块
对于模拟 CommonJS 模块,应继续使用 jest.mock。参考以下示例:
const {BrowserWindow, app} = require('electron');
// etc.
module.exports = {example};
import {createRequire} from 'node:module';
import {jest} from '@jest/globals';
const require = createRequire(import.meta.url);
jest.mock('electron', () => ({
app: {
on: jest.fn(),
whenReady: jest.fn(() => Promise.resolve()),
},
BrowserWindow: jest.fn().mockImplementation(() => ({
// partial mocks.
})),
}));
const {BrowserWindow} = require('electron');
const exported = require('./main.cjs');
// alternatively
const {BrowserWindow} = (await import('electron')).default;
const exported = await import('./main.cjs');
// etc.