Rspackのテスト

Rspackのテストケースには以下が含まれます

  • Rspackコアのテストケースは、`packages/rspack-test-tools/tests`フォルダに格納されており、ビルドプロセスをシミュレートしてテストケースを実行します。一般的に、テストケースはこのフォルダに追加する必要があります。
  • 他のRspackパッケージのテストケースは、`packages/{name}/tests`フォルダに格納されており、そのパッケージを変更する場合のみ追加または変更する必要があります。

テストの実行

これらのテストケースは、以下の方法で実行できます。

  • ルートディレクトリから`./x test unit`または`pnpm run test:unit`を実行します。
  • または、`packages/rspack-test-tools`ディレクトリから`npm run test`を実行します。
  • スナップショットを更新するには、`packages/rspack-test-tools`ディレクトリから`npm run test -- -u`を実行します。
  • 特定のjest cli引数を渡すには、`packages/rspack-test-tools`ディレクトリから`npm run test -- {args}`を実行します。
  • 特定のテストケースをフィルタリングするには、`packages/rspack-test-tools`ディレクトリから`npm run test -- -t path-of-spec`を実行します。
    • `packages/rspack-test-tools/configCases/asset`フォルダのテストケースのみを実行するには、`npm run test -- -t config/asset`のように実行します(configは自動的にconfigCasesにマッピングされ、他のフォルダも同様の方法で動作します)。

ディレクトリ構造

`packages/rspack-test-tools/tests`フォルダの構造は以下のとおりです。

.
├── js # Used to store build artifacts and temporary files
├── __snapshots__ # Used to store test snapshots
├── {Name}.test.js # Entry for normal testing
├── {Name}.hottest.js # Entry for hot snapshot testing
├── {Name}.difftest.js # Entry for diff testing
├── {name}Cases # Directory to store test cases
└── fixtures # General test files

`{Name}.test.js`はテストのエントリファイルであり、`{name}Cases`フォルダを走査してその中のケースを実行します。そのため、テストケースを追加または変更する必要がある場合は、テストの種類に基づいて関連する`{name}Cases`フォルダに追加します。

テストの種類

既存のテストの種類は以下のとおりです。

  • 標準:設定変更なしでコアビルドプロセスをテストするために使用します。`rspack.config.js`を追加する必要がないテストの場合に使用します。
  • 設定:ビルド設定オプションをテストするために使用します。テストで`rspack.config.js`を介して追加された特定の設定が必要で、他のシナリオに当てはまらない場合は、このテストの種類を使用します。
  • ホットモジュール置換(HMR):ホットモジュール置換(HMR)が正しく実行されるかどうかをテストするために使用します。このタイプには、固定`target=async-node`のHotNode、固定`target=web`のHotWeb、固定`target=webworker`のHotWorkerが含まれます。
  • ホットスナップショット:HMRが正しい中間アーティファクトを生成できるかどうかをテストするために使用します。このテストタイプはHotタイプとテストケースを共有し、各HMRの増分アーティファクトのスナップショットを生成します。
  • ウォッチ:ウォッチモードでファイルを修正した後の増分コンパイルをテストするために使用します。
  • 統計出力:ビルド終了後のコンソール出力ログをテストするために使用します。
  • 統計API:ビルド終了後に生成されたStatsオブジェクトをテストするために使用します。
  • 診断:ビルドプロセス中に生成された警告/エラーのフォーマットされた出力情報をテストするために使用します。
  • ハッシュ:ハッシュ生成が正しく機能するかどうかをテストするために使用します。
  • コンパイラ:Compiler/CompilationオブジェクトAPIをテストするために使用します。
  • デフォルト:設定オプション間の相互作用をテストするために使用します。
  • エラー:`compilation.errors`と`compilation.warnings`間の相互作用をテストするために使用します。
  • フック:様々なフック機能をテストするために使用します。
  • ツリーシェイキング:ツリーシェイキング関連の機能をテストするために使用します。
  • ビルトイン:ビルトインネイティブ実装を持つプラグインをテストするために使用します。

上記のテストタイプ内でテストケースを追加することを優先してください。

標準

テストエントリ tests/Normal.test.js
ケースディレクトリ tests/normalCases
出力ディレクトリ tests/js/normal
デフォルト設定 NormalProcessor
実行出力 はい

ケースの書き方は通常のRspackプロジェクトと同じですが、`rspack.config.js`ファイルは含まれず、ビルドには提供された設定を使用します。

設定

テストエントリ tests/Config.test.js
ケースディレクトリ tests/configCases
出力ディレクトリ tests/js/config
デフォルト設定 ConfigProcessor
実行出力 はい

このテストケースは通常のRspackプロジェクトに似ています。`rspack.config.js`を追加してビルド設定を指定し、`test.config.js`を追加することでテスト中の様々な動作を制御できます。`test.config.js`ファイルの構造は以下のとおりです。

test.config.js
1type TConfigCaseConfig = {
2  noTest?: boolean; // Do not run the test output and end the test
3  beforeExecute?: () => void; // Callback before running the output
4  afterExecute?: () => void; // Callback after running the output
5  moduleScope?: (ms: IBasicModuleScope) => IBasicModuleScope; // Module context variables when running the output
6  findBundle?: (
7    // Function for obtaining output when running the output, can control the output at a finer granularity
8    index: number, // Compiler index in multi-compiler scenario
9    options: TCompilerOptions<T>, // Build configuration object
10  ) => string | string[];
11  bundlePath?: string[]; // Output file name when running the output (prior to findBundle)
12  nonEsmThis?: (p: string | string[]) => Object; // this object during CJS output runtime, defaults to current module's module.exports if not specified
13  modules?: Record<string, Object>; // Pre-added modules when running the output, will be prioritized when required
14  timeout?: number; // Timeout for the test case
15};
16
17/** @type {import("../../../..").TConfigCaseConfig} */
18module.exports = {
19  // ...
20};

ホットモジュール置換(HMR)

テストエントリ Hot{Target}.test.js
ケースディレクトリ tests/hotCases
出力ディレクトリ tests/js/hot-{target}
デフォルト設定 HotProcessor
実行出力 はい

このテストケースは通常のRspackプロジェクトに似ています。`rspack.config.js`を追加してビルド設定を指定できます。

また、変更されたファイル内では、`---`を使用して変更前後のコードを区切ります。

file.js
module.exports = 1; // Initial build
---
module.exports = 2; // First hot update
---
module.exports = 3; // Second hot update

テストケースコードでは、`NEXT`メソッドを使用してファイル変更のタイミングを制御し、その中にテストコードを追加します。

index.js
import value from './file';

it('should hot update', done => {
  expect(value).toBe(1);
  // Use packages/rspack-test-tools/tests/hotCases/update.js to trigger update
  NEXT(
    require('../../update')(done, true, () => {
      expect(value).toBe(2);
      NEXT(
        require('../../update')(done, true, () => {
          expect(value).toBe(3);
          done();
        }),
      );
    }),
  );
});

module.hot.accept('./file');

ホットスナップショット

テストエントリ HotSnapshot.hottest.js
ケースディレクトリ tests/hotCases
出力ディレクトリ tests/js/hot-snapshot
デフォルト設定 ホットモジュール置換(HMR)と同じ
実行出力 はい

`Hot{Target}`と同じテストケースを使用し、ケースフォルダに`__snapshots__/{target}/{step}.snap.txt`ファイルを作成して、各HMRの増分アーティファクトのスナップショットテストを実行します。

スナップショットの構造は以下のとおりです。

  • 変更されたファイル:このHMRビルドをトリガーしたソースコードファイル
  • アセットファイル:このHMRビルドのアーティファクトファイル
  • マニフェスト:このHMRビルドの`hot-update.json`メタデータファイルの内容。ここで
    • `"c"`:このHMRで更新されるチャンクのID
    • `"r"`:このHMRで削除されるチャンクのID
    • `"m"`:このHMRで削除されるモジュールのID
  • アップデート:このHMRビルドの`hot-update.js`パッチファイルに関する情報。これには
    • 変更されたモジュール:パッチに含まれるモジュールのリスト
    • 変更されたランタイムモジュール:パッチに含まれるランタイムモジュールのリスト
    • 変更されたコンテンツ:パッチコードのスナップショット

ウォッチ

エントリファイル Watch.test.js
ケースディレクトリ tests/watchCases
出力ディレクトリ tests/js/watch
デフォルト設定 WatchProcessor
実行出力 はい

ウォッチビルドは複数ステップで実行する必要があるため、`rspack.config.js`を追加してビルド設定を指定できます。そのケースのディレクトリ構造は特殊で、変更バッチを表すために増加する番号を使用します。

.
├── 0 # WATCH_STEP=0, initial code for the case
├── 1 # WATCH_STEP=1, diff files for the first change
├── 2 # WATCH_STEP=2, diff files for the second change
└── rspack.config.js

テストコードでは、`WATCH_STEP`変数を使用して、現在の変更バッチ番号を取得できます。

統計出力

テストエントリ StatsOutput.test.js
ケースディレクトリ tests/statsOutputCases
出力ディレクトリ tests/js/statsOutput
デフォルト設定 StatsProcessor
実行出力 いいえ

ケースの書き方は通常のRspackプロジェクトと同じです。実行後、コンソール出力情報はスナップショットにキャプチャされ、`rspack-test-tools/tests/__snapshots__/StatsOutput.test.js.snap`に保存されます。

ヒント

一部のStatsOutputテストケースにはハッシュが含まれているため、出力コードを変更する際は、-uパラメーターを使用してこれらのケースのスナップショットを更新してください。

Stats API

エントリファイル StatsAPI.test.js
ケースディレクトリ tests/statsAPICases
出力ディレクトリ なし
デフォルト設定 なし
実行出力 いいえ

このテストは、ビルドのソースコードとしてrspack-test-tools/tests/fixturesを使用するため、テストケースは単一ファイルとして記述されています。その構造は以下のとおりです。

{case}.js
1type TStatsAPICaseConfig = {
2  description: string, // Case description
3  options?: (context: ITestContext) => TCompilerOptions<T>, // Case build configuration
4  build?: (context: ITestContext, compiler: TCompiler<T>) => Promise<void>, // Case build method
5  check?: (stats: TCompilerStats<T>, compiler: TCompiler<T>) => Promise<void>, // Function to check the stats for the case
6};
7
8/** @type {import('../..').TStatsAPICaseConfig} */
9module.exports = {
10  // ...
11};

診断

エントリファイル Diagnostics.test.js
ケースディレクトリ tests/diagnosticsCases
出力ディレクトリ tests/js/diagnostics
デフォルト設定 DiagnosticProcessor
実行出力 いいえ

このテストケースは一般的なrspackプロジェクトと同様で、rspack.config.jsを追加することでビルド設定を指定できます。さらに、警告/エラーのスナップショットを保存するために、ケースディレクトリにstats.errファイルが追加されます。更新するには、-uパラメーターを使用してください。

ハッシュ

エントリファイル Hash.test.js
ケースディレクトリ tests/hashCases
出力ディレクトリ なし
デフォルト設定 HashProcessor
実行出力 いいえ

このテストケースは一般的なrspackプロジェクトと同様ですが、ケースディレクトリにtest.config.jsファイルを追加し、ビルドが完了した後にstatsオブジェクト内のハッシュ情報をチェックするvalidate()メソッドを指定します。

test.config.js
1type THashCaseConfig = {
2  validate?: (stats: TCompilerStats<T>) => void,
3};
4
5/** @type {import('../..').THashCaseConfig} */
6module.exports = {
7  // ...
8};

コンパイラ

エントリファイル Compiler.test.js
ケースディレクトリ tests/compilerCases
出力ディレクトリ なし
デフォルト設定 なし
実行出力 いいえ

このテストは、ビルドのソースコードとしてrspack-test-tools/tests/fixturesを使用するため、テストケースは単一ファイルとして記述されています。その構造は以下のとおりです。

{case.js}
1interface TCompilerCaseConfig {
2  description: string; // Description of the test case
3  options?: (context: ITestContext) => TCompilerOptions<T>; // Test case build configuration
4  compiler?: (context: ITestContext, compiler: TCompiler<T>) => Promise<void>; // How the compiler is created for the test case
5  build?: (context: ITestContext, compiler: TCompiler<T>) => Promise<void>; // Build method for the test case
6  check?: (
7    context: ITestContext,
8    compiler: TCompiler<T>,
9    stats: TCompilerStats<T>,
10  ) => Promise<void>; // Check function for the test case
11}
12
13/** @type {import('../..').TCompilerCaseConfig} */
14module.exports = {
15  // ...
16};

デフォルト

エントリファイル Defaults.test.js
ケースディレクトリ tests/defaultCases
出力ディレクトリ なし
デフォルト設定 なし
実行出力 いいえ

このテストは実際のビルドを実行しません。ビルド設定を生成し、デフォルト設定との違いを観察するだけです。基本的なデフォルト設定はスナップショットとしてrspack-test-tools/tests/__snapshots__/Defaults.test.js.snapに保存されます。

このテストは、ビルドのソースコードとしてrspack-test-tools/tests/fixturesを使用するため、テストケースは単一ファイルとして記述されています。その構造は以下のとおりです。

{case}.js
1interface TDefaultsCaseConfig {
2  description: string; // Description of the test case
3  cwd?: string; // process.cwd for generating the build configuration of the test case, default is the `rspack-test-tools` directory
4  options?: (context: ITestContext) => TCompilerOptions<ECompilerType.Rspack>; // Test case build configuration
5  diff: (
6    diff: jest.JestMatchers<Diff>,
7    defaults: jest.JestMatchers<TCompilerOptions<ECompilerType.Rspack>>,
8  ) => Promise<void>; // Differences from the default configuration
9}
10
11/** @type {import('../..').TDefaultsCaseConfig} */
12module.exports = {
13  // ...
14};

エラーテストの詳細を以下に示します。

エラー

エントリファイル Error.test.js
ケースディレクトリ tests/errorCases
出力ディレクトリ なし
デフォルト設定 ErrorProcessor
実行出力 いいえ

このテストは、ビルドのソースコードとしてrspack-test-tools/tests/fixturesを使用するため、テストケースは単一ファイルとして記述されています。その構造は以下のとおりです。

{case}.js
1interface TErrorCaseConfig {
2  description: string; // Description of the test case
3  options?: (
4    options: TCompilerOptions<T>,
5    context: ITestContext,
6  ) => TCompilerOptions<T>; // Test case configuration
7  build?: (context: ITestContext, compiler: TCompiler<T>) => Promise<void>; // Test case build method
8  check?: (stats: TStatsDiagnostics) => Promise<void>; // Function to check the test case
9}
10
11/** @type {import('../..').TErrorCaseConfig} */
12module.exports = {
13  // ...
14};

フック

エントリファイル Hook.test.js
ケースディレクトリ tests/hookCases
出力ディレクトリ なし
デフォルト設定 HookProcessor
実行出力 いいえ

このテストはフックの入出力記録し、hooks.snap.txtのスナップショットに保存します。最終的な製品コードのスナップショットはoutput.snap.txtに保存されます。

このテストは、ビルドのソースコードとしてrspack-test-tools/tests/fixturesを使用するため、テストケースは単一ファイルとして記述されています。その構造は以下のとおりです。

{case}/test.js
1interface THookCaseConfig {
2  description: string; // Description of the test case
3  options?: (
4    options: TCompilerOptions<T>,
5    context: ITestContext,
6  ) => TCompilerOptions<T>; // Test case configuration
7  compiler?: (context: ITestContext, compiler: TCompiler<T>) => Promise<void>; // Callback after creating the compiler instance
8  check?: (context: ITestContext) => Promise<void>; // Callback after the build is completed
9}
10
11/** @type {import("../../../..").THookCaseConfig} */
12module.exports = {
13  // ...
14};

ツリーシェイキング

エントリファイル TreeShaking.test.js
ケースディレクトリ tests/treeShakingCases
出力ディレクトリ tests/js/treeShaking
デフォルト設定 TreeShakingProcessor
実行出力 いいえ

このテストケースでは、設定は通常のrspackプロジェクトと同様です。rspack.config.jsを追加することでビルド設定を指定できますが、最終的な製品はスナップショットとして__snapshots__/treeshaking.snap.txtに保存されます。

組み込み

エントリファイル Builtin.test.js
ケースディレクトリ tests/builtinCases
出力ディレクトリ tests/js/builtin
デフォルト設定 BuiltinProcessor
実行出力 いいえ

このテストケースは通常のrspackプロジェクトと同様で、rspack.config.jsを追加することでビルド設定を指定できます。ただし、ディレクトリによっては、製品のスナップショットが異なり、__snapshots__/output.snap.txtに保存されます。

  • plugin-css: .css拡張子のファイルのスナップショット
  • plugin-css-modules: .css.js拡張子のファイルのスナップショット
  • plugin-html: .html拡張子のファイルのスナップショット
  • その他: .js拡張子のファイルのスナップショット