跳至主要內容
版本:29.7

ECMAScript 模組

注意

Jest 附帶實驗性 ECMAScript 模組 (ESM) 支援。

實作可能會有錯誤且缺乏功能。如需最新狀態,請查看 問題 和問題追蹤器上的 標籤

另請注意,Jest 用於實作 ESM 支援的 API 仍 被 Node 視為實驗性(截至版本 18.8.0)。

在提出警告後,以下是您在測試中啟用 ESM 支援的方式。

  1. 確保您已停用 程式碼轉換,方法是傳遞 transform: {} 或以其他方式設定轉換器以發出 ESM 而非預設的 CommonJS (CJS)。

  2. 使用 --experimental-vm-modules 執行 node,例如 node --experimental-vm-modules node_modules/jest/bin/jest.jsNODE_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 匯入,您不需要--experimental-wasm-modules 傳遞給 node。Jest 中 WebAssembly 匯入的目前實作依賴於實驗性的 VM 模組,但這可能會在未來改變。

  3. 除此之外,我們嘗試遵循 node 啟用「ESM 模式」的邏輯(例如查看 package.json.mjs 檔案中的 type),請參閱 他們的說明文件 以取得詳細資訊。

  4. 如果您想將其他副檔名(例如 .jsx.ts)視為 ESM,請使用 extensionsToTreatAsEsm 選項

ESM 和 CommonJS 之間的差異

大多數的差異都說明在 Node 的說明文件 中,但除了那裡提到的內容之外,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 陳述式,因此 CJS 中發生的 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.

對於模擬 CJS 模組,您應該繼續使用 jest.mock。請參閱以下範例

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.