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

コードの変換

Jest はプロジェクト内のコードを JavaScript として実行しますが、Node でサポートされていない構文 (JSX、TypeScript、Vue のテンプレート) を使用している場合は、ブラウザ用にビルドする場合と同様に、コードをプレーンな JavaScript に変換する必要があります。

Jest は、このような変換を transform 設定オプションによりサポートしています。

transformer はソースファイルを変換するメソッドを提供するモジュールです。 たとえば、まだ Node ではサポートされていない新しい言語の機能をモジュールやテストで使用したい場合、将来の JavaScript のバージョンを現在のバージョンにトランスパイルするコードプリプロセッサをプラグインするかもしれません。

Jestは変換の結果をキャッシュし、変換されるファイルのソースや設定の変更など、多くの要因に基づいてその結果を無効にしようとします。

デフォルト

Jest は、1つの transformer – babel-jest を初めから同梱しています。 これはプロジェクトの Babel 設定を読み込み、/\.[jt]sx?$/ RegExp にマッチするすべてのファイル (言い換えると、すべての .js.jsx.ts.tsx ファイル) を変換します。 さらに、babel-jestES Module moking で説明した mock hoisting に必要な Babel プラグインを注入します。

tip

追加のコードプリプロセッサと併用したい場合、次のように、デフォルトの babel-jest transformer を明示的に含めることを忘れないでください。

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

カスタムの transformer を書く

You can write your own transformer. The API of a transformer is as follows:

interface TransformOptions<TransformerConfig = unknown> {
supportsDynamicImport: boolean;
supportsExportNamespaceFrom: boolean;
/**
* 値は次の通りです:
* - `false` - Jest を Node の ESM フラグ `--experimental-vm-modules` なしで実行する場合
* - `true` - ファイル拡張子が [extensionsToTreatAsEsm](Configuration.md#extensionstotreatasesm-arraystring) で定義されている場合
* そして、Jest は Node ESM フラグ `--experimental-vm-modules` を使用して実行されます
*
* 詳細については https://jestjs.io/docs/next/ecmascript-modules を参照してください
*/
supportsStaticESM: boolean;
supportsTopLevelAwait: boolean;
instrument: boolean;
/** 性能改善のために `jest-runtime` が利用するキャッシュされたファイルシステム */
cacheFS: Map<string, string>;
/** 現在実行中のプロジェクトの Jest の設定 */
config: ProjectConfig;
/** 文字列化されたバージョンの `config` - キャッシュの破棄に便利です。 */
configString: string;
/** ユーザーによって `transform` オプションに渡される Transformer の設定 */
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>;
};
note

The definitions above were trimmed down for brevity. Full code can be found in Jest repo on GitHub (remember to choose the right tag/commit for your version of Jest).

Jest にコードをインポートする方法はいくつかあります。Common JS (require) または ECMAScript モジュール (import - 静的および動的バージョンに存在する) を使用してください。 Jest passes files through code transformation on demand (for instance when a require or import is evaluated). This process, also known as "transpilation", might happen synchronously (in the case of require), or asynchronously (in the case of import or import(), the latter of which also works from Common JS modules). For this reason, the interface exposes both pairs of methods for asynchronous and synchronous processes: process{Async} and getCacheKey{Async}. The latter is called to figure out if we need to call process{Async} at all.

Asynchronous transpilation can fall back to the synchronous process call if processAsync is unimplemented, but synchronous transpilation cannot use the asynchronous processAsync call. If your codebase is ESM only, implementing the async variants are sufficient. Otherwise, if any code is loaded through require (including createRequire from within ESM), then you need to implement the synchronous process variant.

Be aware that node_modules is not transpiled with default config, the transformIgnorePatterns setting must be modified in order to do so.

Semi-related to this are the supports flags we pass (see CallerTransformOptions above), but those should be used within the transform to figure out if it should return ESM or CJS, and has no direct bearing on sync vs async

Though not required, we highly recommend implementing getCacheKey as well, so we do not waste resources transpiling when we could have read its previous result from disk. You can use @jest/create-cache-key-function to help implement it.

Instead of having your custom transformer implement the Transformer interface directly, you can choose to export createTransformer, a factory function to dynamically create transformers. This is to allow having a transformer config in your jest config.

note

ECMAScript モジュール サポートは、supports* オプションに渡された値で示されます。 Specifically supportsDynamicImport: true means the transformer can return import() expressions, which is supported by both ESM and CJS. If supportsStaticESM: true it means top level import statements are supported and the code will be interpreted as ESM and not CJS. See Node's docs for details on the differences.

tip

Make sure process{Async} method returns source map alongside with transformed code, so it is possible to report line information accurately in code coverage and test errors. Inline source maps also work but are slower.

During the development of a transformer it can be useful to run Jest with --no-cache to frequently delete cache.

コーディング例

型チェック付きTypeScript

babel-jestはデフォルトでTypeScriptファイルをトランスパイルしますが、Babelはタイプを検証しません。 そうしたい場合は、 ts-jestを使うことができます。

画像をパスに変換する

画像のインポートは、ブラウザのバンドルに含める1つの方法ですが、有効な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',
},
};