Seletores
Um seletor representa um ou mais elementos. Cada seletor é definido por uma string que o identifica. O Vitest abstrai essa definição, fornecendo métodos convenientes que geram esses seletores internamente.
A API de seletores utiliza uma versão modificada dos seletores do Playwright, chamada Ivya. No entanto, o Vitest disponibiliza essa API para todos os provedores, e não apenas para o Playwright.
TIP
Esta página detalha o uso da API. Para uma compreensão mais aprofundada sobre seletores e sua aplicação, consulte a documentação "Locators" do Playwright.
getByRole
function getByRole(
role: ARIARole | string,
options?: LocatorByRoleOptions
): Locator;
Cria um localizador para um elemento com base em seu papel ARIA, atributos ARIA e nome acessível.
TIP
Se você precisa consultar um único elemento com getByText('O nome')
, é frequentemente mais eficaz usar getByRole(papelEsperado, { name: 'O nome' })
. A consulta por nome acessível não substitui outras consultas, como *ByAltText
ou *ByTitle
. Embora o nome acessível possa ser idêntico a esses atributos, ele não assume a funcionalidade deles.
Considere a seguinte estrutura DOM:
<h3>Sign up</h3>
<label>
Login
<input type="text" />
</label>
<label>
Password
<input type="password" />
</label>
<br />
<button>Submit</button>
Você pode localizar cada elemento por seu papel implícito:
await expect
.element(page.getByRole('heading', { name: 'Sign up' }))
.toBeVisible();
await page.getByRole('textbox', { name: 'Login' }).fill('admin');
await page.getByRole('textbox', { name: 'Password' }).fill('admin');
await page.getByRole('button', { name: /submit/i }).click();
WARNING
Os papéis são comparados por igualdade de string, sem herdar da hierarquia de papéis ARIA. Consequentemente, consultar um papel de superclasse como checkbox
não incluirá elementos com um papel de subclasse como switch
.
Por padrão, muitos elementos semânticos em HTML possuem um papel (por exemplo, <input type="radio">
tem o papel "radio"). Elementos não semânticos em HTML não possuem um papel; <div>
e <span>
sem semântica adicional retornam null
. O atributo role
pode adicionar semântica aos elementos.
Fornecer papéis via atributos role
ou aria-*
a elementos nativos que já possuem um papel implícito é altamente desencorajado pelas diretrizes ARIA.
Opções
exact: boolean
Define se o
name
deve ser correspondido exatamente: diferencia maiúsculas de minúsculas e corresponde à string completa. Desabilitado por padrão. Esta opção é ignorada sename
for uma expressão regular. Observe que a correspondência exata ainda normaliza espaços em branco.tsx<button>Hello World</button>; page.getByRole('button', { name: 'hello world' }); // ✅ page.getByRole('button', { name: 'hello world', exact: true }); // ❌ page.getByRole('button', { name: 'Hello World', exact: true }); // ✅
checked: boolean
Define se elementos marcados (definidos por
aria-checked
ou<input type="checkbox"/>
) devem ser incluídos. Por padrão, o filtro não é aplicado.Consulte
aria-checked
para mais informações.tsx<> <button role="checkbox" aria-checked="true" /> <input type="checkbox" checked /> </>; page.getByRole('checkbox', { checked: true }); // ✅ page.getByRole('checkbox', { checked: false }); // ❌
disabled: boolean
Define se elementos desabilitados devem ser incluídos. Por padrão, o filtro não é aplicado. Observe que, ao contrário de outros atributos, o estado
disabled
é herdado.Consulte
aria-disabled
para mais informações.tsx<input type="text" disabled />; page.getByRole('textbox', { disabled: true }); // ✅ page.getByRole('textbox', { disabled: false }); // ❌
expanded: boolean
Define se elementos expandidos devem ser incluídos. Por padrão, o filtro não é aplicado.
Consulte
aria-expanded
para mais informações.tsx<a aria-expanded="true" href="example.com"> Link </a>; page.getByRole('link', { expanded: true }); // ✅ page.getByRole('link', { expanded: false }); // ❌
includeHidden: boolean
Define se elementos que são normalmente excluídos da árvore de acessibilidade devem ser pesquisados. Por padrão, apenas elementos não ocultos são correspondidos pelo seletor de papel.
Observe que os papéis
none
epresentation
são sempre incluídos.tsx<button style="display: none" />; page.getByRole('button'); // ❌ page.getByRole('button', { includeHidden: false }); // ❌ page.getByRole('button', { includeHidden: true }); // ✅
level: number
Um atributo numérico geralmente presente para os papéis
heading
,listitem
,row
,treeitem
, com valores padrão para elementos<h1>-<h6>
. Por padrão, o filtro não é aplicado.Consulte
aria-level
para mais informações.tsx<> <h1>Heading Level One</h1> <div role="heading" aria-level="1"> Second Heading Level One </div> </>; page.getByRole('heading', { level: 1 }); // ✅ page.getByRole('heading', { level: 2 }); // ❌
name: string | RegExp
Um nome acessível. Por padrão, a correspondência não diferencia maiúsculas de minúsculas e busca por uma sub-string. Use a opção
exact
para controlar esse comportamento.tsx<button>Click Me!</button>; page.getByRole('button', { name: 'Click Me!' }); // ✅ page.getByRole('button', { name: 'click me!' }); // ✅ page.getByRole('button', { name: 'Click Me?' }); // ❌
pressed: boolean
Define se elementos pressionados devem ser incluídos. Por padrão, o filtro não é aplicado.
Consulte
aria-pressed
para mais informações.tsx<button aria-pressed="true">👍</button>; page.getByRole('button', { pressed: true }); // ✅ page.getByRole('button', { pressed: false }); // ❌
selected: boolean
Define se elementos selecionados devem ser incluídos. Por padrão, o filtro não é aplicado.
Consulte
aria-selected
para mais informações.tsx<button role="tab" aria-selected="true"> Vue </button>; page.getByRole('button', { selected: true }); // ✅ page.getByRole('button', { selected: false }); // ❌
Veja também
getByAltText
function getByAltText(text: string | RegExp, options?: LocatorOptions): Locator;
Cria um seletor capaz de encontrar um elemento com um atributo alt
que corresponde ao texto. Diferente da implementação da testing-library, o Vitest encontrará qualquer elemento que possua um atributo alt
correspondente.
<img alt="Incredibles 2 Poster" src="/incredibles-2.png" />;
page.getByAltText(/incredibles.*? poster/i); // ✅
page.getByAltText('non existing alt text'); // ❌
Opções
exact: boolean
Define se o
text
deve ser correspondido exatamente: diferencia maiúsculas de minúsculas e corresponde à string completa. Desabilitado por padrão. Esta opção é ignorada setext
for uma expressão regular. Observe que a correspondência exata ainda normaliza espaços em branco.
Veja também
getByLabelText
function getByLabelText(
text: string | RegExp,
options?: LocatorOptions
): Locator;
Cria um seletor capaz de encontrar um elemento que tenha um rótulo associado.
O seletor page.getByLabelText('Username')
encontrará todas as entradas no exemplo abaixo:
// relacionamento for/htmlFor entre o label e o id do elemento de formulário
<label for="username-input">Nome de usuário</label>
<input id="username-input" />
// O atributo aria-labelledby com elementos de formulário
<label id="username-label">Nome de usuário</label>
<input aria-labelledby="username-label" />
// Labels de encapsulamento (wrapper labels)
<label>Nome de usuário <input /></label>
// Labels de encapsulamento onde o texto do label está em outro elemento filho
<label>
<span>Nome de usuário</span>
<input />
</label>
// atributos aria-label
// Tenha cuidado porque este não é um label que os usuários podem ver na página, portanto, o propósito da sua entrada deve ser óbvio para usuários visuais.
<input aria-label="Nome de usuário" />
Opções
exact: boolean
Define se o
text
deve ser correspondido exatamente: diferencia maiúsculas de minúsculas e corresponde à string completa. Desabilitado por padrão. Esta opção é ignorada setext
for uma expressão regular. Observe que a correspondência exata ainda normaliza espaços em branco.
Veja também
getByPlaceholder
function getByPlaceholder(
text: string | RegExp,
options?: LocatorOptions
): Locator;
Cria um seletor capaz de encontrar um elemento que tenha o atributo placeholder
especificado. O Vitest encontrará qualquer elemento que possua um atributo placeholder
correspondente, não apenas input
.
<input placeholder="Username" />;
page.getByPlaceholder('Username'); // ✅
page.getByPlaceholder('not found'); // ❌
WARNING
Geralmente, é preferível usar um rótulo com getByLabelText
em vez de um placeholder.
Opções
exact: boolean
Define se o
text
deve ser correspondido exatamente: diferencia maiúsculas de minúsculas e corresponde à string completa. Desabilitado por padrão. Esta opção é ignorada setext
for uma expressão regular. Observe que a correspondência exata ainda normaliza espaços em branco.
Veja também
getByText
function getByText(text: string | RegExp, options?: LocatorOptions): Locator;
Cria um seletor capaz de encontrar um elemento que contém o texto especificado. O texto será correspondido ao nodeValue
do TextNode
ou ao valor do input se o tipo for button
ou reset
. A correspondência por texto sempre normaliza espaços em branco, mesmo com correspondência exata. Por exemplo, múltiplos espaços são convertidos em um único, quebras de linha em espaços, e espaços em branco iniciais e finais são ignorados.
<a href="/about">About ℹ️</a>;
page.getByText(/about/i); // ✅
page.getByText('about', { exact: true }); // ❌
TIP
Este seletor é útil para localizar elementos não interativos. Se você precisar localizar um elemento interativo, como um botão ou um input, prefira getByRole
.
Opções
exact: boolean
Define se o
text
deve ser correspondido exatamente: diferencia maiúsculas de minúsculas e corresponde à string completa. Desabilitado por padrão. Esta opção é ignorada setext
for uma expressão regular. Observe que a correspondência exata ainda normaliza espaços em branco.
Veja também
getByTitle
function getByTitle(text: string | RegExp, options?: LocatorOptions): Locator;
Cria um seletor capaz de encontrar um elemento que tenha o atributo title
especificado. Diferente do getByTitle
da testing-library, o Vitest não consegue encontrar elementos title
dentro de um SVG.
<span title="Delete" id="2"></span>;
page.getByTitle('Delete'); // ✅
page.getByTitle('Create'); // ❌
Opções
exact: boolean
Define se o
text
deve ser correspondido exatamente: diferencia maiúsculas de minúsculas e corresponde à string completa. Desabilitado por padrão. Esta opção é ignorada setext
for uma expressão regular. Observe que a correspondência exata ainda normaliza espaços em branco.
Veja também
getByTestId
function getByTestId(text: string | RegExp): Locator;
Cria um seletor capaz de encontrar um elemento que corresponde ao atributo de ID de teste especificado. Você pode configurar o nome do atributo com browser.locators.testIdAttribute
.
<div data-testid="custom-element" />;
page.getByTestId('custom-element'); // ✅
page.getByTestId('non-existing-element'); // ❌
WARNING
Recomenda-se usar isso somente quando os outros seletores não forem adequados para o seu caso de uso. Usar atributos data-testid
não se assemelha a como seu software é usado e deve ser evitado, se possível.
Opções
exact: boolean
Define se o
text
deve ser correspondido exatamente: diferencia maiúsculas de minúsculas e corresponde à string completa. Desabilitado por padrão. Esta opção é ignorada setext
for uma expressão regular. Observe que a correspondência exata ainda normaliza espaços em branco.
Veja também
nth
function nth(index: number): Locator;
Este método retorna um novo seletor que corresponde apenas a um índice específico dentro de um resultado de consulta de múltiplos elementos. A indexação é baseada em zero, nth(0)
seleciona o primeiro elemento. Ao contrário de elements()[n]
, o seletor nth
será tentado novamente até que o elemento esteja presente.
<div aria-label="one"><input /><input /><input /></div>
<div aria-label="two"><input /></div>
page.getByRole('textbox').nth(0); // ✅
page.getByRole('textbox').nth(4); // ❌
TIP
Antes de recorrer a nth
, você pode achar útil usar seletores encadeados para restringir sua pesquisa. Às vezes, não há uma maneira melhor de distinguir do que pela posição do elemento; embora isso possa levar a testes instáveis/intermitentes, é melhor do que nada.
page.getByLabel('two').getByRole('input'); // ✅ alternativa melhor para page.getByRole('textbox').nth(3)
page.getByLabel('one').getByRole('input'); // ❌ muito ambíguo
page.getByLabel('one').getByRole('input').nth(1); // ✅ compromisso pragmático
first
function first(): Locator;
Este método retorna um novo seletor que corresponde apenas ao primeiro índice de um resultado de consulta de múltiplos elementos. É uma forma abreviada de nth(0)
.
<input /> <input /> <input />
page.getByRole('textbox').first(); // ✅
last
function last(): Locator;
Este método retorna um novo seletor que corresponde apenas ao último índice de um resultado de consulta de múltiplos elementos. É uma forma abreviada de nth(-1)
.
<input /> <input /> <input />
page.getByRole('textbox').last(); // ✅
and
function and(locator: Locator): Locator;
Este método cria um novo seletor que corresponde tanto ao seletor pai quanto ao seletor fornecido. O exemplo a seguir encontra um botão com um título específico:
page.getByRole('button').and(page.getByTitle('Subscribe'));
or
function or(locator: Locator): Locator;
Este método cria um novo seletor que corresponde a um ou ambos os seletores.
WARNING
Observe que se o seletor corresponder a mais de um único elemento, chamar outro método pode lançar um erro se ele esperar um único elemento:
<>
<button>Click me</button>
<a href="https://vitest.dev">Error happened!</a>
</>;
page.getByRole('button').or(page.getByRole('link')).click(); // ❌ corresponde a múltiplos elementos
filter
function filter(options: LocatorOptions): Locator;
Este método refina o seletor de acordo com as opções, como filtrar por texto. Ele pode ser encadeado para aplicar vários filtros.
has
- Tipo:
Locator
Esta opção refina o seletor para encontrar elementos que contenham outros elementos correspondentes ao seletor fornecido. Por exemplo, com este HTML:
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>
Podemos restringir o seletor para encontrar apenas o article
com o texto Vitest
dentro:
page.getByRole('article').filter({ has: page.getByText('Vitest') }); // ✅
WARNING
O seletor fornecido (page.getByText('Vitest')
no exemplo) deve ser relativo ao seletor pai (page.getByRole('article')
no exemplo). Ele será pesquisado a partir do seletor pai, não da raiz do documento.
Ou seja, você não pode passar um seletor que busca o elemento fora do seletor pai:
page.getByText('Vitest').filter({ has: page.getByRole('article') }); // ❌
Este exemplo falhará porque o elemento article
está fora do elemento com o texto Vitest
.
TIP
Este método pode ser encadeado para restringir ainda mais o elemento:
page
.getByRole('article')
.filter({ has: page.getByRole('button', { name: 'delete row' }) })
.filter({ has: page.getByText('Vitest') });
hasNot
- Tipo:
Locator
Esta opção restringe o seletor para corresponder a elementos que não contêm outros elementos que correspondem ao seletor fornecido. Por exemplo, com este HTML:
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>
Podemos restringir o seletor para encontrar apenas o article
que não tem Rolldown
dentro.
page.getByRole('article').filter({ hasNot: page.getByText('Rolldown') }); // ✅
page.getByRole('article').filter({ hasNot: page.getByText('Vitest') }); // ❌
WARNING
Observe que o seletor fornecido é pesquisado em relação ao pai, não à raiz do documento, assim como a opção has
.
hasText
- Tipo:
string | RegExp
Esta opção restringe o seletor para corresponder apenas a elementos que contêm o texto fornecido em algum lugar dentro. Quando uma string
é passada, a correspondência não diferencia maiúsculas de minúsculas e busca por uma sub-string.
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>
Ambos os seletores encontrarão o mesmo elemento porque a pesquisa não diferencia maiúsculas de minúsculas:
page.getByRole('article').filter({ hasText: 'Vitest' }); // ✅
page.getByRole('article').filter({ hasText: 'Vite' }); // ✅
hasNotText
- Tipo:
string | RegExp
Esta opção restringe o seletor para corresponder apenas a elementos que não contêm o texto fornecido em algum lugar dentro. Quando uma string
é passada, a correspondência não diferencia maiúsculas de minúsculas e busca por uma sub-string.
Métodos
Todos os métodos são assíncronos e devem ser aguardados. A partir do Vitest 3, os testes falharão se um método não for utilizado com await
.
click
function click(options?: UserEventClickOptions): Promise<void>;
Clica em um elemento. Você pode usar as opções para definir a posição do cursor.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).click();
dblClick
function dblClick(options?: UserEventDoubleClickOptions): Promise<void>;
Aciona um evento de clique duplo em um elemento. Você pode usar as opções para definir a posição do cursor.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).dblClick();
tripleClick
function tripleClick(options?: UserEventTripleClickOptions): Promise<void>;
Aciona um evento de clique triplo em um elemento. Como não há tripleclick
na API do navegador, este método acionará três eventos de clique em sequência.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).tripleClick();
clear
function clear(options?: UserEventClearOptions): Promise<void>;
Limpa o conteúdo do campo de entrada.
import { page } from '@vitest/browser/context';
await page.getByRole('textbox', { name: 'Full Name' }).clear();
hover
function hover(options?: UserEventHoverOptions): Promise<void>;
Move o cursor para o elemento selecionado pelo seletor.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).hover();
unhover
function unhover(options?: UserEventHoverOptions): Promise<void>;
Isso funciona da mesma forma que locator.hover
, mas move o cursor para o elemento document.body
.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).unhover();
fill
function fill(text: string, options?: UserEventFillOptions): Promise<void>;
Define o valor do input
, textarea
ou elemento contenteditable
atual.
import { page } from '@vitest/browser/context';
await page.getByRole('input', { name: 'Full Name' }).fill('Mr. Bean');
dropTo
function dropTo(
target: Locator,
options?: UserEventDragAndDropOptions
): Promise<void>;
Arrasta o elemento atual para o local de destino.
import { page } from '@vitest/browser/context';
const paris = page.getByText('Paris');
const france = page.getByText('France');
await paris.dropTo(france);
selectOptions
function selectOptions(
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
options?: UserEventSelectOptions
): Promise<void>;
Seleciona um ou mais valores de um elemento <select>
.
import { page } from '@vitest/browser/context';
const languages = page.getByRole('select', { name: 'Languages' });
await languages.selectOptions('EN');
await languages.selectOptions(['ES', 'FR']);
await languages.selectOptions([
languages.getByRole('option', { name: 'Spanish' }),
languages.getByRole('option', { name: 'French' }),
]);
screenshot
function screenshot(
options: LocatorScreenshotOptions & { save: false }
): Promise<string>;
function screenshot(
options: LocatorScreenshotOptions & { base64: true }
): Promise<{
path: string;
base64: string;
}>;
function screenshot(
options?: LocatorScreenshotOptions & { base64?: false }
): Promise<string>;
Cria uma captura de tela do elemento correspondente ao seletor.
Você pode especificar o local de salvamento para a captura de tela usando a opção path
, que é relativa ao arquivo de teste atual. Se a opção path
não for definida, o Vitest usará por padrão browser.screenshotDirectory
(__screenshot__
por padrão), combinando-o com os nomes do arquivo e do teste para determinar o caminho da captura de tela.
Se você também precisar do conteúdo da captura de tela, pode especificar base64: true
para retorná-lo junto com o caminho onde a captura de tela é salva.
import { page } from '@vitest/browser/context';
const button = page.getByRole('button', { name: 'Click Me!' });
const path = await button.screenshot();
const { path, base64 } = await button.screenshot({
path: './button-click-me.png',
base64: true, // também retorna a string base64
});
// path - caminho completo para a captura de tela
// base64 - string codificada em base64 da captura de tela
AVISO 3.2.0+
Observe que screenshot
sempre retornará uma string base64 se save
for false
. O path
também é ignorado nesse caso.
query
function query(): Element | null;
Este método retorna um único elemento correspondente ao seletor, ou null
se nenhum elemento for encontrado.
Se vários elementos corresponderem ao seletor, este método lançará um erro. Use .elements()
quando precisar de todos os elementos DOM correspondentes ou .all()
se precisar de um array de seletores que correspondam ao seletor.
Considere a seguinte estrutura DOM:
<div>Hello <span>World</span></div>
<div>Hello</div>
Esses seletores não lançarão um erro:
page.getByText('Hello World').query(); // ✅ HTMLDivElement
page.getByText('Hello Germany').query(); // ✅ null
page.getByText('World').query(); // ✅ HTMLSpanElement
page.getByText('Hello', { exact: true }).query(); // ✅ HTMLSpanElement
Esses seletores lançarão um erro:
// retorna múltiplos elementos
page.getByText('Hello').query(); // ❌
page.getByText(/^Hello/).query(); // ❌
element
function element(): Element;
Este método retorna um único elemento correspondente ao seletor.
Se nenhum elemento corresponder ao seletor, um erro é lançado. Considere usar .query()
quando for necessário apenas verificar a existência do elemento.
Se múltiplos elementos corresponderem ao seletor, um erro é lançado. Use .elements()
quando precisar de todos os elementos DOM correspondentes ou .all()
se precisar de um array de seletores que correspondam ao seletor.
TIP
Este método pode ser útil se você precisar passá-lo para uma biblioteca externa. Ele é chamado automaticamente quando o seletor é usado com expect.element
toda vez que a asserção é tentada novamente:
await expect.element(page.getByRole('button')).toBeDisabled();
Considere a seguinte estrutura DOM:
<div>Hello <span>World</span></div>
<div>Hello Germany</div>
<div>Hello</div>
Esses seletores não lançarão um erro:
page.getByText('Hello World').element(); // ✅
page.getByText('Hello Germany').element(); // ✅
page.getByText('World').element(); // ✅
page.getByText('Hello', { exact: true }).element(); // ✅
Esses seletores lançarão um erro:
// retorna múltiplos elementos
page.getByText('Hello').element(); // ❌
page.getByText(/^Hello/).element(); // ❌
// retorna nenhum elemento
page.getByText('Hello USA').element(); // ❌
elements
function elements(): Element[];
Este método retorna um array de elementos correspondentes ao seletor.
Esta função nunca lança um erro. Se não houver elementos correspondentes ao seletor, este método retornará um array vazio.
Considere a seguinte estrutura DOM:
<div>Hello <span>World</span></div>
<div>Hello</div>
Esses seletores sempre funcionarão:
page.getByText('Hello World').elements(); // ✅ [HTMLElement]
page.getByText('World').elements(); // ✅ [HTMLElement]
page.getByText('Hello', { exact: true }).elements(); // ✅ [HTMLElement]
page.getByText('Hello').element(); // ✅ [HTMLElement, HTMLElement]
page.getByText('Hello USA').elements(); // ✅ []
all
function all(): Locator[];
Este método retorna um array de novos seletores que correspondem ao seletor.
Internamente, este método chama .elements
e envolve cada elemento usando page.elementLocator
.
Propriedades
selector
O selector
é uma string que o provedor do navegador usará para localizar o elemento. O Playwright usará sua sintaxe de seletor, enquanto preview
e webdriverio
usarão CSS.
DANGER
Você não deve usar esta string diretamente em seu código de teste. A string selector
só deve ser utilizada ao interagir com a API de Comandos:
import type { BrowserCommand } from 'vitest/node';
const test: BrowserCommand<string> = function test(context, selector) {
// playwright
await context.iframe.locator(selector).click();
// webdriverio
await context.browser.$(selector).click();
};
import { test } from 'vitest';
import { commands, page } from '@vitest/browser/context';
test('works correctly', async () => {
await commands.test(page.getByText('Hello').selector); // ✅
// vitest irá automaticamente convertê-lo para uma string
await commands.test(page.getByText('Hello')); // ✅
});
Seletores Personalizados 3.2.0+ avançado
Você pode estender a API de seletores embutidos definindo um objeto de funções de fábrica de seletores. Esses métodos estarão disponíveis no objeto page
e em qualquer seletor criado.
Esses seletores podem ser úteis se os seletores embutidos não forem suficientes. Por exemplo, quando você usa um framework personalizado para sua UI.
A função de fábrica do seletor precisa retornar uma string de seletor ou o próprio seletor.
TIP
A sintaxe do seletor é idêntica aos seletores do Playwright. Por favor, leia o guia deles para entender melhor como utilizá-los.
import { locators } from '@vitest/browser/context';
locators.extend({
getByArticleTitle(title) {
return `[data-title="${title}"]`;
},
getByArticleCommentsCount(count) {
return `.comments :text("${count} comments")`;
},
async previewComments() {
// você tem acesso ao localizador atual via "this"
// cuidado: se o método foi chamado em `page`, `this` será `page`,
// não o localizador!
if (this !== page) {
await this.click();
}
// ...
},
});
// se você estiver usando typescript, você pode estender a interface LocatorSelectors
// para ter o autocompletar em locators.extend, page.* e locator.* methods
declare module '@vitest/browser/context' {
interface LocatorSelectors {
// se o método personalizado retornar uma string, ele será convertido em um seletor
// se retornar qualquer outra coisa, será retornado como de costume
getByArticleTitle(title: string): Locator;
getByArticleCommentsCount(count: number): Locator;
// Vitest retornará uma promessa e não tentará convertê-la em um seletor
previewComments(this: Locator): Promise<void>;
}
}
Se o método for chamado no objeto page
global, o seletor será aplicado a toda a página. No exemplo abaixo, getByArticleTitle
encontrará todos os elementos com um atributo data-title
cujo valor seja title
. No entanto, se o método for chamado no seletor, seu escopo será restrito a esse seletor.
<article data-title="Hello, World!">
Hello, World!
<button id="comments">2 comments</button>
</article>
<article data-title="Hello, Vitest!">
Hello, Vitest!
<button id="comments">0 comments</button>
</article>
const articles = page.getByRole('article');
const worldArticle = page.getByArticleTitle('Hello, World!'); // ✅
const commentsElement = worldArticle.getByArticleCommentsCount(2); // ✅
const wrongCommentsElement = worldArticle.getByArticleCommentsCount(0); // ❌
const wrongElement = page.getByArticleTitle('No Article!'); // ❌
await commentsElement.previewComments(); // ✅
await wrongCommentsElement.previewComments(); // ❌