Interactivity API
Vitest 使用 Chrome DevTools Protocol 或 webdriver API 实现了 @testing-library/user-event应用程序接口的子集,而不是伪造事件,这使得浏览器行为更加可靠和一致。
几乎每个 userEvent 方法都继承了其provider选项。要在集成开发环境中查看所有可用选项,请在 tsconfig.json 文件中添加 webdriver 或 playwright 类型:
{
"compilerOptions": {
"types": [
"@vitest/browser/providers/playwright"
]
}
}{
"compilerOptions": {
"types": [
"@vitest/browser/providers/webdriverio"
]
}
}userEvent.setup
- Type:
() => UserEvent
创建一个新的用户事件实例。如果需要保持键盘状态,以便正确按下和释放按钮,这将非常有用。
WARNING
与 @testing-library/user-event 不同,来自 @vitest/browser/context 的默认 userEvent 实例只创建一次,而不是每次调用其方法时都创建一次!您可以从本代码段中看到其工作方式的不同之处:
import { userEvent as vitestUserEvent } from '@vitest/browser/context'
import { userEvent as originalUserEvent } from '@testing-library/user-event'
await vitestUserEvent.keyboard('{Shift}') // press shift without releasing
await vitestUserEvent.keyboard('{/Shift}') // releases shift
await originalUserEvent.keyboard('{Shift}') // press shift without releasing
await originalUserEvent.keyboard('{/Shift}') // DID NOT release shift because the state is different这种行为更有用,因为我们并没有模拟键盘,而是实际按下了 Shift 键,所以保留原来的行为会在字段中键入时造成意想不到的问题。
userEvent.click
- Type:
(element: Element, options?: UserEventClickOptions) => Promise<void>
点击元素。继承 provider 的选项。有关此方法如何工作的详细说明,请参阅 provider 的文档。
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('clicks on an element', async () => {
const logo = screen.getByRole('img', { name: /logo/ })
await userEvent.click(logo)
})References:
userEvent.dblClick
- Type:
(element: Element, options?: UserEventDoubleClickOptions) => Promise<void>
触发元素的双击事件
请参阅你的 provider 的文档以获取有关此方法如何工作的详细说明。
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('triggers a double click on an element', async () => {
const logo = screen.getByRole('img', { name: /logo/ })
await userEvent.dblClick(logo)
})References:
userEvent.tripleClick
- Type:
(element: Element, options?: UserEventTripleClickOptions) => Promise<void>
Triggers a triple click event on an element. Since there is no tripleclick in browser api, this method will fire three click events in a row, and so you must check click event detail to filter the event: evt.detail === 3.
Please refer to your provider's documentation for detailed explanation about how this method works.
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('triggers a triple click on an element', async () => {
const logo = screen.getByRole('img', { name: /logo/ })
let tripleClickFired = false
logo.addEventListener('click', (evt) => {
if (evt.detail === 3) {
tripleClickFired = true
}
})
await userEvent.tripleClick(logo)
expect(tripleClickFired).toBe(true)
})References:
- Playwright
locator.clickAPI: implemented viaclickwithclickCount: 3. - WebdriverIO
browser.actionAPI: implemented via actions api withmoveplus threedown + up + pauseevents in a row - testing-library
tripleClickAPI
userEvent.fill
- Type:
(element: Element, text: string) => Promise<void>
用文本填充 input/textarea/conteneditable。这将在输入新值之前移除输入框中的任何现有文本。
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('update input', async () => {
const input = screen.getByRole('input')
await userEvent.fill(input, 'foo') // input.value == foo
await userEvent.fill(input, '{{a[[') // input.value == {{a[[
await userEvent.fill(input, '{Shift}') // input.value == {Shift}
})TIP
该 API 比使用 userEvent.type 或 userEvent.keyboard 更快,但不支持 user-event keyboard syntax (例如,{Shift}{selectall})。
在不需要输入特殊字符的情况下,我们建议使用此 API 而不是 userEvent.type。
References:
userEvent.keyboard
- Type:
(text: string) => Promise<void>
通过 userEvent.keyboard 可以触发键盘输入。如果任何输入有焦点,它就会在该输入中键入字符。否则,它将触发当前焦点元素(如果没有焦点元素,则为 document.body)上的键盘事件。
This API supports user-event keyboard syntax.
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('trigger keystrokes', async () => {
await userEvent.keyboard('foo') // translates to: f, o, o
await userEvent.keyboard('{{a[[') // translates to: {, a, [
await userEvent.keyboard('{Shift}{f}{o}{o}') // translates to: Shift, f, o, o
await userEvent.keyboard('{a>5}') // press a without releasing it and trigger 5 keydown
await userEvent.keyboard('{a>5/}') // press a for 5 keydown and then release it
})References:
userEvent.tab
- Type:
(options?: UserEventTabOptions) => Promise<void>
发送一个 Tab 键事件。这是userEvent.keyboard('{tab}')的简写。
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('tab works', async () => {
const [input1, input2] = screen.getAllByRole('input')
expect(input1).toHaveFocus()
await userEvent.tab()
expect(input2).toHaveFocus()
await userEvent.tab({ shift: true })
expect(input1).toHaveFocus()
})References:
userEvent.type
- Type:
(element: Element, text: string, options?: UserEventTypeOptions) => Promise<void>
WARNING
如果不依赖 special characters(例如,{shift} 或 {selectall}),建议使用 userEvent.fill。
type 方法在 keyboard API 的基础上实现了 @testing-library/user-event 的 type 工具。
该函数允许您在 input/textarea/conteneditable 中键入字符。它支持 user-event keyboard syntax。
如果只需按下字符而无需输入,请使用 userEvent.keyboard API。
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('update input', async () => {
const input = screen.getByRole('input')
await userEvent.type(input, 'foo') // input.value == foo
await userEvent.type(input, '{{a[[') // input.value == foo{a[
await userEvent.type(input, '{Shift}') // input.value == foo{a[
})References:
userEvent.clear
- Type:
(element: Element) => Promise<void>
此方法会清除输入元素的内容。
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('clears input', async () => {
const input = screen.getByRole('input')
await userEvent.fill(input, 'foo')
expect(input).toHaveValue('foo')
await userEvent.clear(input)
expect(input).toHaveValue('')
})References:
userEvent.selectOptions
- Type:
(element: Element, values: HTMLElement | HTMLElement[] | string | string[], options?: UserEventSelectOptions) => Promise<void>
The userEvent.selectOptions allows selecting a value in a <select> element.
WARNING
如果 select 元素没有 multiple 属性,Vitest 将只选择数组中的第一个元素。
与 @testing-library 不同,Vitest 目前不支持 listbox,但我们计划在将来添加对它的支持。
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('clears input', async () => {
const select = screen.getByRole('select')
await userEvent.selectOptions(select, 'Option 1')
expect(select).toHaveValue('option-1')
await userEvent.selectOptions(select, 'option-1')
expect(select).toHaveValue('option-1')
await userEvent.selectOptions(select, [
screen.getByRole('option', { name: 'Option 1' }),
screen.getByRole('option', { name: 'Option 2' }),
])
expect(select).toHaveValue(['option-1', 'option-2'])
})WARNING
webdriverio provider 不支持选择多个元素,因为它不提供选择多个元素的 API。
References:
- Playwright
locator.selectOptionAPI - WebdriverIO
element.selectByIndexAPI - testing-library
selectOptionsAPI
userEvent.hover
- Type:
(element: Element, options?: UserEventHoverOptions) => Promise<void>
该方法将光标位置移动到所选元素上。有关此方法如何工作的详细说明,请参阅 provider 的文档。
WARNING
如果使用的是 webdriverio provider,光标默认会移动到元素的中心。
如果使用的是 playwright provider,光标会移动到元素的某个可见点。
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('hovers logo element', async () => {
const logo = screen.getByRole('img', { name: /logo/ })
await userEvent.hover(logo)
})References:
userEvent.unhover
- Type:
(element: Element, options?: UserEventHoverOptions) => Promise<void>
其作用与 userEvent.hover 相同,但会将光标移至 document.body 元素。
WARNING
默认情况下,光标位置位于主体元素的中心(在 webdriverio provider 中)或某个可见位置(在 playwright provider中),因此如果当前悬停的元素已经位于相同位置,本方法将不起作用。
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
test('unhover logo element', async () => {
const logo = screen.getByRole('img', { name: /logo/ })
await userEvent.unhover(logo)
})References:
userEvent.dragAndDrop
- Type:
(source: Element, target: Element, options?: UserEventDragAndDropOptions) => Promise<void>
将源元素拖到目标元素的顶部。不要忘记,源元素的draggable属性必须设置为 true。
import { userEvent } from '@vitest/browser/context'
import { screen } from '@testing-library/dom'
import '@testing-library/jest-dom' // adds support for "toHaveTextContent"
test('drag and drop works', async () => {
const source = screen.getByRole('img', { name: /logo/ })
const target = screen.getByTestId('logo-target')
await userEvent.dragAndDrop(source, target)
expect(target).toHaveTextContent('Logo is processed')
})WARNING
preview provider不支持此 API。
References: