vitest-browser-vue
由社区提供的 vitest-browser-vue 包可在 浏览器模式 中渲染 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 = render(Component, {
props: {
initialCount: 1,
}
})
await screen.getByRole('button', { name: 'Increment' }).click()
await expect.element(screen.getByText('Count is 2')).toBeVisible()
})WARNING
该库的灵感来至于 @testing-library/vue.
如果你之前使用过 @testing-library/vue,仍可以继续延用。但 vitest-browser-vue 包提供了浏览器模式下特有的优势,这些是 @testing-library/vue 所不具备的:
vitest-browser-vue 返回的 API 能与内置的 定位器、用户事件 及 断言 更好的协作。例如:即使组件在断言间被重新渲染,Vitest 仍会自动重试元素查找,直至断言成功。
该包提供两个入口点:vitest-browser-vue 和 vitest-browser-vue/pure。两者暴露完全相同的 API,在下一个测试开始前 pure 不会添加移除组件处理程序。
渲染函数
export function render(
component: Component,
options?: ComponentRenderOptions,
): RenderResult选项
render 函数支持 @vue/test-utils 中 mount 选项 的全部参数(除 attachTo 外,需改用 container)。此外还额外支持 container 和 baseElement 参数。
container
默认情况下,Vitest 会创建一个 div 并添加到 document.body 上,然后在该节点中渲染你的组件。如果提供自定义的 HTMLElement 容器,则不会自动添加,你需要在调用 render 前手动执行 document.body.appendChild(container)。
例如,当测试 tbody 元素时,它不能作为 div 的子元素。在这个例子中,你可以指定一个 table 作为渲染容器。
const table = document.createElement('table')
const { container } = render(TableBody, {
props,
// ⚠️ 渲染前需手动将元素添加到 `body`
container: document.body.appendChild(table),
})baseElement
如果指定了 container 参数,则默认以此为根元素,否则将默认使用 document.body。该元素既作为查询操作的根节点,也会在使用 debug() 时被输出展示。
渲染结果
除文档记载的返回值外,render 函数还会返回相对于 baseElement 的所有可用 定位器,包括 自定义定位器。
const screen = render(TableBody, { props })
await screen.getByRole('link', { name: 'Expand' }).click()container
承载 Vue 组件渲染的 DOM 容器节点。这是一个常规 DOM 节点,因此理论上可以通过 container.querySelector 等方式检查子元素。
DANGER
如果你需通过 container 查询渲染元素,你应该重新考虑测试方法!定位器 专为应对组件变更设计,比直接查询容器更具稳定性。应避免使用 container 查询元素!
baseElement
TIP
render 返回的查询方法会基于 baseElement 进行查找,因此即使不指定 baseElement,也能通过这些查询方法来测试你的传送门组件。
locator
container 的 定位器。在组件范围内查找元素或传递给其他断言语句场景下特别有用:
import { render } from 'vitest-browser-vue'
const { locator } = render(NumberDisplay, {
props: { number: 2 }
})
await locator.getByRole('button').click()
await expect.element(locator).toHaveTextContent('Hello World')debug
function debug(
el?: HTMLElement | HTMLElement[] | Locator | Locator[],
maxLength?: number,
options?: PrettyDOMOptions,
): void此方法是 console.log(prettyDOM(baseElement)) 的快捷方式,用于在控制台输出容器或指定元素的 DOM 内容。
rerender
function rerender(props: Partial<Props>): void最佳实践是测试负责更新属性的组件本身,以确保属性更新逻辑正确,从而避免测试代码依赖于实现细节。如果需要在测试过程中更新已渲染组件的属性,当前函数可用于实现该需求。
import { render } from 'vitest-browser-vue'
const { rerender } = render(NumberDisplay, { props: { number: 1 } })
// 使用新属性重新渲染同一个组件
rerender({ number: 2 })unmount
function unmount(): void此操作将会把已渲染的组件卸载。该特性适用于测试组件从页面移除时的行为(例如验证是否残留未清除的事件处理器,避免引发内存泄漏)。
emitted
function emitted<T = unknown>(): Record<string, T[]>
function emitted<T = unknown[]>(eventName: string): undefined | T[]返回组件触发的事件。
WARNING
事件触发值是内部实现细节,不直接向用户公开。建议通过 定位器 测试触发值如何改变显示内容,而非直接依赖此方法。
cleanup
export function cleanup(): void移除所有通过 render 方法渲染的组件。
扩展查询
如果想扩展定位器的查询方法,详情参阅 “自定义扩展器”。例如,要为 render 扩展一个新的定位器,可使用 locators.extend API 进行定义:
import { locators } from 'vitest/browser'
import { render } from 'vitest-browser-vue'
locators.extend({
getByArticleTitle(title) {
return `[data-title="${title}"]`
},
})
const screen = render(Component)
await expect.element(
screen.getByArticleTitle('Hello World')
).toBeVisible()配置
像配置 Vue Test Utils 一样, 通过将属性分配给导出的 config 选项 (在vitest-browser-vue 和 vitest-borowser-vue/pure 中都可用):
import { config } from 'vitest-browser-vue/pure'
config.global.stubs.CustomComponent = {
template: '<div></div>',
}