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.
对于模拟 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.