API d'interactivité
Vitest implémente un sous-ensemble des API de @testing-library/user-event
en utilisant le Protocole Chrome DevTools ou Webdriver plutôt que de simuler des événements. Cette approche garantit un comportement plus fiable et plus conforme à l'interaction réelle des utilisateurs avec une page dans un navigateur.
import { userEvent } from '@vitest/browser/context';
await userEvent.click(document.querySelector('.button'));
Presque toutes les méthodes userEvent
héritent des options de leur fournisseur. Pour bénéficier de l'autocomplétion des options dans votre IDE, ajoutez les types webdriver
ou playwright
(selon votre fournisseur) à votre fichier de configuration de démarrage ou à un fichier de configuration (selon ce qui est inclus dans votre tsconfig.json
) :
/// <reference types="@vitest/browser/providers/playwright" />
/// <reference types="@vitest/browser/providers/webdriverio" />
userEvent.setup
function setup(): UserEvent;
Crée une nouvelle instance d'événement utilisateur. Cette fonction est utile pour maintenir l'état du clavier, permettant ainsi d'appuyer et de relâcher les touches correctement.
WARNING
Contrairement à @testing-library/user-event
, l'instance userEvent
par défaut de @vitest/browser/context
est créée une seule fois et n'est pas recréée à chaque appel de ses méthodes. Vous pouvez observer la différence de comportement dans l'extrait suivant :
import { userEvent as vitestUserEvent } from '@vitest/browser/context';
import { userEvent as originalUserEvent } from '@testing-library/user-event';
await vitestUserEvent.keyboard('{Shift}'); // Appuie sur Shift sans le relâcher
await vitestUserEvent.keyboard('{/Shift}'); // Relâche Shift
await originalUserEvent.keyboard('{Shift}'); // Appuie sur Shift sans le relâcher
await originalUserEvent.keyboard('{/Shift}'); // N'a PAS relâché Shift car l'état est différent
Ce comportement est plus pertinent car nous n'émulons pas le clavier ; nous appuyons réellement sur la touche Shift. Conserver le comportement original pourrait entraîner des problèmes inattendus lors de la saisie dans un champ.
userEvent.click
function click(
element: Element | Locator,
options?: UserEventClickOptions
): Promise<void>;
Clique sur un élément. Cette méthode hérite des options du fournisseur. Veuillez vous référer à la documentation de votre fournisseur pour une explication détaillée de son fonctionnement.
import { page, userEvent } from '@vitest/browser/context';
test('clicks on an element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.click(logo);
// ou vous pouvez y accéder directement via le localisateur
await logo.click();
});
Références :
userEvent.dblClick
function dblClick(
element: Element | Locator,
options?: UserEventDoubleClickOptions
): Promise<void>;
Déclenche un événement de double-clic sur un élément.
Veuillez vous référer à la documentation de votre fournisseur pour une explication détaillée du fonctionnement de cette méthode.
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);
// ou vous pouvez y accéder directement via le localisateur
await logo.dblClick();
});
Références :
userEvent.tripleClick
function tripleClick(
element: Element | Locator,
options?: UserEventTripleClickOptions
): Promise<void>;
Déclenche un événement de triple-clic sur un élément. Puisqu'il n'existe pas de triple-clic
dans l'API native du navigateur, cette méthode déclenchera trois événements de clic consécutifs. Vous devrez donc vérifier la propriété detail
de l'événement de clic (evt.detail === 3
) pour le filtrer.
Veuillez vous référer à la documentation de votre fournisseur pour une explication détaillée du fonctionnement de cette méthode.
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);
// ou vous pouvez y accéder directement via le localisateur
await logo.tripleClick();
expect(tripleClickFired).toBe(true);
});
Références :
- API Playwright
locator.click
: implémenté viaclick
avecclickCount: 3
. - API WebdriverIO
browser.action
: implémenté via l'API d'actions avecmove
plus trois événementsdown + up + pause
consécutifs. - API testing-library
tripleClick
userEvent.fill
function fill(element: Element | Locator, text: string): Promise<void>;
Définit une valeur pour un champ input
, textarea
ou un élément contenteditable
, en supprimant tout texte existant avant de définir la nouvelle valeur.
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}
// ou vous pouvez y accéder directement via le localisateur
await input.fill('foo'); // input.value == foo
});
Cette méthode focalise l'élément, le remplit et déclenche un événement input
après le remplissage. Vous pouvez utiliser une chaîne vide pour vider le champ.
TIP
Cette API est plus rapide que l'utilisation de userEvent.type
ou userEvent.keyboard
, mais elle ne prend pas en charge la syntaxe keyboard
de user-event (par exemple, {Shift}{selectall}
).
Nous recommandons d'utiliser cette API plutôt que userEvent.type
dans les situations où vous n'avez pas besoin de saisir des caractères spéciaux ou d'avoir un contrôle précis sur les événements de frappe.
Références :
userEvent.keyboard
function keyboard(text: string): Promise<void>;
userEvent.keyboard
vous permet de déclencher des frappes au clavier. Si un champ de saisie est focalisé, elle tapera des caractères dans ce champ. Sinon, elle déclenchera des événements clavier sur l'élément actuellement focalisé (ou document.body
s'il n'y a pas d'éléments focalisés).
Cette API prend en charge la syntaxe keyboard
de user-event.
import { userEvent } from '@vitest/browser/context';
test('trigger keystrokes', async () => {
await userEvent.keyboard('foo'); // équivaut à : f, o, o
await userEvent.keyboard('{{a[['); // équivaut à : {, a, [
await userEvent.keyboard('{Shift}{f}{o}{o}'); // équivaut à : Shift, f, o, o
await userEvent.keyboard('{a>5}'); // appuie sur 'a' sans relâcher et déclenche 5 événements de pression de touche
await userEvent.keyboard('{a>5/}'); // appuie sur 'a' pendant 5 événements de pression de touche puis la relâche
});
Références :
userEvent.tab
function tab(options?: UserEventTabOptions): Promise<void>;
Envoie un événement de touche Tab
. C'est un raccourci pour 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();
});
Références :
userEvent.type
function type(
element: Element | Locator,
text: string,
options?: UserEventTypeOptions
): Promise<void>;
WARNING
Si vous n'avez pas besoin des caractères spéciaux (par exemple, {shift}
ou {selectall}
), il est recommandé d'utiliser userEvent.fill
à la place pour de meilleures performances.
La méthode type
implémente l'utilitaire type
de @testing-library/user-event
, qui est construit sur l'API keyboard
.
Cette fonction vous permet de taper des caractères dans un élément input
, textarea
ou contenteditable
. Elle prend en charge la syntaxe keyboard
de user-event.
Si vous avez juste besoin d'appuyer sur des caractères sans les saisir dans un champ, utilisez 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 n'expose pas la méthode .type
sur le localisateur (contrairement à input.type
) car elle n'existe que pour des raisons de compatibilité avec la bibliothèque userEvent
. Envisagez d'utiliser .fill
à la place, car c'est plus rapide.
Références :
userEvent.clear
function clear(
element: Element | Locator,
options?: UserEventClearOptions
): Promise<void>;
Cette méthode efface le contenu de l'élément d'entrée.
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);
// ou vous pouvez y accéder directement via le localisateur
await input.clear();
expect(input).toHaveValue('');
});
Références :
userEvent.selectOptions
function selectOptions(
element: Element | Locator,
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;
userEvent.selectOptions
permet de sélectionner une ou plusieurs valeurs dans un élément <select>
.
WARNING
Si l'élément select
n'a pas l'attribut multiple
, Vitest ne sélectionnera que le premier élément du tableau de valeurs fourni.
Contrairement à @testing-library
, Vitest ne prend pas en charge les listbox pour le moment, mais nous prévoyons d'y ajouter la prise en charge à l'avenir.
import { page, userEvent } from '@vitest/browser/context';
test('clears input', async () => {
const select = page.getByRole('select');
await userEvent.selectOptions(select, 'Option 1');
// ou vous pouvez y accéder directement via le localisateur
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
Le fournisseur webdriverio
ne prend pas en charge la sélection de plusieurs éléments car il ne propose pas d'API à cet effet.
Références :
- API Playwright
locator.selectOption
- API WebdriverIO
element.selectByIndex
- API testing-library
selectOptions
userEvent.hover
function hover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;
Cette méthode déplace la position du curseur vers l'élément sélectionné. Veuillez vous référer à la documentation de votre fournisseur pour une explication détaillée du fonctionnement de cette méthode.
WARNING
Si vous utilisez le fournisseur webdriverio
, le curseur se positionnera par défaut au centre de l'élément.
Si vous utilisez le fournisseur playwright
, le curseur se déplace vers un point visible quelconque de l'élément.
import { page, userEvent } from '@vitest/browser/context';
test('hovers logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.hover(logo);
// ou vous pouvez y accéder directement via le localisateur
await logo.hover();
});
Références :
userEvent.unhover
function unhover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;
Cette méthode fonctionne de la même manière que userEvent.hover
, mais déplace le curseur vers l'élément document.body
.
WARNING
Par défaut, la position du curseur est à un endroit visible quelconque (avec le fournisseur playwright
) ou au centre (avec le fournisseur webdriverio
) de l'élément body
. Par conséquent, si l'élément actuellement survolé est déjà à la même position, cette méthode sera sans effet.
import { page, userEvent } from '@vitest/browser/context';
test('unhover logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.unhover(logo);
// ou vous pouvez y accéder directement via le localisateur
await logo.unhover();
});
Références :
userEvent.upload
function upload(
element: Element | Locator,
files: string[] | string | File[] | File,
options?: UserEventUploadOptions
): Promise<void>;
Modifie un champ de saisie de fichier pour qu'il contienne les fichiers spécifiés.
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);
// ou vous pouvez y accéder directement via le localisateur
await input.upload(file);
// vous pouvez également utiliser des chemins de fichiers relatifs à la racine du projet
await userEvent.upload(input, './fixtures/file.png');
});
WARNING
Le fournisseur webdriverio
ne prend en charge cette commande que dans les navigateurs chrome
et edge
. Il ne prend également en charge que les types de chaînes pour le moment.
Références :
userEvent.dragAndDrop
function dragAndDrop(
source: Element | Locator,
target: Element | Locator,
options?: UserEventDragAndDropOptions
): Promise<void>;
Déplace l'élément source vers l'élément cible. N'oubliez pas que l'élément source
doit avoir l'attribut draggable
défini sur 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);
// ou vous pouvez y accéder directement via le localisateur
await source.dropTo(target);
await expect.element(target).toHaveTextContent('Logo is processed');
});
WARNING
Cette API n'est pas prise en charge par le fournisseur preview
par défaut.
Références :
userEvent.copy
function copy(): Promise<void>;
Permet de copier le texte sélectionné dans le presse-papiers.
import { page, userEvent } from '@vitest/browser/context';
test('copy and paste', async () => {
// écrire dans 'source'
await userEvent.click(page.getByPlaceholder('source'));
await userEvent.keyboard('hello');
// sélectionner et copier 'source'
await userEvent.dblClick(page.getByPlaceholder('source'));
await userEvent.copy();
// coller dans 'target'
await userEvent.click(page.getByPlaceholder('target'));
await userEvent.paste();
await expect
.element(page.getByPlaceholder('source'))
.toHaveTextContent('hello');
await expect
.element(page.getByPlaceholder('target'))
.toHaveTextContent('hello');
});
Références :
userEvent.cut
function cut(): Promise<void>;
Permet de couper le texte sélectionné dans le presse-papiers.
import { page, userEvent } from '@vitest/browser/context';
test('copy and paste', async () => {
// écrire dans 'source'
await userEvent.click(page.getByPlaceholder('source'));
await userEvent.keyboard('hello');
// sélectionner et couper 'source'
await userEvent.dblClick(page.getByPlaceholder('source'));
await userEvent.cut();
// coller dans 'target'
await userEvent.click(page.getByPlaceholder('target'));
await userEvent.paste();
await expect.element(page.getByPlaceholder('source')).toHaveTextContent('');
await expect
.element(page.getByPlaceholder('target'))
.toHaveTextContent('hello');
});
Références :
userEvent.paste
function paste(): Promise<void>;
Permet de coller le texte du presse-papiers. Voir userEvent.copy
et userEvent.cut
pour des exemples d'utilisation.
Références :