API de Interatividade
O Vitest implementa um subconjunto das APIs do @testing-library/user-event utilizando o Chrome DevTools Protocol ou webdriver. Diferente de simular eventos, essa abordagem interage diretamente com o navegador, tornando o comportamento mais confiável e consistente com a forma como os usuários interagem com uma página.
import { userEvent } from '@vitest/browser/context';
await userEvent.click(document.querySelector('.button'));Praticamente todos os métodos userEvent herdam suas opções do provedor configurado. Para visualizar todas as opções disponíveis em sua IDE, adicione os tipos webdriver ou playwright (conforme seu provedor) ao seu arquivo de configuração ou a um arquivo de configuração (dependendo do que está incluído no seu tsconfig.json):
/// <reference types="@vitest/browser/providers/playwright" />/// <reference types="@vitest/browser/providers/webdriverio" />userEvent.setup
function setup(): UserEvent;Cria uma nova instância de evento de usuário. Isso é útil para manter o estado do teclado, permitindo pressionar e soltar teclas corretamente.
WARNING
Ao contrário do @testing-library/user-event, a instância padrão de userEvent de @vitest/browser/context é criada uma única vez, e não a cada chamada de seus métodos! Você pode observar a diferença de comportamento neste trecho:
import { userEvent as vitestUserEvent } from '@vitest/browser/context';
import { userEvent as originalUserEvent } from '@testing-library/user-event';
await vitestUserEvent.keyboard('{Shift}'); // pressiona Shift sem soltar
await vitestUserEvent.keyboard('{/Shift}'); // solta Shift
await originalUserEvent.keyboard('{Shift}'); // pressiona Shift sem soltar
await originalUserEvent.keyboard('{/Shift}'); // NÃO solta Shift porque a instância é diferenteEste comportamento é mais útil porque não emulamos o teclado; na verdade, pressionamos a tecla Shift. Manter o comportamento original poderia causar problemas inesperados ao digitar em um campo.
userEvent.click
function click(
element: Element | Locator,
options?: UserEventClickOptions
): Promise<void>;Clica em um elemento. Herda as opções do provedor. Consulte a documentação do seu provedor para uma explicação detalhada sobre como este método funciona.
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 você pode acessá-lo diretamente no localizador
await logo.click();
});Referências:
userEvent.dblClick
function dblClick(
element: Element | Locator,
options?: UserEventDoubleClickOptions
): Promise<void>;Aciona um evento de clique duplo em um elemento.
Consulte a documentação do seu provedor para uma explicação detalhada sobre como este método funciona.
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 você pode acessá-lo diretamente no localizador
await logo.dblClick();
});Referências:
userEvent.tripleClick
function tripleClick(
element: Element | Locator,
options?: UserEventTripleClickOptions
): Promise<void>;Dispara um evento de clique triplo em um elemento. Como não existe um evento tripleclick na API do navegador, este método disparará três eventos de clique em sequência. Portanto, você deve verificar o detalhe do evento de clique para filtrar o evento: evt.detail === 3.
Consulte a documentação do seu provedor para uma explicação detalhada sobre como este método funciona.
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 você pode acessá-lo diretamente no localizador
await logo.tripleClick();
expect(tripleClickFired).toBe(true);
});Referências:
- Playwright
locator.clickAPI: implementado viaclickcomclickCount: 3. - WebdriverIO
browser.actionAPI: implementado via API de ações commovemais três eventosdown + up + pauseem sequência. - testing-library
tripleClickAPI
userEvent.fill
function fill(element: Element | Locator, text: string): Promise<void>;Define um valor para o campo input/textarea/contenteditable. Isso removerá qualquer texto existente no campo antes de definir o novo 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}
// ou você pode acessá-lo diretamente no localizador
await input.fill('foo'); // input.value == foo
});Este método foca o elemento, preenche-o e dispara um evento input após o preenchimento. Você pode usar uma string vazia para limpar o campo.
TIP
Esta API é mais rápida que userEvent.type ou userEvent.keyboard, mas não suporta a sintaxe de teclado do user-event (ex: {Shift}{selectall}).
Recomendamos usar esta API em vez de userEvent.type em situações em que você não precisa inserir caracteres especiais ou ter um controle mais detalhado sobre os eventos de pressionamento de tecla.
Referências:
userEvent.keyboard
function keyboard(text: string): Promise<void>;O userEvent.keyboard permite simular pressionamento de teclas. Se qualquer campo de entrada estiver focado, ele digitará caracteres nesse campo. Caso contrário, ele disparará eventos de teclado no elemento atualmente focado (document.body se não houver elementos focados).
Esta API suporta a sintaxe de teclado do 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}'); // pressiona a sem soltar e dispara 5 keydown
await userEvent.keyboard('{a>5/}'); // pressiona a por 5 keydown e depois solta
});Referências:
userEvent.tab
function tab(options?: UserEventTabOptions): Promise<void>;Envia um evento de tecla Tab. É um atalho para 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();
});Referências:
userEvent.type
function type(
element: Element | Locator,
text: string,
options?: UserEventTypeOptions
): Promise<void>;WARNING
Se você não precisar de caracteres especiais (por exemplo, {shift} ou {selectall}), é recomendado usar userEvent.fill para um melhor desempenho.
O método type implementa a funcionalidade type do @testing-library/user-event, baseada na API keyboard.
Esta função permite que você digite caracteres em um elemento input/textarea/contenteditable. Ela suporta a sintaxe de teclado do user-event.
Se você precisar apenas pressionar caracteres sem um campo de entrada, use a 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
O Vitest não expõe o método .type no localizador como input.type porque ele existe apenas para compatibilidade com a biblioteca userEvent. Considere usar .fill, pois é mais rápido.
Referências:
userEvent.clear
function clear(
element: Element | Locator,
options?: UserEventClearOptions
): Promise<void>;Este método limpa o conteúdo do 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);
// ou você pode acessá-lo diretamente no localizador
await input.clear();
expect(input).toHaveValue('');
});Referências:
userEvent.selectOptions
function selectOptions(
element: Element | Locator,
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;O userEvent.selectOptions permite selecionar um valor em um elemento <select>.
WARNING
Se o elemento <select> não tiver o atributo multiple, o Vitest selecionará apenas o primeiro elemento no array de valores fornecido.
Ao contrário do @testing-library, o Vitest não oferece suporte a listbox atualmente, mas planejamos adicioná-lo no futuro.
import { page, userEvent } from '@vitest/browser/context';
test('clears input', async () => {
const select = page.getByRole('select');
await userEvent.selectOptions(select, 'Option 1');
// ou você pode acessá-lo diretamente no localizador
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
O provedor webdriverio não oferece suporte à seleção de múltiplos elementos porque não fornece uma API para isso.
Referências:
- Playwright
locator.selectOptionAPI - WebdriverIO
element.selectByIndexAPI - testing-library
selectOptionsAPI
userEvent.hover
function hover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;Este método move o cursor para o elemento selecionado. Consulte a documentação do seu provedor para uma explicação detalhada sobre como este método funciona.
WARNING
Se você estiver usando o provedor webdriverio, o cursor é movido para o centro do elemento por padrão.
Se você estiver usando o provedor playwright, o cursor é movido para um ponto visível do elemento.
import { page, userEvent } from '@vitest/browser/context';
test('hovers logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.hover(logo);
// ou você pode acessá-lo diretamente no localizador
await logo.hover();
});Referências:
userEvent.unhover
function unhover(
element: Element | Locator,
options?: UserEventHoverOptions
): Promise<void>;Isso funciona da mesma forma que userEvent.hover, mas move o cursor para o elemento document.body.
WARNING
Por padrão, a posição do cursor está em um ponto visível (no provedor playwright) ou no centro (no provedor webdriverio) do elemento body. Portanto, se o elemento atualmente com o mouse sobre ele já estiver na mesma posição, este método não terá efeito.
import { page, userEvent } from '@vitest/browser/context';
test('unhover logo element', async () => {
const logo = page.getByRole('img', { name: /logo/ });
await userEvent.unhover(logo);
// ou você pode acessá-lo diretamente no localizador
await logo.unhover();
});Referências:
userEvent.upload
function upload(
element: Element | Locator,
files: string[] | string | File[] | File,
options?: UserEventUploadOptions
): Promise<void>;Altera um elemento de entrada de arquivo para conter os arquivos 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);
// ou você pode acessá-lo diretamente no localizador
await input.upload(file);
// você também pode usar caminhos de arquivo relativos à raiz do projeto
await userEvent.upload(input, './fixtures/file.png');
});WARNING
O provedor webdriverio suporta este comando apenas nos navegadores chrome e edge. Atualmente, ele suporta apenas tipos de string (caminhos de arquivo).
Referências:
userEvent.dragAndDrop
function dragAndDrop(
source: Element | Locator,
target: Element | Locator,
options?: UserEventDragAndDropOptions
): Promise<void>;Arrasta o elemento de origem para o elemento de destino. Lembre-se de que o elemento source deve ter o atributo draggable definido como 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 você pode acessá-lo diretamente no localizador
await source.dropTo(target);
await expect.element(target).toHaveTextContent('Logo is processed');
});WARNING
Esta API não é compatível com o provedor preview padrão.
Referências:
userEvent.copy
function copy(): Promise<void>;Copia o texto selecionado para a área de transferência.
import { page, userEvent } from '@vitest/browser/context';
test('copy and paste', async () => {
// escreve em 'source'
await userEvent.click(page.getByPlaceholder('source'));
await userEvent.keyboard('hello');
// seleciona e copia 'source'
await userEvent.dblClick(page.getByPlaceholder('source'));
await userEvent.copy();
// cola em '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');
});Referências:
userEvent.cut
function cut(): Promise<void>;Corta o texto selecionado para a área de transferência.
import { page, userEvent } from '@vitest/browser/context';
test('copy and paste', async () => {
// escreve em 'source'
await userEvent.click(page.getByPlaceholder('source'));
await userEvent.keyboard('hello');
// seleciona e corta 'source'
await userEvent.dblClick(page.getByPlaceholder('source'));
await userEvent.cut();
// cola em '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');
});Referências:
userEvent.paste
function paste(): Promise<void>;Cola o texto da área de transferência. Consulte userEvent.copy e userEvent.cut para exemplos de uso.
Referências: