跳至主要內容

實用工具 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 參數可以透過選項的值、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])
})