ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Vitest Browser Mode 的 browser.trace 配置实战:捕获与阅读 Playwright Trace 文件

2026/9/14 23:03:30 拓冰建站 浏览量
Vitest Browser Mode 的 browser.trace 配置实战:捕获与阅读 Playwright Trace 文件 Vitest Browser Mode 的 browser.trace 配置实战捕获与阅读 Playwright Trace 文件【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitest本文围绕 Vitest 的配置项browser.trace展开讲解如何在 Browser Mode 中为测试运行捕获 Playwright 格式的 trace 文件、选择适合的捕获模式on、on-first-retry、on-all-retries、retain-on-failure等、自定义存储目录与截图策略并借助page.mark()等标记机制读懂 trace 时间线。读完本文你将掌握一套完整的浏览器测试取证与调试流程从配置 trace 捕获到在 Playwright Trace Viewer 中回放失败现场再到结合源码理解 Vitest 是如何把浏览器交互关联回测试代码具体行号的。一、browser.trace 选项概览browser.trace是test.browser配置下的一个选项用于在浏览器测试运行期间捕获 trace。捕获生成的文件是 Playwright 的 trace 格式可以用 Playwright Trace Viewerhttps://trace.playwright.dev/进行回放。该选项的关键元信息如下属性值Typeon \| off \| on-first-retry \| on-all-retries \| retain-on-failure \| objectCLI--browser.traceon、--browser.traceretain-on-failureDefaultoff一个需要特别注意的前提约束该选项仅由playwrightprovider 支持。官方文档docs/config/browser/trace.md以 danger 级别明确标注了这一点在源码层面packages/browser-playwright/src/commands/trace.ts 中每个 trace 命令实现都会先做isPlaywrightProvider(provider)判断非 Playwright provider 会抛出The ${provider.name} provider does not support tracing.的TypeError。二、五种捕获模式的含义与取舍browser.trace支持以下几种取值适用于不同场景on—— 为所有测试捕获 trace。文档中明确建议“not recommended as its performance heavy”性能开销大不建议长期使用off—— 不捕获 trace即默认值on-first-retry—— 仅在测试第一次重试时捕获 trace适合只关心“首次失败后重试现场”的场景on-all-retries—— 在测试的每一次重试中捕获 trace会保留多份 trace 用于对比retain-on-failure—— 仅为失败的测试保留 trace测试通过后会自动删除其 trace 文件。这是 CI 中最实用的取值平时零残留失败时自动留下完整证据。object—— 传入一个更精细的对象配置见下文。从源码结构看模式的判定逻辑集中在浏览器端的测试 runner 中。packages/browser/src/client/tester/runner.ts 里对每个测试计算是否应开启 tracingconst trace this.config.browser.trace const shouldTrace trace ! off !(trace on-all-retries retry 0) !(trace on-first-retry retry ! 1)即on-first-retry精确对应retry 1第一次重试on-all-retries则排除retry 0的首次执行。而在每个测试结束时runner 会检查retain-on-failure语义若模式为retain-on-failure且task.result?.state pass则调用deleteTracing命令删除该测试产生的 trace 文件否则调用annotateTraces命令把 trace 注册为测试的注解annotation。三、对象形式TraceOptions 详细字段除字符串模式外browser.trace还可以配置为一个对象interface TraceOptions { mode: on | off | on-first-retry | on-all-retries | retain-on-failure /** * The directory where all traces will be stored. By default, Vitest * stores all traces in __traces__ folder close to the test file. */ tracesDir?: string /** * Whether to capture screenshots during tracing. Screenshots are used to build a timeline preview. * default true */ screenshots?: boolean /** * If this option is true tracing will * - capture DOM snapshot on every action * - record network activity * default true */ snapshots?: boolean }三个字段的作用mode与上面五种字符串取值相同的捕获模式tracesDir所有 trace 文件的统一存放目录。不配置时默认存放在测试文件旁边的__traces__文件夹中screenshots是否在 tracing 期间捕获截图截图用于构建 Trace Viewer 中的时间线预览。默认truesnapshots为true时tracing 会在每个动作后捕获 DOM 快照并记录网络活动。默认true。这三个默认值在源码中有直接印证。Playwright provider 的startTracing命令packages/browser-playwright/src/commands/trace.ts调用context.tracing.start()时写入const options project.config.browser!.trace await context.tracing.start({ screenshots: options.screenshots ?? true, snapshots: options.snapshots ?? true, sources: options.sources ?? true, }).catch(() { provider.tracingContexts.delete(sessionId) })另外tracesDir还会被透传给 Playwright 的浏览器启动参数。packages/browser-playwright/src/playwright.ts 的resolveLaunchOptions中if (typeof browser.trace object browser.trace.tracesDir) { launchOptions.tracesDir browser.trace.tracesDir }四、完整配置示例最简配置配置文件形式// vitest.config.js import { defineConfig } from vitest/config import { playwright } from vitest/browser-playwright export default defineConfig({ test: { browser: { provider: playwright(), trace: on, }, }, })CLI 形式vitest --browser.traceon如需统一 trace 输出目录路径相对于项目根目录// vitest.config.js import { defineConfig } from vitest/config import { playwright } from vitest/browser-playwright export default defineConfig({ test: { browser: { provider: playwright(), trace: { mode: on, // the path is relative to the root of the project tracesDir: ./playwright-traces, }, }, }, })配合retry使用失败取证是常见组合例如vitest --browser.traceretain-on-failure这样只有失败测试的 trace 会被保留方便在 CI 失败后按需下载。五、trace 文件命名规则与默认存放位置默认情况下Vitest 为每个测试生成一个 trace 文件保存在测试文件旁边的__traces__文件夹中。文件名由四部分构成chromium-my-test-0-0.trace.zip ^^^^^^^^ project name ^^^^^^ test name ^ repeat count ^ retry count即project-name-test-name-repeatCount-retryCount.trace.zip。这个命名约定直接对应文档 docs/guide/browser/playwright-traces.md 中的说明其中 repeat 计数对应 repeats 配置retry 计数对应 retry 配置。从源码看默认路径的拼装逻辑在resolveTracesPathpackages/browser-playwright/src/commands/trace.tsfunction resolveTracesPath({ testPath, project }: BrowserCommandContext, name: string) { if (!testPath) { throw new Error(This command can only be called inside a test file.) } const options project.config.browser!.trace const sanitizedName ${project.name.replace(/[^a-z0-9]/gi, -)}-${name}.trace.zip if (options.tracesDir) { return resolve(options.tracesDir, sanitizedName) } const dir dirname(testPath) const base basename(testPath) return resolve( dir, __traces__, base, ${project.name.replace(/[^a-z0-9]/gi, -)}-${name}.trace.zip, ) }可以看到项目名会先经过[^a-z0-9]的净化非法字符替换为-配置了tracesDir时所有 trace 集中到同一目录并按测试文件分组未配置时则落在测试文件目录/__traces__/测试文件名/下。六、Trace markers给时间线加命名分组除了 Vitest 自动生成的分组你还可以添加显式的命名标记让 trace 时间线更易读。两种方式都可用page.mark(name)与locator.mark(name)。给单个操作加标记import { page } from vitest/browser document.body.innerHTML button typebuttonSign in/button await page.getByRole(button, { name: Sign in }).mark(sign in button rendered)用回调把多个操作归入同一标记await page.mark(sign in flow, async () { await page.getByRole(textbox, { name: Email }).fill(johnexample.com) await page.getByRole(textbox, { name: Password }).fill(secret) await page.getByRole(button, { name: Sign in }).click() })还可以用vi.defineHelper()包装可复用辅助函数使 trace 条目指向“调用辅助函数的位置”而不是其内部实现import { vi } from vitest import { page } from vitest/browser const myRender vi.defineHelper(async (content: string) { document.body.innerHTML content await page.elementLocator(document.body).mark(render helper) }) test(renders content, async () { await myRender(buttonHello/button) // trace points to this line })从源码结构看mark最终走的是 provider 命令markTracepackages/browser-playwright/src/commands/trace.ts。它先解析调用栈得到源码位置再用tracing.group(name, { location })/tracing.groupEnd()包裹一个“哑调用”page.evaluate(() 0)或 locator 的_expect(to.be.attached)来强制 Playwright 生成一次 DOM 快照——源码注释中注明这是为了规避 Playwright 的已知问题group 本身不产生快照。groupTraceStart/groupTraceEnd两个命令则对应page.mark(name, callback)的分组开始与结束。七、Source Location交互与测试行号的自动关联打开 trace 文件时你会注意到 Vitest 会把浏览器交互分组并链接回触发它的测试代码行号。官方文档说明以下场景会自动关联expect.element(...)断言交互动作click、fill、type、hover、selectOptions、upload、dragAndDrop、tab、keyboard、wheel以及截图。其底层机制是Playwright 依旧按原样记录它自己的低层动作事件Vitest 在其外层包上带有源码位置信息的 group从而让你能从 trace 时间线直接跳转到测试文件对应行。对于自动覆盖之外的场景则用page.mark()/locator.mark()手动补充分组。源码层面客户端命令层packages/browser/src/node/commands/trace.ts负责把浏览器侧命令转发给 provider并在服务端做栈解析// resolve stack strings → source locations server-side (requires source maps) const stacks project.browser!.parseStacktrace(entry.stack) if (stacks[0]) { entry.location stacks[0] }也就是说调用栈字符串先在浏览器端收集随后由 Node 端通过 source map 解析为真实的源码位置file/line/column这正是 trace 时间线能“跳回测试代码那一行”的原理。八、查看与回放 trace 文件生成 trace 文件后有两种查看方式方式一本地终端命令会启动 Trace Viewer 并加载指定文件npx playwright show-trace path-to-trace-file方式二直接在浏览器中打开 Playwright Trace Viewerhttps://trace.playwright.dev/上传 trace 文件。此外trace 文件会以 annotations注解的形式出现在 reporter 中。例如在 HTML reporter 的测试详情里可以直接找到指向 trace 文件的链接。实现上annotateTraces命令packages/browser-playwright/src/commands/trace.ts会调用vitest._testRun.recordArtifact(testId, { type: internal:annotation, annotation: { type: traces, ... } })把 trace 文件路径作为附件记录到对应测试实体上。九、实现细节补充结合源码还有几个值得了解的实现细节会话级去重PlaywrightBrowserProvider维护tracingContexts: Setstring记录已开启 tracing 的会话 IDpackages/browser-playwright/src/playwright.ts。startTracing对同一会话只启动一次避免重复tracing.start()。挂起 trace 的兜底处理provider 构造时注册了process.on(SIGTERM, this.onSIGTERM)当测试挂起导致进程被终止时会对pendingTraces中未结束的 chunk 逐个执行context.tracing.stopChunk({ path })保证 trace 文件完整落盘packages/browser-playwright/src/playwright.ts 的onSIGTERM。删除即清理deleteTracing命令通过unlink逐个删除 trace 文件ENOENT文件不存在会被静默忽略其他错误则抛出——这是retain-on-failure模式清理通过测试 trace 的底层实现。路径安全校验stopChunkTrace、deleteTracing、annotateTraces在写/删文件前都会调用assertBrowserApiWrite与assertBrowserFileAccess防止越权访问浏览器 API 允许之外的文件。测试用例佐证仓库在 test/browser/specs/playwright-trace.test.ts 中对各 trace 模式包括on-first-retry、on-all-retries、retain-on-failure做了行为验证可作为配置行为的事实依据。十、适用限制与使用建议该功能仅支持 Playwright provider即test.browser.provider: playwright()其他 provider 会抛出TypeErroron模式为所有测试捕获 trace性能开销大官方建议只在调试期短期开启日常开发建议trace: on定位问题CI 中建议--browser.traceretain-on-failure按需保留失败证据需要多次重试对比时选on-all-retries只关心首次重试现场时选on-first-retry默认 trace 落在各测试文件旁的__traces__目录若希望集中管理请通过对象形式的tracesDir指定统一目录相对项目根目录。综上browser.trace把 Playwright 成熟的 trace 采集能力接入了 Vitest Browser Mode配置上只需一个选项或一个对象行为上支持按重试/失败精细控制实现上借助 source map 将浏览器交互与测试代码行号关联起来配合 Trace Viewer 即可获得“失败现场回放 代码定位”的完整调试闭环。【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考