从 Vitest 迁移
如果你正在使用 Rstack 工具链(Rsbuild / Rslib / Rspack 等),迁移到 Rstest 可以带来更一致的开发体验。
安装依赖
首先,你需要安装 Rstest 依赖。
deno add npm:@rstest/core -D
接下来,更新 package.json 中的测试脚本,使用 rstest 替代 vitest。例如:
"scripts": {
- "test": "vitest run" // 或 "vitest --run"
+ "test": "rstest"
}
rstest 没有 --run 参数。直接运行 rstest 就会执行一次测试并退出;如果你想使用 watch 模式,可以加上 --watch:
"scripts": {
- "test": "vitest"
+ "test": "rstest --watch"
}
配置迁移
将你的 Vitest 配置文件(例如 vite.config.ts 或 vitest.config.ts)迁移为 rstest.config.ts:
rstest.config.ts
import { defineConfig } from '@rstest/core';
export default defineConfig({
include: ['**/*.{test,spec}.?(c|m)[jt]s?(x)'],
});
测试配置
Rstest 的测试配置和 Vitest 基本一致。
迁移配置时,重点关注这两点:
- 移除
test 字段,将其内部配置提升到顶层。
- 一些字段名的调整(例如
test.environment -> testEnvironment)。
你可以在 Test Configurations 查看全部测试配置项。
import { defineConfig } from '@rstest/core';
export default defineConfig({
- test: {
- include: ['**/*.{test,spec}.?(c|m)[jt]s?(x)'],
- exclude: ['dist/**'],
- setupFiles: ['./test/setup.ts'],
- globals: true,
- environment: 'node',
- },
+ include: ['**/*.{test,spec}.?(c|m)[jt]s?(x)'],
+ exclude: ['dist/**'],
+ setupFiles: ['./test/setup.ts'],
+ globals: true,
+ testEnvironment: 'node',
});
编译配置
Rstest 使用 Rsbuild 作为默认测试编译工具,而不是 Vite。你可以在 Build Configurations 查看全部编译配置项。
大部分的配置可以直接迁移(如,resolve.alias、resolve.extensions 等),但需要注意以下几点:
- 使用
source.define 替代 define。
- 使用
output.externals替代 ssr.external。
- 使用 Rsbuild 插件替代 Vite 插件。
import { defineConfig } from '@rstest/core';
- import react from '@vitejs/plugin-react'
+ import { pluginReact } from '@rsbuild/plugin-react';
export default defineConfig({
- plugins: [react()],
- define: {
- __DEV__: true,
- },
+ plugins: [pluginReact()],
+ source: {
+ define: {
+ __DEV__: true,
+ },
+ },
});
如果你使用的是 Rslib 或 Rsbuild,也可以直接复用对应配置:
- Rslib 项目(存在
rslib.config.*)使用 @rstest/adapter-rslib,并在 extends 中配置 withRslibConfig()(参考 Rslib 集成文档)。
- Rsbuild 项目(存在
rsbuild.config.*)使用 @rstest/adapter-rsbuild,并在 extends 中配置 withRsbuildConfig()(参考 Rsbuild 集成文档)。
替换测试导入与 API
测试 API 的迁移通常只需要两步:
- 将
vitest 的导入替换为 @rstest/core。
- 将
vi 或 vitest 的工具 API 替换为 rs。
- import { describe, expect, it, test, vi, type Mock } from 'vitest';
+ import { describe, expect, it, test, rs, type Mock } from '@rstest/core';
- vi.fn()
+ rs.fn()
- vi.mock('./foo')
+ rs.mock('./foo')
- vi.spyOn(console, 'error')
+ rs.spyOn(console, 'error')
完整工具 API 请参考 Rstest APIs。
自动模拟模块
在 Vitest 中,调用 vi.mock() 且只传模块路径时,会先尝试从对应 __mocks__ 目录加载手动 mock;如果没找到,再自动 mock 整个模块,把导出替换为空 mock 函数。
// Vitest
import { vi, test, expect } from 'vitest';
import { someFunction } from './module';
// 优先查找 __mocks__/module.js,然后自动 mock。
vi.mock('./module');
test('should be mocked', () => {
expect(vi.isMockFunction(someFunction)).toBe(true);
someFunction(); // 返回 undefined
});
Rstest 的行为不同。调用 rs.mock() 且只传模块路径时,只会查找 __mocks__,若未找到会报错。要启用自动 mock,需要显式传入 { mock: true }。
// Rstest
import { rs, test, expect } from '@rstest/core';
import { someFunction } from './module';
- // 优先查找 __mocks__/module.js,然后自动 mock。
- vi.mock('./module');
+ // 传入 { mock: true } 后会自动 mock 模块。
+ rs.mock('./module', { mock: true });
test('should be mocked', () => {
expect(rs.isMockFunction(someFunction)).toBe(true);
someFunction(); // 返回 undefined
});
Mock 异步模块
当你需要 mock 模块返回值时,Rstest 不支持返回异步函数。
作为替代,Rstest 提供了同步 importActual 能力,你可以通过静态 import 导入未 mock 的真实实现:
+ import * as apiActual from './api' with { rstest: 'importActual' };
- vi.mock('./api', async (importOriginal) => {
- const original = await importOriginal();
- return {
- ...original,
- fetchUser: rs.fn().mockResolvedValue({ id: 'mocked' }),
- };
- });
+ rs.mock('./api', () => ({
+ ...apiActual,
fetchUser: rs.fn().mockResolvedValue({ id: 'mocked' }),
}));