Vitest 3.2 发布!
2025 年 6 月 2 日
Vitest 3.2 版本主要聚焦于改进浏览器模式和 TypeScript 支持。此版本还包含一些新的实用方法、配置选项,并弃用了 workspace
配置,转而使用 projects
。
workspace
已弃用
为了简化配置,团队决定弃用独立的 vitest.workspace
文件,并建议仅在根配置中使用 projects
选项。这还简化了全局选项的配置方式(因为当没有根配置时,无需猜测如何添加报告器)。
我们还决定弃用 workspace
名称,因为它与 PNPM 等通过此选项提供 monorepo 支持的其他工具存在命名冲突。Vitest 不会以单独的 CWD
运行这些项目,而是将它们视为子 Vitest 实例。这为我们提供了更多空间,可以在不影响其他工具的情况下,为 monorepo 提出更好的解决方案。
此选项将在未来的主要版本中完全移除,由 projects
替代。在此之前,如果使用了 workspace
功能,Vitest 将打印警告。
import { defineConfig } from "vitest/config";
export default defineConfig({
test: {
// "test.workspace" 已更名为 "test.projects"
workspace: [
projects: [
{ test: { name: "Unit" } },
{ test: { name: "Integration" } },
],
},
});
注释 API
新的注释 API 允许您使用自定义消息和附件来注释任何测试。这些注释在 UI、HTML、JUnit、TAP 和 GitHub Actions 报告器中可见。如果测试失败,Vitest 还将在 CLI 中打印相关注释。

作用域夹具
test.extend
夹具现在可以指定 scope
选项:file
或 worker
。
const test = baseTest.extend({
db: [
async ({}, use) => {
// ...setup
await use(db);
await db.close();
},
{ scope: 'worker' },
],
});
文件作用域的夹具类似于在文件顶层使用 beforeAll
和 afterAll
,但如果夹具未在任何测试中使用,则不会被调用。
worker
作用域的夹具每个 worker 只初始化一次,但请注意,默认情况下 Vitest 会为每个测试创建一个 worker,因此您需要禁用隔离才能从中受益。
自定义项目名称的颜色
现在在使用 projects
时可以设置自定义颜色:
配置示例
export default defineConfig({
test: {
projects: [
{
test: {
name: {
label: 'unit',
color: 'red',
},
},
},
{
test: {
name: {
label: 'browser',
color: 'green',
},
browser: {
enabled: true,
provider: 'playwright',
instances: [{ browser: 'chromium' }],
},
},
},
],
},
})

自定义浏览器定位器 API
内置定位器可能不足以表达您的应用程序需求。现在,我们建议使用新的 locators.extend
API 扩展定位器,而不是回退到 CSS 选择器并失去 Vitest 通过其定位器 API 提供的重试能力保护。
import { locators } from '@vitest/browser/context';
locators.extend({
getByCommentsCount(count: number) {
return `.comments :text("${count} comments")`;
},
});
此方法返回一个 Playwright 定位器字符串来构造一个新的定位器。请注意,如果存在父定位器,此方法返回的字符串将作用于该父定位器。
现在您可以直接在 page
或任何其他定位器上调用 getByCommentsCount
:
await expect.element(page.getByCommentsCount(1)).toBeVisible();
await expect
.element(
page.getByRole('article', { name: 'Hello World' }).getByCommentsCount(1)
)
.toBeVisible();
如果此方法返回一个字符串,则返回值将被转换为定位器,因此您可以继续链式调用:
page
.getByRole('article', { name: 'Hello World' })
.getByCommentsCount(1)
.getByText('comments');
此方法可以访问当前的定位器上下文(如果存在)(如果方法在 page
上调用,则上下文将指向 page
),因此您可以在其内部链式调用所有定位器方法:
import { locators } from '@vitest/browser/context';
import type { Locator } from '@vitest/browser/context';
locators.extend({
getByCommentsCount(this: Locator, count: number) {
return this.getByRole('comment').and(this.getByText(`${count} comments`));
},
});
能够访问上下文还允许您调用定位器的常规方法来定义自定义用户事件:
import { locators, page } from '@vitest/browser/context';
import type { Locator } from '@vitest/browser/context';
locators.extend({
clickAndFill(this: Locator, text: string) {
await this.click();
await this.fill(text);
},
});
await page.getByRole('textbox').clickAndFill('Hello World');
请参阅 locators.extend
API 以获取更多信息。
vi.spyOn
和 vi.fn
中的显式资源管理
在支持显式资源管理的环境中,您可以使用 using
代替 const
,以便在退出包含块时自动对任何模拟函数调用 mockRestore
。这对于被 spy 的方法特别有用:
it('calls console.log', () => {
using spy = vi.spyOn(console, 'log').mockImplementation(() => {})
debug('message')
expect(spy).toHaveBeenCalled()
})
// console.log 在此处恢复
测试 signal
API
Vitest 现在为测试代码提供了一个 AbortSignal
对象。您可以使用它来停止任何支持此 Web API 的资源。
当测试超时、另一个测试失败且 --bail
标志设置为非零值,或者用户在终端中按下 Ctrl+C 时,信号会被中止。
例如,当测试中断时,您可以停止 fetch
请求:
it('stop request when test times out', async ({ signal }) => {
await fetch('/heavy-resource', { signal });
}, 2000);
覆盖率 V8 AST 感知重映射
Vitest 现在使用由 Vitest 维护者之一 AriPerkkio 开发的 ast-v8-to-istanbul
包。这使得 V8 覆盖率报告与 Istanbul 保持一致,同时性能更优!通过将 coverage.experimentalAstAwareRemapping
设为 true
来启用此功能。
我们计划在下一个主要版本中将其作为默认的重映射模式。旧的 v8-to-istanbul
将被彻底移除。欢迎加入讨论:https://github.com/vitest-dev/vitest/issues/7928。
watchTriggerPatterns
选项
当您编辑文件时,Vitest 能够智能地只重新运行导入此文件的测试。不幸的是,Vitest 静态分析只识别静态和动态 import
语句。如果您正在读取文件或启动单独的进程,Vitest 将会忽略相关文件的更改。
通过 watchTriggerPatterns
选项,您可以根据文件更改来配置要重新运行的测试。例如,要在模板更改时始终重新运行 mailers
测试,请添加触发模式:
export default defineConfig({
test: {
watchTriggerPatterns: [
{
pattern: /^src\/templates\/(.*)\.(ts|html|txt)$/,
testsToRun: (file, match) => {
return `api/tests/mailers/${match[2]}.test.ts`;
},
},
],
},
});
新的多用途 Matchers
类型
Vitest 现在有一个 Matchers
类型,您可以扩展它,以便在一个地方为所有自定义匹配器添加类型支持。此类型影响所有这些用例:
expect().to*
expect.to*
expect.extend({ to* })
例如,要拥有类型安全的 toBeFoo
匹配器,您可以编写如下代码:
import { expect } from 'vitest';
interface CustomMatchers<R = unknown> {
toBeFoo: (arg: string) => R;
}
declare module 'vitest' {
interface Matchers<T = any> extends CustomMatchers<T> {}
}
expect.extend({
toBeFoo(actual, arg) {
// ^?
// ... implementation
return {
pass: true,
message: () => '',
};
},
});
expect('foo').toBeFoo('foo');
expect.toBeFoo('foo');
sequence.groupOrder
新的 sequence.groupOrder
选项控制在使用多个项目时项目运行测试的顺序。
- 具有相同组顺序号的项目将一起运行,并且组将按从低到高的顺序运行。
- 如果您不设置此选项,所有项目都将并行运行。
- 如果多个项目使用相同的组顺序,它们将同时运行。
示例
考虑这个例子:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
projects: [
{
test: {
name: 'slow',
sequence: {
groupOrder: 0,
},
},
},
{
test: {
name: 'fast',
sequence: {
groupOrder: 0,
},
},
},
{
test: {
name: 'flaky',
sequence: {
groupOrder: 1,
},
},
},
],
},
});
这些项目中的测试将按此顺序运行:
0. slow |
|> 同时运行
0. fast |
1. flaky |> 在 slow 和 fast 之后单独运行
完整的更改列表请查看 Vitest 3.2 更新日志。