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

コード変換

非公式ベータ版翻訳

このページは PageTurner AI で翻訳されました(ベータ版)。プロジェクト公式の承認はありません。 エラーを見つけましたか? 問題を報告 →

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

Jestはこの機能をtransform設定オプションでサポートしています。

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

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

デフォルト設定

Jestはデフォルトで1つのトランスフォーマーを同梱しています – babel-jestです。これはプロジェクトのBabel設定を読み込み、/\.[jt]sx?$/正規表現に一致するファイル(つまり.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://jestjs.io/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にコードをインポートする方法には主に2通りあります - 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文がサポートされ、コードがCJSではなくESMとして解釈されることを意味します。差異の詳細はNode.jsのドキュメントを参照してください。

ヒント

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