跳至主要内容

实用程序 API

以下 API 在实际用户交互中没有一一对应的等效项。
因此,它们的行為是对如何将“感知”的用户交互转换为 DOM 上的实际事件的一种解释。

clear()

clear(element: Element): Promise<void>

此 API 可用于轻松清除可编辑元素。

  1. 聚焦元素
  2. 选择所有内容,如同浏览器菜单
  3. 删除内容,如同浏览器菜单
test('clear', async () => {
const user = userEvent.setup()

render(<textarea defaultValue="Hello, World!" />)

await user.clear(screen.getByRole('textbox'))

expect(screen.getByRole('textbox')).toHaveValue('')
})

如果元素无法聚焦或内容无法选择,则 Promise 会被拒绝。

selectOptions()、deselectOptions()

selectOptions(
element: Element,
values: HTMLElement | HTMLElement[] | string[] | string,
): Promise<void>
deselectOptions(
element: Element,
values: HTMLElement | HTMLElement[] | string[] | string,
): Promise<void>

HTMLSelectElementlistbox 中选择/取消选择给定的选项。

values 参数可以引用选项的 value、HTML 内容,或者只是提供元素本身。它也可以接受这些参数的数组。

仅当指定了 multiple 时,才可以在 HTMLSelectElement 中选择多个选项和/或取消选择选项。

test('selectOptions', async () => {
const user = userEvent.setup()

render(
<select multiple>
<option value="1">A</option>
<option value="2">B</option>
<option value="3">C</option>
</select>,
)

await user.selectOptions(screen.getByRole('listbox'), ['1', 'C'])

expect(screen.getByRole('option', {name: 'A'}).selected).toBe(true)
expect(screen.getByRole('option', {name: 'B'}).selected).toBe(false)
expect(screen.getByRole('option', {name: 'C'}).selected).toBe(true)
})
test('deselectOptions', async () => {
const user = userEvent.setup()

render(
<select multiple>
<option value="1">A</option>
<option value="2" selected>
B
</option>
<option value="3">C</option>
</select>,
)

await user.deselectOptions(screen.getByRole('listbox'), '2')

expect(screen.getByText('B').selected).toBe(false)
})

请注意,此 API 触发指针事件,因此会受到 pointerEventsCheck 的影响。

type()

type(
element: Element,
text: KeyboardInput,
options?: {
skipClick?: boolean
skipAutoClose?: boolean
initialSelectionStart?: number
initialSelectionEnd?: number
}
): Promise<void>

在输入元素中输入文字。

如果您只想模拟在键盘上按下按钮,则应使用 keyboard()
如果您只想方便地将一些文本插入输入字段或文本区域,则可以使用 type()

  1. 除非 skipClicktrue,否则会单击该元素。
  2. 如果设置了 initialSelectionStart,则在元素上设置选择。如果未设置 initialSelectionEnd,则会导致选择折叠。
  3. 按照 keyboard() 的方式输入给定的 text
  4. 除非 skipAutoClosetrue,否则会释放所有按下的键。
test('type into an input field', async () => {
const user = userEvent.setup()

render(<input defaultValue="Hello," />)
const input = screen.getByRole('textbox')

await user.type(input, ' World!')

expect(input).toHaveValue('Hello, World!')
})

upload()

upload(
element: HTMLElement,
fileOrFiles: File | File[],
): Promise<void>

更改文件输入,就像用户单击它并在结果的文件上传对话框中选择文件一样。

不匹配 accept 属性的文件将被自动丢弃,除非 applyAccept 设置为 false

test('upload file', async () => {
const user = userEvent.setup()

render(
<div>
<label htmlFor="file-uploader">Upload file:</label>
<input id="file-uploader" type="file" />
</div>,
)
const file = new File(['hello'], 'hello.png', {type: 'image/png'})
const input = screen.getByLabelText(/upload file/i)

await user.upload(input, file)

expect(input.files[0]).toBe(file)
expect(input.files.item(0)).toBe(file)
expect(input.files).toHaveLength(1)
})

test('upload multiple files', async () => {
const user = userEvent.setup()

render(
<div>
<label htmlFor="file-uploader">Upload file:</label>
<input id="file-uploader" type="file" multiple />
</div>,
)
const files = [
new File(['hello'], 'hello.png', {type: 'image/png'}),
new File(['there'], 'there.png', {type: 'image/png'}),
]
const input = screen.getByLabelText(/upload file/i)

await user.upload(input, files)

expect(input.files).toHaveLength(2)
expect(input.files[0]).toBe(files[0])
expect(input.files[1]).toBe(files[1])
})