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 different
Este 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.dblclick
de Playwright - API
element.doubleClick
de WebdriverIO - API
dblClick
de 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.click
de Playwright: implementado a través declick
conclickCount: 3
. - API
browser.action
de WebdriverIO: implementado a través de la API de acciones conmove
más tres eventosdown + up + pause
seguidos. - API
tripleClick
de 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.selectOption
de Playwright - API
element.selectByIndex
de WebdriverIO - API
selectOptions
de 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.setInputFiles
de Playwright - API
browser.uploadFile
de WebdriverIO - API
upload
de 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: