跳至主要內容
版本:29.7

程式碼轉換

Jest 以 JavaScript 執行專案中的程式碼,但如果您使用某些 Node 原生不支援的語法(例如 JSX、TypeScript、Vue 範本),則需要將該程式碼轉換為純 JavaScript,類似於您在為瀏覽器建置時所執行的動作。

Jest 透過 transform 設定選項支援此功能。

轉換器是一個提供轉換原始檔方法的模組。例如,如果您想在模組或測試中使用 Node 尚未支援的新語言功能,則可以插入一個程式碼預處理器,將未來版本的 JavaScript 轉譯成目前的版本。

Jest 會快取轉換結果,並嘗試根據多項因素(例如待轉換檔案的來源和變更設定)使該結果失效。

預設值

Jest 內建一個轉譯器 – babel-jest。它會載入專案的 Babel 組態,並轉譯任何符合 /\.[jt]sx?$/ RegExp 的檔案(換句話說,任何 .js.jsx.ts.tsx 檔案)。此外,babel-jest 會注入 ES 模組模擬中提到的模擬提升所需的 Babel 外掛。

提示

如果你想將預設的 babel-jest 轉譯器與其他程式碼預處理器一起使用,請記得明確包含它

"transform": {
"\\.[jt]sx?$": "babel-jest",
"\\.css$": "some-css-transformer",
}

撰寫自訂轉譯器

你可以撰寫自己的轉譯器。轉譯器的 API 如下

interface TransformOptions<TransformerConfig = unknown> {
supportsDynamicImport: boolean;
supportsExportNamespaceFrom: boolean;
/**
* The value is:
* - `false` if Jest runs without Node ESM flag `--experimental-vm-modules`
* - `true` if the file extension is defined in [extensionsToTreatAsEsm](Configuration.md#extensionstotreatasesm-arraystring)
* and Jest runs with Node ESM flag `--experimental-vm-modules`
*
* See more at https://jest.dev.org.tw/docs/next/ecmascript-modules
*/
supportsStaticESM: boolean;
supportsTopLevelAwait: boolean;
instrument: boolean;
/** Cached file system which is used by `jest-runtime` to improve performance. */
cacheFS: Map<string, string>;
/** Jest configuration of currently running project. */
config: ProjectConfig;
/** Stringified version of the `config` - useful in cache busting. */
configString: string;
/** Transformer configuration passed through `transform` option by the user. */
transformerConfig: TransformerConfig;
}

type TransformedSource = {
code: string;
map?: RawSourceMap | string | null;
};

interface SyncTransformer<TransformerConfig = unknown> {
canInstrument?: boolean;

getCacheKey?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => string;

getCacheKeyAsync?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => Promise<string>;

process: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => TransformedSource;

processAsync?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => Promise<TransformedSource>;
}

interface AsyncTransformer<TransformerConfig = unknown> {
canInstrument?: boolean;

getCacheKey?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => string;

getCacheKeyAsync?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => Promise<string>;

process?: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => TransformedSource;

processAsync: (
sourceText: string,
sourcePath: string,
options: TransformOptions<TransformerConfig>,
) => Promise<TransformedSource>;
}

type Transformer<TransformerConfig = unknown> =
| SyncTransformer<TransformerConfig>
| AsyncTransformer<TransformerConfig>;

type TransformerCreator<
X extends Transformer<TransformerConfig>,
TransformerConfig = unknown,
> = (transformerConfig?: TransformerConfig) => X;

type TransformerFactory<X extends Transformer> = {
createTransformer: TransformerCreator<X>;
};
注意

上述定義已為了簡潔而縮減。完整的程式碼可以在 GitHub 上的 Jest 儲存庫 中找到(請記得為你的 Jest 版本選擇正確的標籤/提交)。

有幾種方法可以將程式碼匯入 Jest - 使用 Common JS (require) 或 ECMAScript 模組 (import - 存在靜態和動態版本)。Jest 會根據需要透過程式碼轉譯傳遞檔案(例如,當評估 requireimport 時)。這個過程也稱為「轉譯」,可能會同步(在 require 的情況下)或非同步(在 importimport() 的情況下,後者也適用於 Common JS 模組)發生。因此,介面公開了非同步和同步處理程序的兩組方法:process{Async}getCacheKey{Async}。後者是用來找出我們是否需要呼叫 process{Async}

非同步轉譯如果未實作 `processAsync`,可以回退到同步 `process` 呼叫,但同步轉譯不能使用非同步 `processAsync` 呼叫。如果你的程式碼庫只有 ESM,實作非同步變數就足夠了。否則,如果有任何程式碼透過 `require` 載入(包括 ESM 中的 `createRequire`),則需要實作同步 `process` 變數。

請注意,`node_modules` 未使用預設設定轉譯,必須修改 `transformIgnorePatterns` 設定才能執行此動作。

與此半相關的是我們傳遞的支援旗標(請參閱上方的 `CallerTransformOptions`),但這些旗標應在轉譯中使用,以找出它應該傳回 ESM 或 CJS,且與同步與非同步無直接關係

雖然不是必需的,但我們強烈建議也實作 `getCacheKey`,這樣我們就不會在可以從磁碟讀取先前結果時浪費資源進行轉譯。你可以使用 @jest/create-cache-key-function 來協助實作。

與其讓你的自訂轉譯器直接實作 `Transformer` 介面,你可以選擇匯出 `createTransformer`,一個用於動態建立轉譯器的工廠函式。這是為了讓你的 jest 設定中有一個轉譯器設定。

注意

ECMAScript 模組 支援由傳入的 `supports*` 選項表示。特別是 `supportsDynamicImport: true` 表示轉譯器可以傳回 `import()` 表達式,這同時受到 ESM 和 CJS 支援。如果 `supportsStaticESM: true` 表示支援頂層 `import` 陳述式,且程式碼將被解釋為 ESM 而不是 CJS。請參閱 Node 的文件,了解差異的詳細資訊。

提示

請確定 `process{Async}` 方法傳回原始碼對應表以及轉譯後的程式碼,這樣才能在程式碼覆蓋率和測試錯誤中準確報告行資訊。內嵌原始碼對應表也可以使用,但速度較慢。

在開發轉譯器的過程中,使用 `--no-cache` 執行 Jest 可能會有用,以頻繁地 刪除快取

範例

帶類型檢查的 TypeScript

雖然 babel-jest 預設會轉譯 TypeScript 檔案,但 Babel 卻不會驗證類型。如果您想要驗證類型,可以使用 ts-jest

將影像轉換為其路徑

匯入影像是一種將影像包含在瀏覽器套件中的方式,但它們並非有效的 JavaScript。在 Jest 中處理影像的一種方式是將匯入的值替換為其檔名。

fileTransformer.js
const path = require('path');

module.exports = {
process(sourceText, sourcePath, options) {
return {
code: `module.exports = ${JSON.stringify(path.basename(sourcePath))};`,
};
},
};
jest.config.js
module.exports = {
transform: {
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'<rootDir>/fileTransformer.js',
},
};