ECMAScript模块
注意
Jest 提供对 ES 模块(ESM) 的 实验性支持。
它的实现可能存在缺少一些特性支持或存在一些 bug。 最新状态请在 issue 板块查看 对应的 issue 与 label。
另外需要注意的是 Jest 使用的是 实验性的 Node API 实现的 ESM 支持(截至 v18.8.0
)。
With the warnings out of the way, this is how you activate ESM support in your tests.
Ensure you either disable code transforms by passing
transform: {}
or otherwise configure your transformer to emit ESM rather than the default CommonJS (CJS).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 库来设置环境变量。
如果使用 yarn,可以运行
yarn node --experimental-vm-modules $(yarn bin jest)
。 如果是使用 Yarn Plug’n’Play 这条命令同样可用。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.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.If you want to treat other file extensions (such as
.jsx
or.ts
) as ESM, please use the extensionsToTreatAsEsm option.
Differences between ESM and CommonJS
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. 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
Module mocking in ESM
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.
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.
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.
For mocking CJS modules, you should continue to use jest.mock
. See the example below:
main.cjs
const {BrowserWindow, app} = require('electron');
// etc.
module.exports = {example};
main.test.cjs
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.