API de Interacción
Vitest implementa un subconjunto de las APIs de @testing-library/user-event utilizando el Chrome DevTools Protocol o webdriver en lugar de simular eventos. Esto resulta en un comportamiento del navegador más fiable y coherente con la forma en que los usuarios interactúan con una página.
import { userEvent } from '@vitest/browser/context';
await userEvent.click(document.querySelector('.button'));Casi todos los métodos de userEvent utilizan las opciones de su proveedor. Para ver todas las opciones disponibles en tu IDE, añade los tipos webdriver o playwright (dependiendo de tu proveedor) a tu archivo tsconfig.json:
{
"compilerOptions": {
"types": ["@vitest/browser/providers/playwright"]
}
}{
"compilerOptions": {
"types": ["@vitest/browser/providers/webdriverio"]
}
}userEvent.setup
function setup(): UserEvent;Crea una nueva instancia de evento de usuario. Esto es útil si necesitas mantener el estado del teclado para gestionar correctamente las pulsaciones y liberaciones de teclas.
WARNING
A diferencia de @testing-library/user-event, la instancia predeterminada de userEvent de @vitest/browser/context se crea una única vez, no cada vez que se llaman sus métodos. Puedes ver la diferencia en cómo funciona en este fragmento:
import { userEvent as vitestUserEvent } from '@vitest/browser/context';
import { userEvent as originalUserEvent } from '@testing-library/user-event';
await vitestUserEvent.keyboard('{Shift}'); // press shift without releasing
await vitestUserEvent.keyboard('{/Shift}'); // releases shift
await originalUserEvent.keyboard('{Shift}'); // press shift without releasing
await originalUserEvent.keyboard('{/Shift}'); // DID NOT release shift because the state is differentEste comportamiento es más útil porque no emulamos el teclado; realmente presionamos la tecla Shift, por lo que mantener el comportamiento original podría causar problemas inesperados al escribir en el campo.
userEvent.click
function click(
element: Element | Locator,
options?: UserEventClickOptions
): Promise<void>;Hace clic en un elemento. Utiliza las opciones del proveedor. Consulta la documentación de tu proveedor para obtener una explicación detallada de cómo funciona este método.
import { page, userEvent } from '@vitest/browser/context';
test('clicks on an element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.click(logo);
// or you can access it directly on the locator
await logo.click();
});Referencias:
userEvent.dblClick
function dblClick(
element: Element | Locator,
options?: UserEventDoubleClickOptions
): Promise<void>;Desencadena un evento de doble clic en un elemento.
Consulta la documentación de tu proveedor para obtener una explicación detallada de cómo funciona este método.
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);
// or you can access it directly on the locator
await logo.dblClick();
});Referencias:
- API
locator.dblclickde Playwright - API
element.doubleClickde WebdriverIO - API
dblClickde testing-library
userEvent.tripleClick
function tripleClick(
element: Element | Locator,
options?: UserEventTripleClickOptions
): Promise<void>;Desencadena un evento de triple clic en un elemento. Como no existe tripleclick en la API del navegador, este método disparará tres eventos de clic seguidos, por lo que debes verificar el detalle del evento click para filtrar el evento: evt.detail === 3.
Consulta la documentación de tu proveedor para obtener una explicación detallada de cómo funciona este método.
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);
// or you can access it directly on the locator
await logo.tripleClick();
expect(tripleClickFired).toBe(true);
});Referencias:
- API
locator.clickde Playwright: implementado a través declickconclickCount: 3. - API
browser.actionde WebdriverIO: implementado a través de la API de acciones conmovemás tres eventosdown + up + pauseseguidos. - API
tripleClickde testing-library
userEvent.fill
function fill(element: Element | Locator, text: string): Promise<void>;Establece un valor en el campo input/textarea/conteneditable. Esto eliminará cualquier texto existente en el campo de entrada antes de establecer el nuevo valor.
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}
// or you can access it directly on the locator
await input.fill('foo'); // input.value == foo
});Este método pone el foco en el elemento, lo llena y dispara un evento input después de llenarlo. Puedes usar una cadena vacía para borrar el campo.
TIP
Esta API es más rápida que usar userEvent.type o userEvent.keyboard, pero no admite la sintaxis de keyboard de user-event (por ejemplo, {Shift}{selectall}).
Recomendamos usar esta API en lugar de userEvent.type en situaciones en las que no necesites introducir caracteres especiales o tener un control granular sobre los eventos de pulsación de teclas.
Referencias:
userEvent.keyboard
function keyboard(text: string): Promise<void>;El método userEvent.keyboard te permite disparar pulsaciones de teclado. Si algún campo de entrada tiene el foco, escribirá caracteres en esa entrada. De lo contrario, disparará eventos de teclado en el elemento actualmente enfocado (document.body si no hay elementos enfocados).
Esta API soporta la sintaxis de keyboard de user-event.
import { userEvent } from '@vitest/browser/context';
test('trigger keystrokes', async () => {
await userEvent.keyboard('foo'); // translates to: f, o, o
await userEvent.keyboard('{{a[['); // translates to: {, a, [
await userEvent.keyboard('{Shift}{f}{o}{o}'); // translates to: Shift, f, o, o
await userEvent.keyboard('{a>5}'); // press a without releasing it and trigger 5 keydown
await userEvent.keyboard('{a>5/}'); // press a for 5 keydown and then release it
});Referencias:
userEvent.tab
function tab(options?: UserEventTabOptions): Promise<void>;Envía un evento de tecla Tab. Esto es una abreviatura de 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();
});Referencias:
userEvent.type
function type(
element: Element | Locator,
text: string,
options?: UserEventTypeOptions
): Promise<void>;WARNING
Si no dependes de caracteres especiales (por ejemplo, {shift} o {selectall}), se recomienda usar userEvent.fill en su lugar para un mejor rendimiento.
El método type implementa la utilidad type de @testing-library/user-event construida sobre la API keyboard.
Esta función te permite escribir caracteres en un elemento input/textarea/conteneditable. Soporta la sintaxis de keyboard de user-event.
Si solo necesitas presionar caracteres sin un campo de entrada, usa la 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 no expone el método .type en el localizador como input.type porque solo existe por compatibilidad con la librería userEvent. Considera usar .fill en su lugar, ya que es más rápido.
Referencias:
userEvent.clear
function clear(element: Element | Locator): Promise<void>;Este método borra el contenido del campo de entrada.
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);
// or you can access it directly on the locator
await input.clear();
expect(input).toHaveValue('');
});Referencias:
userEvent.selectOptions
function selectOptions(
element: Element | Locator,
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;El método userEvent.selectOptions permite seleccionar un valor en un elemento <select>.
WARNING
Si el elemento select no tiene el atributo multiple, Vitest seleccionará solo el primer elemento del array.
A diferencia de @testing-library, Vitest no admite listbox en este momento, pero planeamos añadir soporte en el futuro.
import { page, userEvent } from '@vitest/browser/context';
test('clears input', async () => {
const select = page.getByRole('select');
await userEvent.selectOptions(select, 'Option 1');
// or you can access it directly on the 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
El proveedor webdriverio no admite la selección de múltiples elementos porque no proporciona una API para hacerlo.
Referencias:
- API
locator.selectOptionde Playwright - API
element.selectByIndexde WebdriverIO - API
selectOptionsde testing-library
userEvent.hover
function hover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;Este método mueve la posición del cursor al elemento seleccionado. Consulta la documentación de tu proveedor para obtener una explicación detallada de cómo funciona este método.
WARNING
Si estás utilizando el proveedor webdriverio, el cursor se moverá al centro del elemento por defecto.
Si estás utilizando el proveedor playwright, el cursor se mueve a "algún" punto visible del elemento.
import { page, userEvent } from '@vitest/browser/context';
test('hovers logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.hover(logo);
// or you can access it directly on the locator
await logo.hover();
});Referencias:
userEvent.unhover
function unhover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;Esto funciona igual que userEvent.hover, pero mueve el cursor al elemento document.body en su lugar.
WARNING
Por defecto, la posición del cursor está en "algún" lugar visible (en el proveedor playwright) o en el centro (en el proveedor webdriverio) del elemento body. Si el elemento sobre el que se está pasando el ratón ya se encuentra en la misma posición, este método no tendrá efecto.
import { page, userEvent } from '@vitest/browser/context';
test('unhover logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.unhover(logo);
// or you can access it directly on the locator
await logo.unhover();
});Referencias:
userEvent.upload
function upload(
element: Element | Locator,
files: string[] | string | File[] | File
): Promise<void>;Cambia un elemento de entrada de archivo para que tenga los archivos especificados.
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);
// or you can access it directly on the locator
await input.upload(file);
// you can also use file paths relative to the test file
await userEvent.upload(input, '../fixtures/file.png');
});WARNING
El proveedor webdriverio solo admite este comando en los navegadores chrome y edge. También solo soporta tipos de cadena en este momento.
Referencias:
- API
locator.setInputFilesde Playwright - API
browser.uploadFilede WebdriverIO - API
uploadde testing-library
userEvent.dragAndDrop
function dragAndDrop(
source: Element | Locator,
target: Element | Locator,
options?: UserEventDragAndDropOptions
): Promise<void>;Arrastra el elemento origen al elemento destino. Es necesario que el elemento source tenga el atributo draggable establecido a 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);
// or you can access it directly on the locator
await source.dropTo(target);
await expect.element(target).toHaveTextContent('Logo is processed');
});WARNING
Esta API no es compatible con el proveedor predeterminado preview.
Referencias: