测试 Rspack

Rspack 的测试用例包括以下内容

  • Rspack 核心测试用例存储在 packages/rspack-test-tools/tests 文件夹中,并将通过模拟构建过程运行测试用例。 通常情况下,应该在这个文件夹中添加测试用例。
  • 其他 Rspack 包的测试用例存储在 packages/{name}/tests 文件夹中,仅在修改该包时添加或修改这些测试用例。

运行测试

您可以通过以下方式运行这些测试用例

  • 从根目录运行 ./x test unitpnpm 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
    • 例如 npm run test -- -t config/asset 只运行 packages/rspack-test-tools/configCases/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) 是否正常运行。 此类型包括具有固定 target=async-node 的 HotNode,具有固定 target=web 的 HotWeb,以及具有固定 target=webworker 的 HotWorker。
  • 热更新快照: 用于测试 HMR 是否可以生成正确的中间产物。 此测试类型与 Hot 类型共享测试用例,并为每次 HMR 生成增量产物的快照。
  • 监听: 用于测试在监听模式下修改文件后的增量编译。
  • 统计输出: 用于测试构建结束后控制台输出日志。
  • 统计 API: 用于测试构建结束后生成的 Stats 对象。
  • 诊断: 用于测试构建过程中生成的警告/错误的格式化输出信息。
  • 哈希: 用于测试哈希生成是否正常工作。
  • 编译器: 用于测试 Compiler/Compilation 对象 API。
  • 默认值: 用于测试配置选项之间的交互。
  • 错误: 用于测试 compilation.errorscompilation.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};

热更新

测试入口 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
默认配置 热更新 相同
运行输出

使用与 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 参数来更新这些用例的快照。

统计 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文件,并在构建完成后指定一个validate()方法来检查stats对象中的哈希信息。

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

入口文件 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扩展名的文件的快照