メインコンテンツへスキップ
バージョン: 29.7

コード変換

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

Jestはtransform設定オプションを介してこれをサポートしています。

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

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

デフォルト値

Jestは、babel-jestという1つのトランスフォーマーを標準で提供しています。これはプロジェクトのバベル設定を読み込み、/\.[jt]sx?$/正規表現に一致する任意のファイル(つまり、任意の.js.jsx.ts、または.tsxファイル)を変換します。さらに、babel-jestESモジュールのモックで説明されているモックホイスティングに必要な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.dokyumento.jp/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には、CommonJS(require)またはECMAScriptモジュール(import - 静的および動的バージョンが存在します)を使用してコードをインポートする2つの方法があります。Jestは、(requireまたはimportが評価されたときなど)必要に応じてコード変換を通してファイルを渡します。このプロセス(「トランスパイル」とも呼ばれます)は、requireの場合には同期的にimportまたはimport()(後者はCommonJSモジュールからも機能します)の場合には非同期的に発生する可能性があります。このため、インターフェースは非同期プロセスと同期プロセスの両方のメソッドのペアを公開しています:process{Async}getCacheKey{Async}です。後者は、process{Async}を呼び出す必要があるかどうかを判断するために呼び出されます。

非同期トランスパイルは、processAsyncが実装されていない場合、同期のprocess呼び出しにフォールバックできますが、同期トランスパイルは非同期のprocessAsync呼び出しを使用できません。コードベースがESMのみの場合は、非同期バリアントを実装するだけで十分です。そうでない場合、require(ESM内からのcreateRequireを含む)を使用してコードがロードされる場合は、同期のprocessバリアントを実装する必要があります。

デフォルトの設定ではnode_modulesはトランスパイルされないことに注意してください。そうするには、transformIgnorePatterns設定を変更する必要があります。

これと関連しているのが、渡すsupportsフラグ(上記の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.jsのドキュメントを参照してください。

ヒント

process{Async}メソッドは、変換されたコードとともにソースマップを返すようにしてください。これにより、コードカバレッジとテストエラーで正確に行情報を報告できます。インラインソースマップも機能しますが、速度が遅くなります。

トランスフォーマーの開発中は、--no-cacheを使用してJestを実行し、頻繁にキャッシュを削除すると便利です。

型チェック付きTypeScript

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

画像をパスに変換

画像をインポートすると、ブラウザバンドルに含めることができますが、有効なJavaScriptではありません。Jestでこれを処理する1つの方法は、インポートされた値をファイル名に置き換えることです。

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',
},
};