API di interazione
Vitest implementa un sottoinsieme delle API di @testing-library/user-event
utilizzando il Chrome DevTools Protocol o webdriver anziché simulare eventi. Questo approccio rende il comportamento del browser più affidabile e coerente con il modo in cui gli utenti interagiscono con una pagina.
import { userEvent } from '@vitest/browser/context';
await userEvent.click(document.querySelector('.button'));
La maggior parte dei metodi di userEvent
eredita le opzioni dal provider configurato. Per visualizzare tutte le opzioni disponibili nel tuo IDE, aggiungi i tipi webdriver
o playwright
(a seconda del provider che utilizzi) al tuo file tsconfig.json
:
{
"compilerOptions": {
"types": ["@vitest/browser/providers/playwright"]
}
}
{
"compilerOptions": {
"types": ["@vitest/browser/providers/webdriverio"]
}
}
userEvent.setup
function setup(): UserEvent;
Crea una nuova istanza di user event. Questo è utile se è necessario mantenere lo stato della tastiera per gestire correttamente la pressione e il rilascio dei tasti.
WARNING
A differenza di @testing-library/user-event
, l'istanza predefinita di userEvent
fornita da @vitest/browser/context
viene creata una sola volta, non ad ogni chiamata dei suoi metodi! Puoi osservare la differenza di comportamento in questo snippet:
import { userEvent as vitestUserEvent } from '@vitest/browser/context';
import { userEvent as originalUserEvent } from '@testing-library/user-event';
await vitestUserEvent.keyboard('{Shift}'); // preme il tasto Shift senza rilasciare
await vitestUserEvent.keyboard('{/Shift}'); // rilascia il tasto Shift
await originalUserEvent.keyboard('{Shift}'); // preme il tasto Shift senza rilasciare
await originalUserEvent.keyboard('{/Shift}'); // NON ha rilasciato il tasto Shift perché lo stato è diverso
Questo comportamento è più utile perché non emuliamo la tastiera, ma premiamo effettivamente il tasto Shift. Mantenere il comportamento originale causerebbe problemi inaspettati durante la digitazione in un campo.
userEvent.click
function click(
element: Element | Locator,
options?: UserEventClickOptions
): Promise<void>;
Esegue un clic su un elemento. Eredita le opzioni dal provider. Per una spiegazione dettagliata su come funziona questo metodo, fare riferimento alla documentazione del proprio provider.
import { page, userEvent } from '@vitest/browser/context';
test('clicks on an element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.click(logo);
// o puoi chiamarlo direttamente sul locator
await logo.click();
});
Riferimenti:
userEvent.dblClick
function dblClick(
element: Element | Locator,
options?: UserEventDoubleClickOptions
): Promise<void>;
Genera un evento di doppio clic su un elemento.
Si prega di fare riferimento alla documentazione del proprio provider per una spiegazione dettagliata su come funziona questo metodo.
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);
// o puoi accedervi direttamente sul locator
await logo.dblClick();
});
Riferimenti:
- API
locator.dblclick
di Playwright - API
element.doubleClick
di WebdriverIO - API
dblClick
di testing-library
userEvent.tripleClick
function tripleClick(
element: Element | Locator,
options?: UserEventTripleClickOptions
): Promise<void>;
Genera un evento di triplo clic su un elemento. Poiché non esiste un evento tripleclick
nell'API del browser, questo metodo attiverà tre eventi click in successione. Pertanto, è necessario controllare il dettaglio dell'evento click per filtrare l'evento desiderato: evt.detail === 3
.
Si prega di fare riferimento alla documentazione del proprio provider per una spiegazione dettagliata su come funziona questo metodo.
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);
// o puoi accedervi direttamente sul locator
await logo.tripleClick();
expect(tripleClickFired).toBe(true);
});
Riferimenti:
- API
locator.click
di Playwright: implementato tramiteclick
conclickCount: 3
. - API
browser.action
di WebdriverIO: implementato tramite l'API delle azioni conmove
più tre eventidown + up + pause
in successione. - API
tripleClick
di testing-library
userEvent.fill
function fill(element: Element | Locator, text: string): Promise<void>;
Imposta un valore nel campo input
/textarea
/contenteditable
. Questo metodo rimuoverà qualsiasi testo esistente nell'input prima di impostare il nuovo valore.
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}
// o puoi accedervi direttamente sul locator
await input.fill('foo'); // input.value == foo
});
Questo metodo dà il focus all'elemento, lo riempie e attiva un evento input
dopo il riempimento. Puoi usare una stringa vuota per svuotare il campo.
TIP
Questa API è più veloce rispetto all'utilizzo di userEvent.type
o userEvent.keyboard
, ma non supporta la sintassi keyboard
di user-event (ad esempio, {Shift}{selectall}
).
Consigliamo di utilizzare questa API al posto di userEvent.type
nelle situazioni in cui non è necessario inserire caratteri speciali o avere un controllo granulare sugli eventi di pressione dei tasti.
Riferimenti:
userEvent.keyboard
function keyboard(text: string): Promise<void>;
Il metodo userEvent.keyboard
ti consente di attivare sequenze di tasti. Se un input ha il focus, digiterà i caratteri in quell'input. Altrimenti, attiverà gli eventi della tastiera sull'elemento attualmente a fuoco (document.body
se non ci sono elementi a fuoco).
Questa API supporta la sintassi keyboard
di user-event.
import { userEvent } from '@vitest/browser/context';
test('trigger keystrokes', async () => {
await userEvent.keyboard('foo'); // equivale a: f, o, o
await userEvent.keyboard('{{a[['); // equivale a: {, a, [
await userEvent.keyboard('{Shift}{f}{o}{o}'); // equivale a: Shift, f, o, o
await userEvent.keyboard('{a>5}'); // preme il tasto 'a' senza rilasciarlo e attiva 5 eventi keydown
await userEvent.keyboard('{a>5/}'); // preme il tasto 'a' per 5 eventi keydown e poi lo rilascia
});
Riferimenti:
userEvent.tab
function tab(options?: UserEventTabOptions): Promise<void>;
Genera un evento per il tasto Tab
. Questa è una scorciatoia per 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();
});
Riferimenti:
userEvent.type
function type(
element: Element | Locator,
text: string,
options?: UserEventTypeOptions
): Promise<void>;
WARNING
Se non ti affidi a caratteri speciali (ad esempio, {shift}
o {selectall}
), si consiglia di utilizzare userEvent.fill
invece per prestazioni migliori.
Il metodo type
implementa l'utility type
di @testing-library/user-event
costruita sull'API keyboard
.
Questa funzione ti consente di digitare caratteri in un elemento input/textarea/contenteditable. Supporta la sintassi keyboard
di user-event.
Se hai solo bisogno di premere caratteri senza un input, usa l'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 non espone il metodo .type
tramite il locator come input.type
perché esiste solo per compatibilità con la libreria userEvent
. Considera l'utilizzo di .fill
invece poiché è più veloce.
Riferimenti:
userEvent.clear
function clear(element: Element | Locator): Promise<void>;
Questo metodo pulisce il contenuto dell'elemento input.
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);
// o puoi accedervi direttamente sul locator
await input.clear();
expect(input).toHaveValue('');
});
Riferimenti:
userEvent.selectOptions
function selectOptions(
element: Element | Locator,
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;
Il metodo userEvent.selectOptions
consente di selezionare un valore in un elemento <select>
.
WARNING
Se l'elemento select non ha l'attributo multiple
, Vitest selezionerà solo il primo elemento nell'array fornito.
A differenza di @testing-library
, Vitest al momento non supporta listbox, ma prevediamo di aggiungere il supporto in futuro.
import { page, userEvent } from '@vitest/browser/context';
test('clears input', async () => {
const select = page.getByRole('select');
await userEvent.selectOptions(select, 'Option 1');
// o puoi accedervi direttamente sul locator
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
Il provider webdriverio
non supporta la selezione di più elementi contemporaneamente perché non fornisce un'API nativa per farlo.
Riferimenti:
- API
locator.selectOption
di Playwright - API
element.selectByIndex
di WebdriverIO - API
selectOptions
di testing-library
userEvent.hover
function hover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;
Questo metodo sposta il cursore sull'elemento selezionato. Si prega di fare riferimento alla documentazione del proprio provider per una spiegazione dettagliata su come funziona questo metodo.
WARNING
Se stai usando il provider webdriverio
, il cursore si sposterà al centro dell'elemento per impostazione predefinita.
Se stai usando il provider playwright
, il cursore si sposta in "un" punto visibile dell'elemento.
import { page, userEvent } from '@vitest/browser/context';
test('hovers logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.hover(logo);
// o puoi accedervi direttamente sul locator
await logo.hover();
});
Riferimenti:
userEvent.unhover
function unhover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;
Questo metodo funziona in modo simile a userEvent.hover
, ma sposta il cursore sull'elemento document.body
invece.
WARNING
Per impostazione predefinita, la posizione del cursore è in "un" punto visibile (nel provider playwright
) o al centro (nel provider webdriverio
) dell'elemento body. Pertanto, se il cursore si trova già in quella posizione, questo metodo potrebbe non avere alcun effetto visibile sull'elemento precedentemente hovered.
import { page, userEvent } from '@vitest/browser/context';
test('unhover logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.unhover(logo);
// o puoi accedervi direttamente sul locator
await logo.unhover();
});
Riferimenti:
userEvent.upload
function upload(
element: Element | Locator,
files: string[] | string | File[] | File
): Promise<void>;
Configura un elemento input di tipo file per avere i file specificati.
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);
// o puoi accedervi direttamente sul locator
await input.upload(file);
// puoi anche usare percorsi di file relativi al file di test
await userEvent.upload(input, '../fixtures/file.png');
});
WARNING
Il provider webdriverio
supporta questo comando solo nei browser chrome
ed edge
. Al momento supporta anche solo tipi stringa per i percorsi dei file.
Riferimenti:
- API
locator.setInputFiles
di Playwright - API
browser.uploadFile
di WebdriverIO - API
upload
di testing-library
userEvent.dragAndDrop
function dragAndDrop(
source: Element | Locator,
target: Element | Locator,
options?: UserEventDragAndDropOptions
): Promise<void>;
Trascina l'elemento di origine sull'elemento di destinazione. Non dimenticare che l'elemento source
deve avere l'attributo draggable
impostato su 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);
// o puoi accedervi direttamente sul locator
await source.dropTo(target);
await expect.element(target).toHaveTextContent('Logo is processed');
});
WARNING
Questa API non è supportata dal provider predefinito preview
.
Riferimenti: