Interaktivní API
Vitest implementuje podmnožinu API z @testing-library/user-event
pomocí Chrome DevTools Protocol nebo webdriver namísto simulace událostí. Tím je chování prohlížeče spolehlivější a konzistentnější s tím, jak uživatelé interagují se stránkou.
import { userEvent } from '@vitest/browser/context';
await userEvent.click(document.querySelector('.button'));
Téměř každá metoda userEvent
dědí možnosti od svého poskytovatele. Pro zobrazení všech dostupných možností ve vašem IDE přidejte typy webdriver
nebo playwright
(v závislosti na vašem poskytovateli) do souboru tsconfig.json
.
{
"compilerOptions": {
"types": ["@vitest/browser/providers/playwright"]
}
}
{
"compilerOptions": {
"types": ["@vitest/browser/providers/webdriverio"]
}
}
userEvent.setup
function setup(): UserEvent;
Vytvoří novou instanci uživatelské události. To je užitečné, pokud potřebujete zachovat stav klávesnice pro správné stisknutí a uvolnění kláves.
WARNING
Na rozdíl od @testing-library/user-event
je výchozí instance userEvent
z @vitest/browser/context
vytvořena jednou, nikoli pokaždé, když jsou volány její metody. Rozdíl v chování můžete vidět v tomto úryvku:
import { userEvent as vitestUserEvent } from '@vitest/browser/context';
import { userEvent as originalUserEvent } from '@testing-library/user-event';
await vitestUserEvent.keyboard('{Shift}'); // podrží Shift stisknutý
await vitestUserEvent.keyboard('{/Shift}'); // uvolní Shift
await originalUserEvent.keyboard('{Shift}'); // podrží Shift stisknutý
await originalUserEvent.keyboard('{/Shift}'); // NEUvolní Shift, protože stav je jiný
Toto chování je užitečnější, protože neemulujeme klávesnici, ale skutečně stiskneme Shift. Zachování původního chování by způsobilo neočekávané problémy při psaní do pole.
userEvent.click
function click(
element: Element | Locator,
options?: UserEventClickOptions
): Promise<void>;
Klikne na prvek. Dědí možnosti od poskytovatele. Podrobné vysvětlení, jak tato metoda funguje, najdete v dokumentaci vašeho poskytovatele.
import { page, userEvent } from '@vitest/browser/context';
test('clicks on an element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.click(logo);
// nebo k němu můžete přistupovat přímo na lokátoru
await logo.click();
});
Reference:
userEvent.dblClick
function dblClick(
element: Element | Locator,
options?: UserEventDoubleClickOptions
): Promise<void>;
Spustí událost dvojkliku na elementu.
Podrobné vysvětlení, jak tato metoda funguje, najdete v dokumentaci vašeho poskytovatele.
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);
// nebo k němu můžete přistupovat přímo na lokátoru
await logo.dblClick();
});
Reference:
userEvent.tripleClick
function tripleClick(
element: Element | Locator,
options?: UserEventTripleClickOptions
): Promise<void>;
Spustí událost trojkliku na prvku. Jelikož v API prohlížeče neexistuje tripleclick
, tato metoda spustí tři události kliknutí za sebou. Proto musíte zkontrolovat detail události kliknutí pro filtrování události: evt.detail === 3
.
Podrobné vysvětlení, jak tato metoda funguje, najdete v dokumentaci vašeho poskytovatele.
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);
// nebo k němu můžete přistupovat přímo na lokátoru
await logo.tripleClick();
expect(tripleClickFired).toBe(true);
});
Reference:
- Playwright
locator.click
API: implementováno pomocíclick
sclickCount: 3
. - WebdriverIO
browser.action
API: implementováno pomocí actions API smove
plus třemi událostmidown + up + pause
za sebou. - testing-library
tripleClick
API
userEvent.fill
function fill(element: Element | Locator, text: string): Promise<void>;
Nastaví hodnotu do pole input/textarea/contenteditable
. Tím se před nastavením nové hodnoty odstraní veškerý existující text v inputu.
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}
// nebo k němu můžete přistupovat přímo na lokátoru
await input.fill('foo'); // input.value == foo
});
Tato metoda zaostřuje prvek, naplní jej a po vyplnění spustí událost input
. Prázdný řetězec můžete použít k vymazání pole.
TIP
Toto API je rychlejší než použití userEvent.type
nebo userEvent.keyboard
, ale nepodporuje syntaxi keyboard
z user-event (např. {Shift}{selectall}
).
Doporučujeme používat toto API namísto userEvent.type
v situacích, kdy nepotřebujete zadávat speciální znaky nebo mít detailní kontrolu nad událostmi stisku kláves.
Reference:
userEvent.keyboard
function keyboard(text: string): Promise<void>;
userEvent.keyboard
vám umožňuje spouštět stisky kláves. Pokud je zaostřen jakýkoli input, bude do něj psát znaky. Jinak spustí události klávesnice na aktuálně zaostřeném prvku (document.body
, pokud nejsou žádné zaostřené prvky).
Toto API podporuje syntaxi keyboard
z user-event.
import { userEvent } from '@vitest/browser/context';
test('trigger keystrokes', async () => {
await userEvent.keyboard('foo'); // odpovídá: f, o, o
await userEvent.keyboard('{{a[['); // odpovídá: {, a, [
await userEvent.keyboard('{Shift}{f}{o}{o}'); // odpovídá: Shift, f, o, o
await userEvent.keyboard('{a>5}'); // podrží 'a' stisknuté a spustí 5 keydown
await userEvent.keyboard('{a>5/}'); // stiskne 'a' pro 5 keydown a poté jej uvolní
});
Reference:
userEvent.tab
function tab(options?: UserEventTabOptions): Promise<void>;
Odešle událost klávesy Tab
. Toto je zkratka pro userEvent.keyboard('{tab}')
.
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();
});
Reference:
userEvent.type
function type(
element: Element | Locator,
text: string,
options?: UserEventTypeOptions
): Promise<void>;
WARNING
Pokud se nespoléháte na speciální znaky (např. {shift}
nebo {selectall}
), doporučuje se místo toho použít userEvent.fill
pro lepší výkon.
Metoda type
implementuje utilitu type
z @testing-library/user-event
postavenou na API keyboard
.
Tato funkce vám umožňuje psát znaky do prvku input/textarea/contenteditable. Podporuje syntaxi keyboard
z user-event.
Pokud potřebujete pouze stisknout znaky bez inputu, použijte API userEvent.keyboard
.
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 nezpřístupňuje metodu .type
na lokátoru jako input.type
, protože existuje pouze pro kompatibilitu s knihovnou userEvent
. Zvažte místo toho použití .fill
, protože je rychlejší.
Reference:
userEvent.clear
function clear(element: Element | Locator): Promise<void>;
Tato metoda vymaže obsah input elementu.
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);
// nebo k němu můžete přistupovat přímo na lokátoru
await input.clear();
expect(input).toHaveValue('');
});
Reference:
userEvent.selectOptions
function selectOptions(
element: Element | Locator,
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;
userEvent.selectOptions
umožňuje vybrat hodnotu v prvku <select>
.
WARNING
Pokud prvek select nemá atribut multiple
, Vitest vybere pouze první prvek v poli.
Na rozdíl od @testing-library
Vitest v současné době nepodporuje listbox, ale plánujeme přidat podporu v budoucnu.
import { page, userEvent } from '@vitest/browser/context';
test('clears input', async () => {
const select = page.getByRole('select');
await userEvent.selectOptions(select, 'Option 1');
// nebo k němu můžete přistupovat přímo na lokátoru
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
Poskytovatel webdriverio
nepodporuje výběr více prvků, protože k tomu neposkytuje API.
Reference:
- Playwright
locator.selectOption
API - WebdriverIO
element.selectByIndex
API - testing-library
selectOptions
API
userEvent.hover
function hover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;
Tato metoda přesune pozici kurzoru na vybraný prvek. Podrobné vysvětlení, jak tato metoda funguje, najdete v dokumentaci vašeho poskytovatele.
WARNING
Pokud používáte poskytovatele webdriverio
, kurzor se ve výchozím nastavení přesune do středu prvku.
Pokud používáte poskytovatele playwright
, kurzor se přesune na "nějaký" viditelný bod prvku.
import { page, userEvent } from '@vitest/browser/context';
test('hovers logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.hover(logo);
// nebo k němu můžete přistupovat přímo na lokátoru
await logo.hover();
});
Reference:
userEvent.unhover
function unhover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;
Toto funguje stejně jako userEvent.hover
, ale místo toho přesune kurzor na prvek document.body
.
WARNING
Ve výchozím nastavení je pozice kurzoru na "nějakém" viditelném místě (u poskytovatele playwright
) nebo ve středu (u poskytovatele webdriverio
) prvku body. Pokud je aktuálně prvek pod kurzorem již na stejné pozici, tato metoda nebude mít žádný účinek.
import { page, userEvent } from '@vitest/browser/context';
test('unhover logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.unhover(logo);
// nebo k němu můžete přistupovat přímo na lokátoru
await logo.unhover();
});
Reference:
userEvent.upload
function upload(
element: Element | Locator,
files: string[] | string | File[] | File
): Promise<void>;
Změní vstupní prvek typu file tak, aby obsahoval zadané soubory.
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);
// nebo k němu můžete přistupovat přímo na lokátoru
await input.upload(file);
// můžete také použít cesty k souborům relativní k testovacímu souboru
await userEvent.upload(input, '../fixtures/file.png');
});
WARNING
Poskytovatel webdriverio
podporuje tento příkaz pouze v prohlížečích chrome
a edge
. V současné době také podporuje pouze typy string.
Reference:
userEvent.dragAndDrop
function dragAndDrop(
source: Element | Locator,
target: Element | Locator,
options?: UserEventDragAndDropOptions
): Promise<void>;
Přetáhne zdrojový prvek na cílový prvek. Nezapomeňte, že zdrojový prvek musí mít atribut draggable
nastaven na true
.
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);
// nebo k němu můžete přistupovat přímo na lokátoru
await source.dropTo(target);
await expect.element(target).toHaveTextContent('Logo is processed');
});
WARNING
Toto API není podporováno výchozím poskytovatelem preview
.
Reference: