拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Vitest Browser Mode 中测试 Vue 组件:`vitest-browser-vue` 完整指南

Vitest Browser Mode 中测试 Vue 组件vitest-browser-vue完整指南【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitestvitest-browser-vue是 Vitest 生态中用于在Browser Mode浏览器模式下渲染与测试 Vue 为骨架结合仓库内 Browser Mode 的 locator、断言、交互与 Trace View 能力系统讲解render的全部选项与返回值、cleanup、查询扩展、Vue Test Utils 配置等实战要点帮助你写出可在真实浏览器中运行、抗抖动flaky-resistant的 Vue 组件测试。一、vitest-browser-vue是什么vitest-browser-vue渲染 Vue 组件的方式与testing-library/vue类似但它运行在 Vitest 的Browser Mode中——即测试真正跑在浏览器Playwright / WebdriverIO / preview里而非 jsdom 之类的 DOM 模拟环境。它所带来的独特优势包括返回的 API 与内置的 locators、user events 和 assertions 深度配合配合expect.element时Vitest 会自动重试元素查询直到断言成功即使组件在断言之间发生了重新渲染测试依然稳定渲染、重渲染、卸载等动作会记录 trace mark可在 Trace View 中逐步回放。如果你已经用过testing-library/vue可以继续沿用既有写法但vitest-browser-vue提供了 Testing Library 在 Browser Mode 下所不具备的上述能力。最简单的入门用例完整代码可在仓库脚手架示例 packages/vitest/src/create/browser/examples.ts 中看到其为HelloWorld.vue生成的测试与此结构一致import { render } from vitest-browser-vue import { expect, test } from vitest import Component from ./Component.vue test(counter button increments the count, async () { const screen await render(Component, { props: { initialCount: 1, } }) await screen.getByRole(button, { name: Increment }).click() await expect.element(screen.getByText(Count is 2)).toBeVisible() })两个入口点vitest-browser-vue与vitest-browser-vue/pure该包暴露两个入口点二者 API 完全相同唯一区别在于vitest-browser-vue会在下一个测试开始前自动注册清理逻辑cleanup handler卸载本次渲染的组件vitest-browser-vue/pure不注册该自动清理 handler适合需要完全手动控制组件生命周期的场景例如在beforeEach/afterEach中自行调用cleanup()。二、render函数export function render( component: Component, options?: ComponentRenderOptions, ): PromiseRenderResultrender是渲染 Vue 组件的核心函数返回一个PromiseRenderResult因此需要await。每次调用render都会在 Trace View 中记录一个vue.rendertrace mark方便在回放时定位渲染发生的时刻。2.1 Optionsrender支持vue/test-utils的mount全部选项唯一的例外是attachTo——请改用container。在此基础之上还额外增加了两个选项container和baseElement。container默认情况下Vitest 会创建一个div将其追加到document.body然后把组件渲染进去。如果你传入自己的HTMLElement作为container它不会被自动追加——你必须在调用render之前手动调用document.body.appendChild(container)。典型场景当你要单测tbody元素时tbody不能是div的子元素此时可以指定table作为渲染容器const table document.createElement(table) const { container } await render(TableBody, { props, // ⚠️ 在渲染前手动把元素追加到 body container: document.body.appendChild(table), })baseElement如果指定了containerbaseElement默认等于它否则默认等于document.body。baseElement有两个用途作为查询query的基准元素——render返回的所有 locator 都相对baseElement进行查找作为调用debug()时打印的内容范围。2.2 Render Result除了文档列出的返回值外render还会返回相对于baseElement的全部可用 locator包括自定义 locator见 Custom Locators。这意味着你可以把返回值当作一个作用域化的page使用const screen await render(TableBody, { props }) await screen.getByRole(link, { name: Expand }).click()container组件实际渲染到的 DOM 节点。它是一个普通 DOM 节点技术上你也可以调用container.querySelector之类的原生方法去检查子元素。::: danger 如果你发现自己依赖container去查询渲染出来的元素请重新考虑locators 的设计目标是对组件的变动更具韧性例如结构调整、类名变化应避免使用container直接查询元素。 :::baseElement组件在container内渲染时baseElement是更外层的容器 DOM 节点。如果你没有在 options 中指定baseElement它默认是document.body。这个属性对于测试渲染到容器 div 之外的组件非常有用。例如你要做快照测试一个 portal 组件——它直接把 HTML 渲染到body里此时就可以用baseElement来捕获。::: tiprender返回的查询queries会查找baseElement内部所以你可以直接用查询来测试 portal 组件无需额外处理baseElement。 :::locatorcontainer对应的 locator。当你想把查询作用域限制在组件内部或者把它传给其他断言时这个 locator 非常有用import { render } from vitest-browser-vue const { locator } await render(NumberDisplay, { props: { number: 2 } }) await locator.getByRole(button).click() await expect.element(locator).toHaveTextContent(Hello World)debugfunction debug( el?: HTMLElement | HTMLElement[] | Locator | Locator[], maxLength?: number, options?: PrettyDOMOptions, ): void这是console.log(prettyDOM(baseElement))的快捷方式会把容器或指定元素的 DOM 内容打印到控制台用于排查为什么查不到元素等问题。可选地传入元素/locator 数组、最大长度与格式化选项来控制输出。rerenderfunction rerender(props: PartialProps): Promisevoid以新的 props 重新渲染同一个组件同样会在 Trace View 中记录vue.rerendertrace mark。从最佳实践角度更好的做法是测试真正负责更新 props 的父组件从而验证 props 被正确传递避免测试依赖实现细节。但如果你确实想在测试里更新已渲染组件的 props可以这样用import { render } from vitest-browser-vue const { rerender } await render(NumberDisplay, { props: { number: 1 } }) // 用不同的 props 重渲染同一组件 await rerender({ number: 2 })unmountfunction unmount(): Promisevoid卸载已渲染的组件并记录vue.unmounttrace mark。它适合测试组件从页面移除时的行为——例如验证没有遗留的事件处理器避免内存泄漏const { unmount } await render(Component) await unmount() // 此时可断言全局状态、事件监听等已被正确清理emittedfunction emittedT unknown(): Recordstring, T[] function emittedT unknown[](eventName: string): undefined | T[]返回组件发出的emitted事件。不带参数时返回所有事件名到事件参数数组的映射传入事件名时只返回该事件对应的参数数组未触发则为undefined。::: warning Emitted 的值属于不直接暴露给用户的实现细节因此更推荐用 locators 来验证发出的值如何改变界面上显示的内容而不是直接断言事件参数本身。 :::三、cleanupexport function cleanup(): void移除所有通过render渲染的组件。如前文所述vitest-browser-vue主入口会在下一个测试开始前自动执行清理vitest-browser-vue/pure不会需要你在合适的时机通常是afterEach手动调用cleanup()。四、扩展查询让render返回自定义 locator要扩展 locator 查询使用 “Custom Locators” 中介绍的locators.extendAPI。例如要让render返回一个新的自定义 locator可以这样定义import { locators } from vitest/browser import { render } from vitest-browser-vue locators.extend({ getByArticleTitle(title) { return [data-title${title}] }, }) const screen await render(Component) await expect.element( screen.getByArticleTitle(Hello World) ).toBeVisible()locators.extend定义的是选择器生成器——它返回一个 CSS 选择器字符串。扩展之后所有通过 locator API 创建的对象包括page与render的返回值都会拥有这个新查询方法。五、配置 Vue Test Utils你可以通过给config导出在vitest-browser-vue与vitest-browser-vue/pure中都可用赋值的方式来配置 Vue Test Utils 的选项import { config } from vitest-browser-vue/pure config.global.stubs.CustomComponent { template: div/div, }config.global支持 Vue Test Utils 的全局配置项例如stubs组件桩、plugins、mocks、provide等从而在渲染每个组件时统一生效。六、与 Browser Mode 能力深度协同从查询到断言再到交互vitest-browser-vue的价值在于它把 Vue 组件渲染接入了一整套 Browser Mode 基础设施。理解下面几个核心机制可以写出更稳定、更贴近真实用户的测试。6.1 locator惰性查询与自动重试render返回的getBy*方法返回的是locator 对象而不是 DOM 元素。locator 是惰性的——它只是一个由选择器字符串定义的元素或一组元素的抽象真正解析发生在你调用其方法click、element等或传给断言时。这使得 locator 查询可组合、可保存也让 Vitest 可以在必要时重试交互与断言。常用查询包括getByRole按 ARIA role 与 accessible name、getByText、getByLabelText、getByPlaceholder、getByAltText、getByTitle、getByTestId等详见 Locators API。例如const screen await render(LoginForm) // 按可访问名称定位推荐贴近真实用户的使用方式 await screen.getByRole(textbox, { name: Login }).fill(admin) await screen.getByRole(button, { name: /submit/i }).click()locator 还支持链式操作.filter、.nth、.and、.or与转义舱.element()、.query()、.elements()、.all()等能力其底层实现位于 packages/browser/src/client/tester/locators.ts。6.2expect.element内置重试的 DOM 断言浏览器测试因异步性质超时、网络请求、动画等可能不稳定因此 Vitest 通过expect.poll与expect.element提供开箱即用的可重试断言。断言 API 文档见 Assertion API其 DOM 断言实现toBeVisible、toBeEnabled、toHaveTextContent等均 fork 自testing-library/jest-dom位于 packages/browser/src/client/tester/expect/。test(error banner is rendered, async () { triggerError() // 创建 locator此时并不检查元素是否存在 const banner screen.getByRole(alert, { name: /error/i }) // expect.element 会反复检查元素存在于 DOM 中且 textContent 等于 Error! // 直到条件满足或超时 await expect.element(banner).toMatchTextContent(Error!) })expect.element接受可选的第二个参数用于控制重试行为interface ExpectPollOptions { // 重试间隔毫秒默认取 expect.poll.interval 配置 interval?: number // 重试总时长毫秒默认取 expect.poll.timeout 配置 timeout?: number // 断言失败时打印的消息 message?: string }当传入 locator 时Vitest 会先通过locator.findElement()解析元素再执行 DOM 断言——findElement自身使用递增的重试间隔0、20、50、100、100、500ms随后才应用断言层面的interval。注意toMatchTextContent等断言在普通expect上也可用只是没有内置重试// 如果 .textContent 不是 Error!会立即失败 expect(banner).toMatchTextContent(Error!)推荐做法只要使用page.getBy*/screen.getBy*locator就始终配合expect.element来降低测试抖动。6.3 userEvent 与 locator 方法真实浏览器交互vitest-browser-vue渲染出的组件可以接受userEvent从vitest/browser导入与 locator 方法click、fill、hover、selectOptions、upload、dragAndDrop、keyboard、tab、copy/cut/paste等的真实交互。与testing-library/user-event用合成事件模拟不同Vitest 通过 Chrome DevTools Protocol 或 WebDriver 执行交互行为与真实用户一致详见 Interactivity API。import { userEvent } from vitest/browser const screen await render(ContactForm) await screen.getByRole(textbox, { name: /email/i }).fill(johnexample.com) await userEvent.keyboard({Tab}) // 真实按键可用于焦点管理测试 await screen.getByRole(button, { name: /submit/i }).click()仓库中的组件测试指南 docs/guide/browser/component-testing.md 提供了大量组合示例例如用expect.element自动重试等待异步数据渲染、用userEvent.keyboard测试模态框的 Escape 关闭与焦点陷阱等。七、Trace View 集成vue.render/vue.rerender/vue.unmountrender、rerender、unmount分别记录vue.render、vue.rerender、vue.unmounttrace mark这些标记会出现在 Vitest 的 Trace View实验特性自 5.0.0 起时间线中。启用方式// vitest.config.ts import { defineConfig } from vitest/config export default defineConfig({ test: { browser: { traceView: true, }, }, })# 或通过 CLI vitest --browser.traceView开启后在 Browser UI、Vitest UI 与 HTML reporter 中都可以打开 trace viewer左侧是步骤列表每个动作、断言、mark、生命周期条目含名称、时机、选择器与源码位置失败项标红右侧是该步骤时刻的 DOM 快照被交互的元素高亮为蓝色。vue.render等标记能帮你快速定位组件是在哪一步被渲染/更新/卸载的再配合locator.mark()仅当browser.trace启用时有效可进一步标注关键时间点。八、仓库中的配套示例脚手架模板vitest create browser生成的 Vue 项目模板定义在 packages/vitest/src/create/browser/examples.ts其中HelloWorld.vue的测试即为render(HelloWorld, { props: { name: Vitest } })expect.element(getByText(Hello Vitest!))的组合组件测试策略仓库的 docs/guide/browser/component-testing.md 覆盖了隔离策略、集成策略、表单校验、错误边界、可访问性测试与调试技巧底层能力文档Locators API、Interactivity API、Assertion API、Trace View。总结vitest-browser-vue把 Vue 组件渲染融入 Vitest Browser Mode 的完整能力栈render负责挂载组件并暴露作用域化的 locator 查询expect.element提供自动重试的 DOM 断言userEvent与 locator 方法提供真实的浏览器交互而 Trace View 让render/rerender/unmount等生命周期动作可被回放与调试。遵循通过 locator 查询、通过可访问名称定位、优先expect.element、避免container.querySelector与emitted实现细节等原则即可写出既贴近真实用户行为又足够稳定的 Vue 组件测试。【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门