从 Vitest 迁移
如果你正在使用 Rstack 工具链(Rsbuild / Rslib / Rspack 等),迁移到 Rstest 可以带来更一致的开发体验。
使用 Agent Skills
如果你在使用支持 Skills 的 Coding Agent,可以安装 migrate-to-rstest 技能来辅助完成从 Vitest 到 Rstest 的迁移。
安装后,让 Coding Agent 协助完成升级即可。
安装依赖
首先,你需要安装 Rstest 依赖。
接下来,更新 package.json 中的测试脚本,使用 rstest 替代 vitest。例如:
rstest 没有 --run 参数。直接运行 rstest 就会执行一次测试并退出;如果你想使用 watch 模式,可以加上 --watch:
CLI 参数映射
Vitest 的一部分 CLI 参数可以直接映射到 Rstest,另一部分则需要调整写法。迁移时,最常遇到的差异可以参考下表:
配置迁移
将你的 Vitest 配置文件(例如 vite.config.ts 或 vitest.config.ts)迁移为 rstest.config.ts:
Helper 映射
Vitest 配置文件中使用的 helper 可以对应到 @rstest/core 导出的同类方法:
Vitest 配置映射
迁移配置时,重点关注这两点:
- 移除
test字段,将其内部配置提升到顶层。 - 一些字段名的调整(例如
test.environment→testEnvironment)。
请遍历 test 下的每一个字段,对照下表进行提升、重命名或删除。表中未列出的字段未必能 1:1 映射,直接删除前请先对照 Rstest 配置参考 确认。
文件级环境注释
如果你的 Vitest 测试使用了文件级环境注释,Rstest 在迁移时会识别 Vitest 环境注释:
你可以保留这些注释,也可以改名为 @rstest-environment / @rstest-environment-options。选项值必须是单行 JSON 对象。支持的环境包括 node、jsdom 和 happy-dom。
编译配置
Rstest 使用 Rsbuild 作为默认测试编译工具,而不是 Vite。你可以在 Build Configurations 查看全部编译配置项。
Vite 在转换 TypeScript 时会读取 tsconfig.json 中选定的 compiler option。Rstest 会自动使用 compilerOptions.paths 进行模块解析,但不会将其他 compiler option 转为自己的转换配置。迁移时请逐项检查转换设置,并在需要时配置对应的 Rstest 选项,例如用 source.decorators 配置装饰器语法。Vite 的输出 target 配置与 TypeScript compiler option 应分别检查。adapter 可能会继承或推断额外设置,请参考所用 adapter 的文档。详见 source.tsconfigPath。如果你的 Vitest 配置启用了 Vite 的 TypeScript paths 支持,或使用了 vite-tsconfig-paths 插件,请在确认 Rstest 项目使用了预期的 tsconfig.json 后移除这些 Vite 专用配置。
Rstest 采用基于 bundle 的执行模型来运行测试。没有进入 bundle graph 的代码会保留 Node.js 原生 loader 行为,这可能和 Vitest 不同。如果你在运行时动态加载文件,请参考 bundle graph 之外的代码使用 Node.js 原生行为。
大部分项目中,主要的编译侧变化如下:
- 使用
source.define替代define。 - 使用
output.externals替代ssr.external。 - 使用 Rsbuild 插件替代 Vite 插件。
如果你使用的是 Rslib 或 Rsbuild,也可以直接复用对应配置:
- Rslib 项目(存在
rslib.config.*)使用@rstest/adapter-rslib,并在extends中配置withRslibConfig()(参考 Rslib 集成文档)。 - Rsbuild 项目(存在
rsbuild.config.*)使用@rstest/adapter-rsbuild,并在extends中配置withRsbuildConfig()(参考 Rsbuild 集成文档)。
更新测试 API
测试 API
Rstest 提供了与 Vitest 兼容的 API,已有的 Vitest 测试文件通常只需要极少改动。将 vitest 的导入替换为 @rstest/core,并把 vi / vitest 工具 API 替换为对应的 rs / rstest:
完整工具 API 请参考 Rstest APIs。
全局 API
当启用 globals: true 时,Vitest 会把 vi 和 vitest 挂在全局对象上。在 Rstest 中,建议按以下顺序映射:
vi.<api>→rs.<api>vitest.<api>→rs.<api>
rs 和 rstest 是等价的全局别名,但统一使用 rs 可以让迁移后的示例和 import style 保持一致。
从 @rstest/core 导入 API 时,统一使用 import style 的 rs.<api> 更一致,避免在同一文件里与 global style 混用。
Setup adapter
有些 setup adapter 是 Vitest 专用的。例如 @testing-library/jest-dom/vitest 面向 Vitest;在 Rstest 中通过 expect.extend 直接注册 matcher。
路径解析
new URL('./file', import.meta.url) 会相对于源码模块解析,与 Node.js 和 Vitest 行为一致,因此可以在 setup 或 helper 文件中定位同级文件(资源、fixture):
Rstest 会保留这类表达式,而不会将其改写成打包后的资源路径,因此解析得到的 URL 指向磁盘上的源文件。
由于这类表达式不会进入打包器的依赖图,在 watch 模式下修改此类同级文件不会自动重跑在运行时读取它的测试。
自动模拟模块
Vitest 和 Rstest 都支持在 mock 调用只包含模块路径时自动 mock。Rstest 会先尝试从对应 __mocks__ 目录加载手写 mock;如果没找到,再自动 mock 整个模块,把函数导出替换为空 mock 函数。
该行为从 Rstest 0.11.0 开始支持。更早版本中,如果没有手写 mock,需要显式传入 { mock: true } 来请求自动 mock。
如果你想跳过 __mocks__ 查找并直接请求自动 mock,可以显式传入 { mock: true }:
Mock 异步模块
当你需要 mock 模块返回值时,Rstest 不支持返回异步函数。
作为替代,Rstest 提供了同步 importActual 能力,你可以通过静态 import 导入未 mock 的真实实现:
mock factory 是 hoisted 执行的;依赖同模块中后初始化的变量会触发初始化顺序错误。共享值可放到 hoisted initializer(例如 rs.hoisted(...))中规避。
Snapshot
Vitest 和 Rstest 使用相同的 snapshot key 格式和 body 序列化方式。原有的 __snapshots__/*.snap 文件可以被 Rstest 原样读取;在 Vitest 下能通过的测试,到 Rstest 下也能通过,不需要重录。两者只有文件 header 行不同:
执行 rstest -u 会把 header 规整为 Rstest 形式,snapshot body 保持 byte-identical。