For AI agents: the complete documentation index is available at /zh/llms.txt, the full documentation bundle is available at /zh/llms-full.txt, and this page is available as Markdown at /zh/config/test/pool.md.
close
  • 简体中文
  • pool

    • 类型:
    export type RstestPoolType = 'forks' | 'threads' | 'vmForks' | 'vmThreads';
    
    export type RstestPoolOptions = {
      /** 运行测试所用的 worker pool */
      type?: RstestPoolType;
      /** worker 数量上限或可用 CPU 的百分比 */
      maxWorkers?: number | string;
      /**
       * `vmForks` 或 `vmThreads` worker 完成一个测试文件后,如果报告的 V8 `heapUsed` 达到该阈值,
       * 则会在分配下一个文件前回收 worker。这是 worker 回收阈值,不是进程 RSS 的硬上限。
       * 支持字节数、百分比和单位字符串。
       * forks 在 isolate: false 时使用 RSS;VM pools 使用 V8 堆用量。
       * threads 和开启隔离的 forks 忽略此选项。
       * @default undefined(VM pool 使用 `系统内存 / maxWorkers`)
       */
      memoryLimit?: number | string;
      /** 向 worker 传递额外的 Node.js 参数。 */
      execArgv?: string[];
    };
    
    export type RstestConfig = {
      /** 运行测试所用的 worker pool */
      pool?: RstestPoolType | RstestPoolOptions;
    };
    • 默认值:
    const defaultPool = {
      type: 'forks',
      // maxWorkers 会根据 CPU 数量和运行模式自动计算
    };
    • CLI: --pool <type>--pool.type <type>--pool.maxWorkers <value>--pool.memoryLimit <limit>--pool.execArgv <arg>

    配置 Rstest 运行测试所用的 worker pool,包括隔离方式、并行度和内存回收阈值。

    如何选择 pool 类型

    建议先使用默认的 forks。它在四种 pool 中引入的执行限制最少,对 Node.js API 和 native addon 的兼容性更好。默认的 isolate: true 还会为每个测试文件创建独立进程,避免进程级状态在文件之间残留,并将原生崩溃的影响限制在子进程内。

    性能不符合预期时,先确认耗时集中在哪个阶段。可以使用 rstest-debugging skill 辅助排查,安装方式和分析方法见性能分析。如果瓶颈确实在 worker 启动或模块加载,再考虑下面的选择:

    场景可以尝试切换前需要确认
    单文件测试较短,worker 启动占用较多时间threads测试及依赖兼容 worker thread 的 API 和 native addon 限制
    文件较多,重复启动 worker、加载和编译依赖的成本较高vmThreads测试兼容 worker thread 和跨 realm 限制
    希望复用 worker,同时需要进程 API 或更容易控制内存压力vmForks测试能接受同一 worker 内的进程状态残留,以及跨 realm 限制

    VM pool 会复用 worker 和编译资源,因此测试文件多、setup 依赖较大时可能受益。不过,setup 文件、测试环境创建和模块求值仍会逐文件执行。如果主要耗时来自 setup 中的数据库初始化或网络请求,切换 VM pool 并不会省去这些工作。最终应以项目自身的耗时和内存测量结果为准。

    Pool 类型

    forksthreads 分别使用子进程和线程运行测试;vmForksvmThreads 则在复用这些 worker 的同时,为每个文件创建新的 vm.Context

    所有 pool 都需要将环境选项序列化后传给 worker,不支持在这些选项中传入函数。具体要求见 testEnvironment.options

    forks

    通过 child_process.fork 创建 Node.js 子进程,每个 worker 都有独立的进程内存和进程级状态。默认每个文件使用新进程;设置 isolate: false 后,多个文件可以复用同一个子进程。

    默认隔离模式下,每个文件都需要承担进程启动和初始化成本。

    CLI
    rstest.config.ts
    npx rstest --pool forks

    threads

    通过 node:worker_threads 运行测试。每个 worker 都有独立的 V8 isolate 和 heap,但所有线程共享同一个操作系统进程,RSS 反映的是整个进程的内存占用。

    相比子进程,线程通常启动更快,但有一些 Node.js API 限制。以下差异同时适用于 threadsvmThreads

    • 不支持 process.chdir()process.abort() 和修改用户或用户组 ID 的方法,也不能修改 process.title
    • process.on() 不会收到操作系统信号;process.exit() 只结束当前 worker thread。
    • native addon 必须支持在 worker thread 中使用,原生崩溃可能影响整个进程。

    完整差异见 Node.js Worker 文档

    CLI
    rstest.config.ts
    npx rstest --pool threads

    vmForks

    复用子进程,并为每个测试文件创建新的 vm.Context,减少反复启动进程的开销。process.chdir() 等进程 API 仍然可用,但同一子进程中的文件可能共享进程级状态。

    CLI
    rstest.config.ts
    npx rstest --pool vmForks

    vmThreads

    复用 worker thread,并为每个测试文件创建新的 vm.Context,减少反复启动线程的开销。它与 vmForks 提供相同的 VM 隔离,同时受上述 worker thread 限制。

    两种 VM pool 的隔离范围和兼容性要求见文末的 VM pool 的行为边界

    CLI
    rstest.config.ts
    npx rstest --pool vmThreads --pool.memoryLimit 256MB

    配置 worker 并行度和内存

    pool.maxWorkers

    pool.maxWorkers 决定同时运行多少个测试文件。测试会竞争同一个数据库、端口或 fixture 目录时,可以调低这个值,减少资源冲突。

    默认值会根据 CPU 数量和运行模式自动计算。你可以传入正整数,或传入可用 CPU 数量的百分比。

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      pool: {
        maxWorkers: 1,
      },
    });

    也可以通过 CLI 传入该配置:

    npx rstest --pool.maxWorkers 1

    常见取值:

    • 1:让测试文件逐个运行。这等价于 Vitest 的 fileParallelism: false 和 Jest 的 --runInBand
    • 50%:根据可用 CPU 数量按比例控制并行度,适合容量共享的 CI 机器。
    • 固定数字,如 4:将同时运行的 worker 数量限制为 4,不随机器的 CPU 数量变化。

    maxWorkers 控制的是文件级并行度。它不会限制单个测试文件内的 test.concurrent 用例;如需限制这类用例,请使用 maxConcurrency

    pool.memoryLimit

    VM worker 会连续运行多个文件,内存也可能随之增长。pool.memoryLimit 用于控制何时回收 worker:每个文件结束后,Rstest 会检查其 V8 heapUsed,达到阈值便回收,在新的 worker 中运行后续文件。

    vmForksvmThreads 的默认阈值为 系统内存 / maxWorkers

    对于 forks,只有在 isolate: false 且显式配置 memoryLimit 时,才会按子进程的 RSS 检查是否需要回收,默认不设限制。isolate: true 时,每个文件结束后都会销毁 fork worker,因此忽略此选项。普通 threads 也会忽略此选项,因为 RSS 反映的是整个进程的内存用量,无法用于判断单个线程的内存用量。

    可以使用以下格式指定阈值:

    • 数字:(0, 1] 表示系统内存的比例,大于 1 表示字节数。
    • 字符串:支持 %KBKiBMBMiBGBGiB,例如 '25%''256MB'

    例如,下面的配置最多运行 4 个 VM worker。每个文件结束后,heap 使用量达到 256MB 的 worker 会被回收:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      pool: {
        type: 'vmThreads',
        maxWorkers: 4,
        memoryLimit: '256MB',
      },
    });

    也可以通过 CLI 设置:

    npx rstest --pool vmThreads --pool.memoryLimit 256MB

    memoryLimit 只在文件之间触发回收,不是进程 RSS 的硬上限,也不能保证避免 OOM。

    它还会影响每个 VM worker 的缓存大小:不可变资源、external source、解析结果和编译数据共用一份缓存,上限取 64 MiB 与 memoryLimit 四分之一中的较小值。调低阈值可能缩小缓存,增加重复加载和编译的开销。

    此外,vmForks 能根据各子进程的 RSS,在内存紧张时延后创建 worker,因此比共享进程 RSS 的 vmThreads 更容易控制内存压力。这项调度机制与 memoryLimit 分开工作;子进程本身仍有额外开销,实际内存占用不一定更低。

    向 worker 传递 Node.js flags

    使用 pool.execArgv 向 worker 传递 Node.js 启动参数。例如,下面的配置启用 development condition:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      pool: {
        execArgv: ['--conditions=development'],
      },
    });

    调试时可以配合 maxWorkers: 1 使用,让测试文件逐个运行,便于跟踪执行过程:

    rstest.config.ts
    import { defineConfig } from '@rstest/core';
    
    export default defineConfig({
      pool: {
        maxWorkers: 1,
        execArgv: ['--inspect-brk'],
      },
    });

    VM pool 的行为边界

    以下限制同时适用于 vmForksvmThreads

    隔离与清理

    每个文件都有新的 VM context、模块图和测试环境,worker scope fixture 也按文件创建和清理;isolate 对此不生效。但 worker 会复用,process.env、native addon 等 VM 之外的状态可能跨文件保留。

    测试仍需在文件结束前 await 或取消异步任务。teardown 会清理受 Rstest 管理的定时器,但不会取消任意 Promise 链、原生 I/O 或后台任务。

    尚未完成的已包装 node:timers/promises 和 promisify timeout/immediate 操作会以 AbortError 取消。这可能触发用户的 catchfinally,因此不能保证 teardown 后不再执行用户代码。

    跨 realm 断言

    来自 Node.js、worker 或 DOM 环境的值可能使用不同的 constructor,无法通过当前 VM 中的 instanceof 检查。请使用 await 和内容断言,判断错误时检查 namecodemessage

    模块加载

    测试和 setup bundle、external JavaScript ESM 与 CommonJS 均可在 VM 中执行。自定义 Node.js loader 和 external TypeScript 执行不受支持,请先编译或 bundle。

    同步 require(esm) 需要 Node.js 24.9+、VM graph API 可用且依赖图不含 top-level await,否则应改用动态 import()。native addon 仅支持通过 CommonJS require() 直接加载,其状态不受 VM 隔离。

    查看模块加载兼容性

    VM 加载方式与 Node.js 原生 loader 存在以下差异:

    加载方式支持范围与限制
    test/setup bundle 和 external JavaScript在文件 VM 中执行,支持静态和动态 import;setup 和模块执行状态按文件重新创建。
    CommonJS named export从原始 module.exports receiver 读取静态识别出的自有导出,包括不可枚举属性和 getter。导出是快照而非 live binding;interopDefault 仍然生效。
    JSON、WebAssembly 和 data: URLJSON ESM import 需要 type: 'json'。支持异步 WebAssembly,以及 JavaScript、JSON 和 base64 WebAssembly data: URL;不支持同步 require() WebAssembly。
    同步 require(esm)需要 Node.js 24.9+ 和 VM graph API。异步依赖图抛出 ERR_REQUIRE_ASYNC_MODULE;较早的 VM 实现会以 ERR_REQUIRE_ESM 拒绝 ESM require。
    Native addonCommonJS require() 直接交给 Node.js 加载;不支持通过 VM ESM import .node 文件,addon 状态不受 VM 隔离。
    CommonJS 解析路径和 export condition 由 Node.js require.resolve() 选择;选中的入口无法在 VM 中执行时,不会自动改选其他入口。
    Module._cache指向当前文件的 require.cache,支持查看和删除 CommonJS/JSON 条目;不支持替换或删除 _cache 本身。同步 require(esm) 使用 VM ESM 缓存,不生成 CommonJS 缓存记录或 module.children 关联。