Skip to content
Vitest 2
Main Navigation 指南API配置瀏覽器模式高級
3.2.0
2.1.9
1.6.1
0.34.6

繁體中文

English
简体中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

繁體中文

English
简体中文
Español
Français
Русский
Português – Brasil
Deutsch
日本語
한국어
Italiano
Polski
Türkçe
čeština
magyar

外觀

Sidebar Navigation

Why Browser Mode?

Getting Started

Context API

Interactivity API

Locators

Assertion API

Commands API

本頁導覽

互動 API ​

Vitest 實作了 @testing-library/user-event API 的子集,並利用 Chrome DevTools Protocol 或 webdriver 來模擬事件行為,而非直接觸發事件。這種方式能讓瀏覽器行為更可靠,並與使用者實際互動的方式更一致。

ts
import { userEvent } from '@vitest/browser/context';

await userEvent.click(document.querySelector('.button'));

幾乎所有 userEvent 方法都會繼承其提供者的選項。若要在您的 IDE 中查看所有可用的選項,請根據您使用的提供者,將 webdriver 或 playwright 類型加入 tsconfig.json 檔案:

json
{
  "compilerOptions": {
    "types": ["@vitest/browser/providers/playwright"]
  }
}
json
{
  "compilerOptions": {
    "types": ["@vitest/browser/providers/webdriverio"]
  }
}

userEvent.setup ​

ts
function setup(): UserEvent;

建立一個新的使用者事件實例。如果您需要維持鍵盤狀態,以便正確模擬按鍵按下與釋放,此方法會很有用。

WARNING

與 @testing-library/user-event 不同,來自 @vitest/browser/context 的預設 userEvent 實例只會建立一次,而非每次呼叫其方法時都建立!您可以在此程式碼片段中看到兩者運作方式的差異:

ts
import { userEvent as vitestUserEvent } from '@vitest/browser/context';
import { userEvent as originalUserEvent } from '@testing-library/user-event';

await vitestUserEvent.keyboard('{Shift}'); // 按下 Shift 鍵但不釋放
await vitestUserEvent.keyboard('{/Shift}'); // 釋放 Shift

await originalUserEvent.keyboard('{Shift}'); // 按下 Shift 鍵但不釋放
await originalUserEvent.keyboard('{/Shift}'); // 沒有釋放 Shift,因為狀態是獨立的

這種行為更符合實際操作,因為我們並非模擬鍵盤,而是實際按下 Shift 鍵。維持原始行為可能會在輸入欄位時導致非預期的問題。

userEvent.click ​

ts
function click(
  element: Element | Locator,
  options?: UserEventClickOptions
): Promise<void>;

對指定的元素執行點擊操作。此方法繼承提供者的選項。有關此方法詳細的運作方式,請參閱您所使用提供者的文件。

ts
import { page, userEvent } from '@vitest/browser/context';

test('clicks on an element', async () => {
  const logo = page.getByRole('img', { name: /logo/ });

  await userEvent.click(logo);
  // 或者您可以直接在定位器上呼叫方法
  await logo.click();
});

參考資料:

  • Playwright locator.click API
  • WebdriverIO element.click API
  • testing-library click API

userEvent.dblClick ​

ts
function dblClick(
  element: Element | Locator,
  options?: UserEventDoubleClickOptions
): Promise<void>;

觸發元素的雙擊事件。

有關此方法詳細的運作方式,請參閱您所使用提供者的文件。

ts
import { page, userEvent } from '@vitest/browser/context';

test('triggers a double click on an element', async () => {
  const logo = page.getByRole('img', { name: /logo/ });

  await userEvent.dblClick(logo);
  // 或者您可以直接在定位器上呼叫方法
  await logo.dblClick();
});

參考資料:

  • Playwright locator.dblclick API
  • WebdriverIO element.doubleClick API
  • testing-library dblClick API

userEvent.tripleClick ​

ts
function tripleClick(
  element: Element | Locator,
  options?: UserEventTripleClickOptions
): Promise<void>;

觸發元素的三次點擊事件。由於瀏覽器 API 中沒有原生的 tripleclick 事件,此方法會連續觸發三次點擊事件。因此,您必須檢查 click event detail(evt.detail === 3)來過濾並識別三次點擊事件。

有關此方法詳細的運作方式,請參閱您所使用提供者的文件。

ts
import { page, userEvent } from '@vitest/browser/context';

test('triggers a triple click on an element', async () => {
  const logo = page.getByRole('img', { name: /logo/ });
  let tripleClickFired = false;
  logo.addEventListener('click', evt => {
    if (evt.detail === 3) {
      tripleClickFired = true;
    }
  });

  await userEvent.tripleClick(logo);
  // 或者您可以直接在定位器上呼叫方法
  await logo.tripleClick();

  expect(tripleClickFired).toBe(true);
});

參考資料:

  • Playwright locator.click API:透過設定 clickCount: 3 來實作。
  • WebdriverIO browser.action API:透過 actions API 實作,執行 move 加上連續三次 down + up + pause 事件。
  • testing-library tripleClick API

userEvent.fill ​

ts
function fill(element: Element | Locator, text: string): Promise<void>;

設定 input、textarea 或 contenteditable 欄位的值。此方法會在設定新值之前移除輸入欄位中的任何現有文字。

ts
import { page, userEvent } from '@vitest/browser/context';

test('update input', async () => {
  const input = page.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}

  // 或者您可以直接在定位器上呼叫方法
  await input.fill('foo'); // input.value == foo
});

此方法會聚焦元素,填入內容,並在填入後觸發 input 事件。您可以使用空字串來清除欄位。

TIP

此 API 比使用 userEvent.type 或 userEvent.keyboard 更快,但它不支援 user-event keyboard 語法(例如,{Shift}{selectall})。

在您不需要輸入特殊字元或對按鍵事件進行精確控制的情況下,我們建議使用此 API 而非 userEvent.type。

參考資料:

  • Playwright locator.fill API
  • WebdriverIO element.setValue API
  • testing-library type API

userEvent.keyboard ​

ts
function keyboard(text: string): Promise<void>;

userEvent.keyboard 允許您觸發鍵盤按鍵。如果任何輸入欄位有焦點,它會將字元輸入到該輸入欄位中。否則,它會在目前聚焦的元素上觸發鍵盤事件(如果沒有聚焦的元素,則為 document.body)。

此 API 支援 user-event keyboard 語法。

ts
import { userEvent } from '@vitest/browser/context';

test('trigger keystrokes', async () => {
  await userEvent.keyboard('foo'); // 轉換為依次輸入:f、o、o
  await userEvent.keyboard('{{a[['); // 轉換為:{、a、[
  await userEvent.keyboard('{Shift}{f}{o}{o}'); // 轉換為:Shift、f、o、o
  await userEvent.keyboard('{a>5}'); // 按住 a 鍵不放並觸發 5 次 keydown 事件
  await userEvent.keyboard('{a>5/}'); // 按下 a 觸發 5 次 keydown 然後釋放
});

參考資料:

  • Playwright Keyboard API
  • WebdriverIO action('key') API
  • testing-library type API

userEvent.tab ​

ts
function tab(options?: UserEventTabOptions): Promise<void>;

傳送 Tab 鍵事件。這是 userEvent.keyboard('{tab}') 的簡寫。

ts
import { page, userEvent } from '@vitest/browser/context';

test('tab works', async () => {
  const [input1, input2] = page.getByRole('input').elements();

  expect(input1).toHaveFocus();

  await userEvent.tab();

  expect(input2).toHaveFocus();

  await userEvent.tab({ shift: true });

  expect(input1).toHaveFocus();
});

參考資料:

  • Playwright Keyboard API
  • WebdriverIO action('key') API
  • testing-library tab API

userEvent.type ​

ts
function type(
  element: Element | Locator,
  text: string,
  options?: UserEventTypeOptions
): Promise<void>;

WARNING

如果您不依賴 特殊字元(例如,{shift} 或 {selectall}),建議使用 userEvent.fill 以獲得更好的效能。

type 方法實作了 @testing-library/user-event 的 type 工具,其底層建構在 keyboard API 之上。

此函數允許您將字元輸入到 input/textarea/conteneditable 元素中。它支援 user-event keyboard 語法。

如果您只需要按下字元而不需要輸入,請使用 userEvent.keyboard API。

ts
import { page, userEvent } from '@vitest/browser/context';

test('update input', async () => {
  const input = page.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[
});

INFO

Vitest 不會在定位器上提供 .type 方法,例如 input.type,因為它僅用於與 userEvent 函式庫相容。考慮改用 .fill,因為它更快。

參考資料:

  • Playwright locator.press API
  • WebdriverIO action('key') API
  • testing-library type API

userEvent.clear ​

ts
function clear(element: Element | Locator): Promise<void>;

此方法用於清除輸入元素的內容。

ts
import { page, userEvent } from '@vitest/browser/context';

test('clears input', async () => {
  const input = page.getByRole('input');

  await userEvent.fill(input, 'foo');
  expect(input).toHaveValue('foo');

  await userEvent.clear(input);
  // 或者您可以直接在定位器上呼叫方法
  await input.clear();

  expect(input).toHaveValue('');
});

參考資料:

  • Playwright locator.clear API
  • WebdriverIO element.clearValue API
  • testing-library clear API

userEvent.selectOptions ​

ts
function selectOptions(
  element: Element | Locator,
  values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
  options?: UserEventSelectOptions
): Promise<void>;

userEvent.selectOptions 允許在 <select> 元素中選擇值。

WARNING

如果 select 元素沒有 multiple 屬性,Vitest 只會選擇陣列中的第一個元素。

與 @testing-library 不同,Vitest 目前不支援 listbox,但我們計劃在未來新增支援。

ts
import { page, userEvent } from '@vitest/browser/context';

test('clears input', async () => {
  const select = page.getByRole('select');

  await userEvent.selectOptions(select, 'Option 1');
  // 或者您可以直接在定位器上呼叫方法
  await select.selectOptions('Option 1');

  expect(select).toHaveValue('option-1');

  await userEvent.selectOptions(select, 'option-1');
  expect(select).toHaveValue('option-1');

  await userEvent.selectOptions(select, [
    page.getByRole('option', { name: 'Option 1' }),
    page.getByRole('option', { name: 'Option 2' }),
  ]);
  expect(select).toHaveValue(['option-1', 'option-2']);
});

WARNING

webdriverio 提供者不支援選擇多個元素,因為它沒有提供相關 API。

參考資料:

  • Playwright locator.selectOption API
  • WebdriverIO element.selectByIndex API
  • testing-library selectOptions API

userEvent.hover ​

ts
function hover(
  element: Element | Locator,
  options?: UserEventHoverOptions
): Promise<void>;

此方法將游標移動到選定的元素上方。有關此方法詳細的運作方式,請參閱您所使用提供者的文件。

WARNING

如果您使用 webdriverio 提供者,游標預設會移動到元素的中心。

如果您使用 playwright 提供者,游標會移動到元素的「某個」可見位置。

ts
import { page, userEvent } from '@vitest/browser/context';

test('hovers logo element', async () => {
  const logo = page.getByRole('img', { name: /logo/ });

  await userEvent.hover(logo);
  // 或者您可以直接在定位器上呼叫方法
  await logo.hover();
});

參考資料:

  • Playwright locator.hover API
  • WebdriverIO element.moveTo API
  • testing-library hover API

userEvent.unhover ​

ts
function unhover(
  element: Element | Locator,
  options?: UserEventHoverOptions
): Promise<void>;

這與 userEvent.hover 的運作方式相同,但會將游標移動到 document.body 元素。

WARNING

預設情況下,游標位置位於 body 元素的「某個」可見位置(在 playwright 提供者中)或中心(在 webdriverio 提供者中)。因此,如果目前懸停的元素已經在相同位置,此方法將無效。

ts
import { page, userEvent } from '@vitest/browser/context';

test('unhover logo element', async () => {
  const logo = page.getByRole('img', { name: /logo/ });

  await userEvent.unhover(logo);
  // 或者您可以直接在定位器上呼叫方法
  await logo.unhover();
});

參考資料:

  • Playwright locator.hover API
  • WebdriverIO element.moveTo API
  • testing-library hover API

userEvent.upload ​

ts
function upload(
  element: Element | Locator,
  files: string[] | string | File[] | File
): Promise<void>;

將檔案輸入元素的內容更改為包含指定的檔案。

ts
import { page, userEvent } from '@vitest/browser/context';

test('can upload a file', async () => {
  const input = page.getByRole('button', { name: /Upload files/ });

  const file = new File(['file'], 'file.png', { type: 'image/png' });

  await userEvent.upload(input, file);
  // 或者您可以直接在定位器上呼叫方法
  await input.upload(file);

  // 您也可以使用相對於測試檔案的檔案路徑
  await userEvent.upload(input, '../fixtures/file.png');
});

WARNING

webdriverio 提供者僅在 chrome 和 edge 瀏覽器中支援此命令,且目前僅支援字串類型的檔案路徑。

參考資料:

  • Playwright locator.setInputFiles API
  • WebdriverIO browser.uploadFile API
  • testing-library upload API

userEvent.dragAndDrop ​

ts
function dragAndDrop(
  source: Element | Locator,
  target: Element | Locator,
  options?: UserEventDragAndDropOptions
): Promise<void>;

將來源元素拖曳到目標元素上方。請記住,source 元素必須將 draggable 屬性設定為 true。

ts
import { page, userEvent } from '@vitest/browser/context';

test('drag and drop works', async () => {
  const source = page.getByRole('img', { name: /logo/ });
  const target = page.getByTestId('logo-target');

  await userEvent.dragAndDrop(source, target);
  // 或者您可以直接在定位器上呼叫方法
  await source.dropTo(target);

  await expect.element(target).toHaveTextContent('Logo is processed');
});

WARNING

預設的 preview 提供者不支援此 API。

參考資料:

  • Playwright frame.dragAndDrop API
  • WebdriverIO element.dragAndDrop API
Pager
上一頁Context API
下一頁Locators

以 MIT 授權條款 發布。

版權所有 (c) 2021-Present Vitest Team

https://v2.vitest.dev/guide/browser/interactivity-api

以 MIT 授權條款 發布。

版權所有 (c) 2021-Present Vitest Team