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 é diferente
Este 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.click
API: implementado viaclick
comclickCount: 3
. - WebdriverIO
browser.action
API: implementado via API de ações commove
mais três eventosdown + up + pause
em sequência. - testing-library
tripleClick
API
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.selectOption
API - WebdriverIO
element.selectByIndex
API - testing-library
selectOptions
API
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: