ECMAScript 模块
Jest 附带了对 ECMAScript 模块 (ESM) 的实验性支持。
¥Jest ships with experimental support for ECMAScript Modules (ESM).
该实现可能存在错误并且缺乏功能。有关最新状态,请查看问题跟踪器上的 issue 和 label。
¥The implementation may have bugs and lack features. For the latest status check out the issue and the label on the issue tracker.
另请注意,Jest 用于实现 ESM 支持的 API 仍然是 Node 认为是实验性的(截至版本 18.8.0
)。
¥Also note that the APIs Jest uses to implement ESM support are still considered experimental by Node (as of version 18.8.0
).
消除警告后,这就是你在测试中激活 ESM 支持的方法。
¥With the warnings out of the way, this is how you activate ESM support in your tests.
-
确保你通过传递
transform: {}
来禁用 代码转换,或者以其他方式配置你的转换器以触发 ESM 而不是默认的 CommonJS (CJS)。¥Ensure you either disable code transforms by passing
transform: {}
or otherwise configure your transformer to emit ESM rather than the default CommonJS (CJS). -
执行
node
和--experimental-vm-modules
,例如node --experimental-vm-modules node_modules/jest/bin/jest.js
或NODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules" npx jest
等¥Execute
node
with--experimental-vm-modules
, e.g.node --experimental-vm-modules node_modules/jest/bin/jest.js
orNODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules" npx jest
etc.在 Windows 上,你可以使用
cross-env
来设置环境变量。¥On Windows, you can use
cross-env
to be able to set environment variables.如果使用 Yarn,则可以使用
yarn node --experimental-vm-modules $(yarn bin jest)
。如果你使用 Yarn Plug'n'Play,此命令也将起作用。¥If you use Yarn, you can use
yarn node --experimental-vm-modules $(yarn bin jest)
. This command will also work if you use Yarn Plug'n'Play.如果你的代码库包含从
*.wasm
文件的 ESM 导入,则无需将--experimental-wasm-modules
传递到node
。目前 Jest 中 WebAssembly 导入的实现依赖于实验性 VM 模块,但是,这种情况将来可能会发生变化。¥If your codebase includes ESM imports from
*.wasm
files, you do not need to pass--experimental-wasm-modules
tonode
. Current implementation of WebAssembly imports in Jest relies on experimental VM modules, however, this may change in the future. -
除此之外,我们尝试遵循
node
的逻辑来激活 "ESM 模式"(例如在package.json
或.mjs
文件中查看type
),详细信息请参见 他们的文档。¥Beyond that, we attempt to follow
node
's logic for activating "ESM mode" (such as looking attype
inpackage.json
or.mjs
files), see their docs for details. -
如果你想将其他文件扩展名(例如
.jsx
或.ts
)视为 ESM,请使用extensionsToTreatAsEsm
选项。¥If you want to treat other file extensions (such as
.jsx
or.ts
) as ESM, please use theextensionsToTreatAsEsm
option.
ESM 和 CommonJS 之间的差异
¥Differences between ESM and CommonJS
大多数差异都在 Node 的文档 中进行了解释,但除了那里提到的内容之外,Jest 还向所有执行的文件中注入了一个特殊变量 - jest
对象。要在 ESM 中访问该对象,你需要从 @jest/globals
模块导入它或使用 import.meta
。
¥Most of the differences are explained in Node's documentation, but in addition to the things mentioned there, Jest injects a special variable into all executed files - the jest
object. To access this object in ESM, you need to import it from the @jest/globals
module or use import.meta
.
import {jest} from '@jest/globals';
jest.useFakeTimers();
// etc.
// alternatively
import.meta.jest.useFakeTimers();
// jest === import.meta.jest => true
ESM 中的模块模拟
¥Module mocking in ESM
由于 ESM 在查看代码之前评估静态 import
语句,因此 CJS 中发生的 jest.mock
调用提升对于 ESM 不起作用。要在 ESM 中模拟模块,你需要在 jest.mock
调用后使用 require
或动态 import()
来加载模拟模块 - 这同样适用于加载模拟模块的模块。
¥Since ESM evaluates static import
statements before looking at the code, the hoisting of jest.mock
calls that happens in CJS won't work for ESM. To mock modules in ESM, you need to use require
or dynamic import()
after jest.mock
calls to load the mocked modules - the same applies to modules which load the mocked modules.
通过 jest.unstable_mockModule
支持 ESM 模拟。顾名思义,该 API 仍在开发中,请关注 这个问题 获取更新。
¥ESM mocking is supported through jest.unstable_mockModule
. As the name suggests, this API is still work in progress, please follow this issue for updates.
jest.unstable_mockModule
的用法与 jest.mock
基本相同,但有两点不同:工厂函数是必需的,它可以是同步的或异步的:
¥The usage of jest.unstable_mockModule
is essentially the same as jest.mock
with two differences: the factory function is required and it can be sync or async:
import {jest} from '@jest/globals';
jest.unstable_mockModule('node:child_process', () => ({
execSync: jest.fn(),
// etc.
}));
const {execSync} = await import('node:child_process');
// etc.
对于模拟 CJS 模块,你应该继续使用 jest.mock
。请参阅下面的示例:
¥For mocking CJS modules, you should continue to use jest.mock
. See the example below:
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.