测试失败时自动预览
虽然在测试中手动调用 debug()
可以精确控制何时捕获 DOM 状态,但有时您希望在测试失败时自动捕获 UI 状态。这对于调试 CI 环境中的测试失败或运行大型测试套件特别有用。
本指南展示了两种设置测试失败时自动预览的方法,无需在每个测试中手动调用 debug()
。
使用 CLI 配置测试失败时自动预览
您可以运行以下命令,轻松设置测试失败时自动预览:
vitest-preview setup --automaticMode
但是,请务必仔细阅读本指南,确保针对您的特定设置正确配置测试失败时自动预览。
方法 1:使用 onTestFinished
钩子(推荐)
Vitest 提供了强大的测试上下文 API,允许您挂钩到测试生命周期。您可以使用 onTestFinished
钩子在测试失败时自动调用 debug()
。
步骤 1:禁用自动清理
如果您使用的是 Testing Library,首先需要禁用自动清理。否则,在您使用 debug()
捕获之前,DOM 将被清理。
// vitest.config.ts/ vite.config.ts
/// <reference types="vitest/config" />
import { defineConfig } from 'vitest';
// https://vitejs.dev/config/
export default defineConfig({
test: {
- globals: true,
},
});
同时,确保您的测试设置文件不执行自动清理
// setupFiles.ts
import { cleanup } from '@testing-library/react'
import { afterEach } from 'vitest'
afterEach(() => {
- cleanup()
})
步骤 2:添加 onTestFinished
钩子
将以下代码添加到您的测试设置文件(例如,src/test/setup.ts
或 Vitest 配置中 setupFiles
指定的文件):
// setupFiles.ts
import { beforeEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import { debug } from 'vitest-preview';
beforeEach((ctx) => {
ctx.onTestFinished(({ task }) => {
if (task?.result?.state === 'fail') {
// 在 Vitest Preview 仪表板中预览失败的测试
debug();
}
// 仍然执行清理,但在捕获 DOM 状态之后。这取决于您使用的清理策略。
cleanup();
});
});
优点
- 设置简单 - 只需注册一个全局
beforeEach
钩子 - 无需修改单个测试文件即可适用于所有测试
- 在测试失败时捕获确切状态
缺点
- 需要修改现有的清理策略
方法 2:使用自定义 Fixtures 扩展测试 API
Vitest 允许您使用自定义 fixtures 扩展测试 API。这种方法可以在不修改清理策略的情况下添加自动调试。
步骤 1:创建自定义测试 Fixture
创建或修改您的测试工具文件以扩展测试 API:
// utils/vitest-utils.ts
import { test as baseTest } from 'vitest';
import { debug } from 'vitest-preview';
// 您可以重新导出 vitest 的所有导出
export * from 'vitest';
// 使用自动调试扩展测试 API
const test = baseTest.extend({
automaticDebugOnFail: [
async ({ task }, use) => {
await use(undefined);
if (task.result?.state === 'fail') {
debug();
}
},
{ auto: true }, // 使此 fixture 自动运行
],
});
const it = test;
export { test, it };
步骤 2:使用扩展的测试 API
在您的测试文件中,导入并使用扩展的测试 API,而不是来自 Vitest 的测试 API:
// Example.test.tsx
// 导入扩展的测试 API 而不是来自 VITEST 的测试 API
import { test, describe, expect } from './utils/vitest-utils';
import { render, screen, userEvent } from '@testing-library/react';
// 如果测试失败,`debug()` 将自动调用
test('should increment count on click', async () => {
render(<App />);
await userEvent.click(screen.getByRole('button'));
expect(await screen.findByText(/count is: 1/i)).toBeInTheDocument();
});
优点
- 无需修改现有的清理策略
- 关注点分离清晰
- 可以选择性地应用于特定测试文件
缺点
- 需要在每个测试文件中导入扩展的测试 API
- 不能直接使用来自 Vitest 的标准
test
/it
导入
选择合适的方法
两种方法各有优点:
方法 1 (onTestFinished) 设置更简单,全局生效,不需要更改单个测试文件。如果您希望以最少的更改为所有测试启用自动调试,推荐使用此方法。
方法 2 (自定义 Fixtures) 提供更多灵活性,不会干扰现有的清理策略。如果您希望更好地控制哪些测试使用自动调试,这种方法更好。
示例实现
这是使用第一种方法实现自动调试的完整示例:
// setup.ts
import { beforeEach } from 'vitest';
import { cleanup } from '@testing-library/react';
import { debug } from 'vitest-preview';
// 禁用自动清理
// 而不是使用 afterEach(cleanup)
beforeEach((ctx) => {
// 注册一个在测试完成时运行的回调
ctx.onTestFinished(({ task }) => {
// 检查测试是否失败
if (task?.result?.state === 'fail') {
// 捕获用于调试的 DOM 状态
debug();
}
// 然后执行清理
cleanup();
});
});
有效自动调试的提示
结合手动调试:您仍然可以将手动
debug()
调用与自动调试一起使用,用于特定的测试用例。CI 集成:自动调试在 CI 环境中可能很有用,因为测试可能会意外失败。但是,您可能不希望在 CI 中进行调试。您可以添加条件以在 CI 中禁用自动调试。
beforeEach((ctx) => {
ctx.onTestFinished(({ task }) => {
if (task?.result?.state === 'fail' && !process.env.CI) {
debug();
}
cleanup();
});
});
- 选择性应用:您可以根据测试名称或其他条件使自动调试更具选择性。
beforeEach((ctx) => {
ctx.onTestFinished(({ task }) => {
// 只调试特定组件或测试套件
if (task?.result?.state === 'fail' && task.name.includes('Button')) {
debug();
}
cleanup();
});
});
为什么不提供配置选项?
您可能想知道为什么 Vitest Preview 不提供简单的配置选项来启用自动调试。有几个挑战:
项目特定的清理行为:不同的项目有不同的清理策略,这使得很难提供适用于所有设置的一刀切解决方案。
测试 API 限制:从
vitest
导入的test
API 是不可变的,这意味着我们不能轻易地全局扩展它,而不需要更改导入语句。
这些挑战导致我们提供多种方法的文档,允许用户选择最适合其项目结构和偏好的方法。