メインコンテンツへスキップ
Version: Next

ECMAScript モジュール

caution

Jest は ECMAScript モジュール (ESM) の実験的なサポートを提供しています。

実装にはバグや機能不足がある可能性があります。 最新のステータスについては、issue トラッカーの issuelabel を確認してください。

また、Jest が ESM サポートを実装するのに使用している API は、まだ Node により実験的であるとされていることに注意してください (バージョン 18.8.0 時点)。

With the warnings out of the way, this is how you activate ESM support in your tests.

  1. transform: {} を渡すことで、コード変換を無効にするか、デフォルトの CommonJS (CJS) ではなく ESM を出力するように変換を設定します。

  2. Execute node with --experimental-vm-modules, e.g. node --experimental-vm-modules node_modules/jest/bin/jest.js or NODE_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 to node. Current implementation of WebAssembly imports in Jest relies on experimental VM modules, however, this may change in the future.

  3. それ以外は node が「ESM モード」を有効にするロジック (たとえば、package.jsontype や、.mjs ファイルであるかを確認するなど) に従うように努めています。詳細については、node のドキュメントを確認してください。

  4. 他のファイル拡張子 (.jsx.ts など) を ESM として扱いたい場合は、extensionsToTreatAsEsm オプション を使用してください。

ESM と 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 or use import.meta.

import {jest} from '@jest/globals';

jest.useFakeTimers();

// etc.

// または
import.meta.jest.useFakeTimers();

// jest === import.meta.jest => true

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(() => ({
// 部分的なモック
})),
}));

const {BrowserWindow} = require('electron');
const exported = require('./main.cjs');

// または
const {BrowserWindow} = (await import('electron')).default;
const exported = await import('./main.cjs');

// etc.