Localizadores
Un localizador representa uno o varios elementos en el DOM. Cada localizador se define mediante una cadena llamada selector. Vitest simplifica el uso de selectores al proporcionar métodos convenientes que los generan automáticamente.
La API de localizadores de Vitest utiliza una adaptación de los localizadores de Playwright denominada Ivya. Sin embargo, Vitest extiende esta API a todos los proveedores de navegador, no solo a Playwright.
TIP
Esta página describe el uso de la API de localizadores. Para una comprensión más profunda de los localizadores y su aplicación, consulta la documentación de Playwright sobre "Localizadores".
getByRole
function getByRole(
role: ARIARole | string,
options?: LocatorByRoleOptions
): Locator;Crea un localizador para encontrar un elemento basándose en su rol ARIA, atributos ARIA y nombre accesible.
TIP
Si solo necesitas consultar un único elemento con getByText('El nombre'), a menudo es más apropiado usar getByRole(rolEsperado, { name: 'El nombre' }). La consulta por nombre accesible no reemplaza otras consultas como *ByAltText o *ByTitle. Aunque el nombre accesible pueda coincidir con dichos atributos, no sustituye su funcionalidad.
Considera la siguiente estructura DOM:
<h3>Sign up</h3>
<label>
Login
<input type="text" />
</label>
<label>
Password
<input type="password" />
</label>
<br />
<button>Submit</button>Puedes localizar cada elemento por su rol 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
Los roles se comparan por igualdad de cadena, sin heredar de la jerarquía de roles ARIA. Por lo tanto, consultar un rol de superclase como checkbox no incluirá elementos con un rol de subclase como switch.
Por defecto, muchos elementos semánticos en HTML tienen un rol; por ejemplo, <input type="radio"> tiene el rol de "radio". Los elementos no semánticos en HTML no tienen un rol; <div> y <span> sin semántica adicional devuelven null. El atributo role puede añadir semántica.
Proporcionar roles a través de atributos role o aria-* a elementos integrados que ya tienen un rol implícito está fuertemente desaconsejado por las directrices ARIA.
Opciones
exact: booleanIndica si el
namedebe coincidir exactamente: sensible a mayúsculas y minúsculas y cadena completa. Deshabilitado por defecto. Esta opción se ignora sinamees una expresión regular. Ten en cuenta que la coincidencia exacta aún recorta los espacios en blanco.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: booleanIndica si se deben incluir los elementos marcados (establecidos por
aria-checkedo<input type="checkbox"/>). Por defecto, el filtro no se aplica.Consulta
aria-checkedpara más información.tsx<> <button role="checkbox" aria-checked="true" /> <input type="checkbox" checked /> </>; page.getByRole('checkbox', { checked: true }); // ✅ page.getByRole('checkbox', { checked: false }); // ❌disabled: booleanIndica si se deben incluir los elementos deshabilitados. Por defecto, el filtro no se aplica. Ten en cuenta que, a diferencia de otros atributos, el estado
disabledse hereda.Consulta
aria-disabledpara más información.tsx<input type="text" disabled />; page.getByRole('textbox', { disabled: true }); // ✅ page.getByRole('textbox', { disabled: false }); // ❌expanded: booleanIndica si se deben incluir los elementos expandidos. Por defecto, el filtro no se aplica.
Consulta
aria-expandedpara más información.tsx<a aria-expanded="true" href="example.com"> Link </a>; page.getByRole('link', { expanded: true }); // ✅ page.getByRole('link', { expanded: false }); // ❌includeHidden: booleanIndica si se deben consultar los elementos que normalmente se excluyen del árbol de accesibilidad. Por defecto, solo los elementos no ocultos coinciden con el selector de rol.
Ten en cuenta que los roles
noneypresentationsiempre se incluyen.tsx<button style="display: none" />; page.getByRole('button'); // ❌ page.getByRole('button', { includeHidden: false }); // ❌ page.getByRole('button', { includeHidden: true }); // ✅level: numberUn atributo numérico que suele estar presente para los roles
heading,listitem,row,treeitemcon valores predeterminados para los elementos<h1>-<h6>. Por defecto, el filtro no se aplica.Consulta
aria-levelpara más información.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 | RegExpUn nombre accesible. Por defecto, la coincidencia es insensible a mayúsculas y minúsculas y busca una subcadena. Usa la opción
exactpara controlar este comportamiento.tsx<button>Click Me!</button>; page.getByRole('button', { name: 'Click Me!' }); // ✅ page.getByRole('button', { name: 'click me!' }); // ✅ page.getByRole('button', { name: 'Click Me?' }); // ❌pressed: booleanIndica si se deben incluir los elementos presionados. Por defecto, el filtro no se aplica.
Consulta
aria-pressedpara más información.tsx<button aria-pressed="true">👍</button>; page.getByRole('button', { pressed: true }); // ✅ page.getByRole('button', { pressed: false }); // ❌selected: booleanIndica si se deben incluir los elementos seleccionados. Por defecto, el filtro no se aplica.
Consulta
aria-selectedpara más información.tsx<button role="tab" aria-selected="true"> Vue </button>; page.getByRole('button', { selected: true }); // ✅ page.getByRole('button', { selected: false }); // ❌
Ver también
getByAltText
function getByAltText(text: string | RegExp, options?: LocatorOptions): Locator;Crea un localizador capaz de encontrar un elemento con un atributo alt que coincida con el texto. A diferencia de la implementación de Testing Library, Vitest encontrará cualquier elemento que tenga un atributo alt coincidente.
<img alt="Incredibles 2 Poster" src="/incredibles-2.png" />;
page.getByAltText(/incredibles.*? poster/i); // ✅
page.getByAltText('non existing alt text'); // ❌Opciones
exact: booleanIndica si el
textdebe coincidir exactamente: sensible a mayúsculas y minúsculas y cadena completa. Deshabilitado por defecto. Esta opción se ignora sitextes una expresión regular. Ten en cuenta que la coincidencia exacta aún recorta los espacios en blanco.
Ver también
getByLabelText
function getByLabelText(
text: string | RegExp,
options?: LocatorOptions
): Locator;Crea un localizador capaz de encontrar un elemento que tenga una etiqueta asociada.
El localizador page.getByLabelText('Username') encontrará todos los elementos input en el siguiente ejemplo:
// Relación for/htmlFor entre la etiqueta y el ID del elemento de formulario
<label for="username-input">Username</label>
<input id="username-input" />
// El atributo aria-labelledby en elementos de formulario
<label id="username-label">Username</label>
<input aria-labelledby="username-label" />
// Etiquetas contenedoras
<label>Username <input /></label>
// Etiquetas contenedoras donde el texto de la etiqueta está en otro elemento hijo
<label>
<span>Username</span>
<input />
</label>
// Atributos aria-label
// ¡Atención! Esta no es una etiqueta visible para los usuarios en la página, por lo que el propósito de tu campo de entrada debe ser obvio para los usuarios visuales.
<input aria-label="Username" />Opciones
exact: booleanIndica si el
textdebe coincidir exactamente: sensible a mayúsculas y minúsculas y cadena completa. Deshabilitado por defecto. Esta opción se ignora sitextes una expresión regular. Ten en cuenta que la coincidencia exacta aún recorta los espacios en blanco.
Ver también
getByPlaceholder
function getByPlaceholder(
text: string | RegExp,
options?: LocatorOptions
): Locator;Crea un localizador capaz de encontrar un elemento que tenga el atributo placeholder especificado. Vitest encontrará cualquier elemento que tenga un atributo placeholder coincidente, no solo input.
<input placeholder="Username" />;
page.getByPlaceholder('Username'); // ✅
page.getByPlaceholder('not found'); // ❌WARNING
Generalmente es preferible usar una etiqueta con getByLabelText en lugar de un marcador de posición.
Opciones
exact: booleanIndica si el
textdebe coincidir exactamente: sensible a mayúsculas y minúsculas y cadena completa. Deshabilitado por defecto. Esta opción se ignora sitextes una expresión regular. Ten en cuenta que la coincidencia exacta aún recorta los espacios en blanco.
Ver también
getByText
function getByText(text: string | RegExp, options?: LocatorOptions): Locator;Crea un localizador capaz de encontrar un elemento que contenga el texto especificado. El texto se comparará con el nodeValue de un TextNode o el valor de un input si el tipo es button o reset. La búsqueda por texto siempre normaliza los espacios en blanco, incluso con coincidencia exacta. Por ejemplo, convierte múltiples espacios en uno solo, transforma los saltos de línea en espacios e ignora los espacios en blanco iniciales y finales.
<a href="/about">About ℹ️</a>;
page.getByText(/about/i); // ✅
page.getByText('about', { exact: true }); // ❌TIP
Este localizador es útil para localizar elementos no interactivos. Si necesitas localizar un elemento interactivo, como un botón o un campo de entrada, prefiere getByRole.
Opciones
exact: booleanIndica si el
textdebe coincidir exactamente: sensible a mayúsculas y minúsculas y cadena completa. Deshabilitado por defecto. Esta opción se ignora sitextes una expresión regular. Ten en cuenta que la coincidencia exacta aún recorta los espacios en blanco.
Ver también
getByTitle
function getByTitle(text: string | RegExp, options?: LocatorOptions): Locator;Crea un localizador capaz de encontrar un elemento que tenga el atributo title especificado. A diferencia de getByTitle de testing-library, Vitest no puede encontrar elementos con atributo title dentro de un SVG.
<span title="Delete" id="2"></span>;
page.getByTitle('Delete'); // ✅
page.getByTitle('Create'); // ❌Opciones
exact: booleanIndica si el
textdebe coincidir exactamente: sensible a mayúsculas y minúsculas y cadena completa. Deshabilitado por defecto. Esta opción se ignora sitextes una expresión regular. Ten en cuenta que la coincidencia exacta aún recorta los espacios en blanco.
Ver también
getByTestId
function getByTestId(text: string | RegExp): Locator;Crea un localizador capaz de encontrar un elemento que coincida con el atributo de ID de prueba especificado. Puedes configurar el nombre del atributo con browser.locators.testIdAttribute.
<div data-testid="custom-element" />;
page.getByTestId('custom-element'); // ✅
page.getByTestId('non-existing-element'); // ❌WARNING
Se recomienda usar esto solo después de que los otros localizadores no funcionen para tu caso de uso. El uso de atributos data-testid no refleja cómo se utiliza tu software y debe evitarse si es posible.
Opciones
exact: booleanIndica si el
textdebe coincidir exactamente: sensible a mayúsculas y minúsculas y cadena completa. Deshabilitado por defecto. Esta opción se ignora sitextes una expresión regular. Ten en cuenta que la coincidencia exacta aún recorta los espacios en blanco.
Ver también
nth
function nth(index: number): Locator;Este método devuelve un nuevo localizador que coincide solo con un índice específico dentro de un resultado de consulta de múltiples elementos. Se basa en un índice de cero, donde nth(0) selecciona el primer elemento. A diferencia de elements()[n], el localizador nth se volverá a intentar hasta que el elemento esté 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 recurrir a nth, te puede resultar útil usar localizadores encadenados para acotar tu búsqueda. A veces no hay mejor manera de distinguir los elementos que por su posición; aunque esto puede llevar a resultados inconsistentes, es mejor que nada.
page.getByLabel('two').getByRole('input'); // ✅ mejor alternativa a page.getByRole('textbox').nth(3)
page.getByLabel('one').getByRole('input'); // ❌ demasiado ambiguo
page.getByLabel('one').getByRole('input').nth(1); // ✅ compromiso pragmáticofirst
function first(): Locator;Este método devuelve un nuevo localizador que coincide solo con el primer índice de un resultado de consulta de múltiples elementos. Es una forma abreviada de nth(0).
<input /> <input /> <input />page.getByRole('textbox').first(); // ✅last
function last(): Locator;Este método devuelve un nuevo localizador que coincide solo con el último índice de un resultado de consulta de múltiples elementos. Es una forma abreviada de nth(-1).
<input /> <input /> <input />page.getByRole('textbox').last(); // ✅and
function and(locator: Locator): Locator;Este método crea un nuevo localizador que coincide tanto con el localizador padre como con el localizador proporcionado. El siguiente ejemplo encuentra un botón con un título específico:
page.getByRole('button').and(page.getByTitle('Subscribe'));or
function or(locator: Locator): Locator;Este método crea un nuevo localizador que coincide con uno o ambos localizadores.
WARNING
Ten en cuenta que si el localizador encuentra más de un elemento, llamar a otro método podría lanzar un error si este espera un solo elemento:
<>
<button>Click me</button>
<a href="https://vitest.dev">Error happened!</a>
</>;
page.getByRole('button').or(page.getByRole('link')).click(); // ❌ coincide con múltiples elementosfilter
function filter(options: LocatorOptions): Locator;Este método acota el localizador según las opciones, como filtrar por texto. Se puede encadenar para aplicar múltiples filtros.
has
- Tipo:
Locator
Esta opción acota el selector para que coincida con elementos que contengan otros elementos que también coincidan con el localizador proporcionado. Por ejemplo, con este HTML:
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>Podemos acotar el localizador para encontrar solo el article con el texto Vitest dentro:
page.getByRole('article').filter({ has: page.getByText('Vitest') }); // ✅WARNING
El localizador proporcionado (page.getByText('Vitest') en el ejemplo) debe ser relativo al localizador padre (page.getByRole('article') en el ejemplo). La consulta se realizará a partir del localizador padre, no de la raíz del documento.
Es decir, no puedes pasar un localizador que busque un elemento fuera del ámbito del localizador padre:
page.getByText('Vitest').filter({ has: page.getByRole('article') }); // ❌Este ejemplo fallará porque el elemento article está fuera del elemento que contiene el texto Vitest.
TIP
Este método se puede encadenar para refinar aún más la búsqueda del elemento:
page
.getByRole('article')
.filter({ has: page.getByRole('button', { name: 'delete row' }) })
.filter({ has: page.getByText('Vitest') });hasNot
- Tipo:
Locator
Esta opción acota el selector para que coincida con elementos que NO contengan otros elementos que también coincidan con el localizador proporcionado. Por ejemplo, con este HTML:
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>Podemos acotar el localizador para encontrar solo el article que no tenga Rolldown dentro.
page.getByRole('article').filter({ hasNot: page.getByText('Rolldown') }); // ✅
page.getByRole('article').filter({ hasNot: page.getByText('Vitest') }); // ❌WARNING
Ten en cuenta que el localizador proporcionado se consulta en relación con el padre, no con la raíz del documento, al igual que la opción has.
hasText
- Tipo:
string | RegExp
Esta opción acota el selector para que solo coincida con elementos que contengan el texto proporcionado en su interior. Cuando se pasa un string, la coincidencia es insensible a mayúsculas y minúsculas y busca una subcadena.
<article>
<div>Vitest</div>
</article>
<article>
<div>Rolldown</div>
</article>Ambos localizadores encontrarán el mismo elemento porque la búsqueda no distingue entre mayúsculas y minúsculas:
page.getByRole('article').filter({ hasText: 'Vitest' }); // ✅
page.getByRole('article').filter({ hasText: 'Vite' }); // ✅hasNotText
- Tipo:
string | RegExp
Esta opción acota el selector para que solo coincida con elementos que NO contengan el texto proporcionado en su interior. Cuando se pasa un string, la coincidencia es insensible a mayúsculas y minúsculas y busca una subcadena.
Métodos
Todos los métodos son asíncronos y requieren el uso de await. Desde Vitest 3, las pruebas fallarán si un método no se espera (no se usa await).
click
function click(options?: UserEventClickOptions): Promise<void>;Haz clic en un elemento. Puedes usar las opciones para establecer la posición del cursor.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).click();dblClick
function dblClick(options?: UserEventDoubleClickOptions): Promise<void>;Activa un evento de doble clic en un elemento. Puedes usar las opciones para establecer la posición del cursor.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).dblClick();tripleClick
function tripleClick(options?: UserEventTripleClickOptions): Promise<void>;Activa un evento de triple clic en un elemento. Dado que no existe tripleclick en la API del navegador, este método activará tres eventos de clic seguidos.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).tripleClick();clear
function clear(options?: UserEventClearOptions): Promise<void>;Borra el contenido del campo de entrada.
import { page } from '@vitest/browser/context';
await page.getByRole('textbox', { name: 'Full Name' }).clear();hover
function hover(options?: UserEventHoverOptions): Promise<void>;Mueve la posición del cursor al elemento seleccionado.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).hover();unhover
function unhover(options?: UserEventHoverOptions): Promise<void>;Esto funciona igual que locator.hover, pero mueve el cursor al elemento document.body en su lugar.
import { page } from '@vitest/browser/context';
await page.getByRole('img', { name: 'Rose' }).unhover();fill
function fill(text: string, options?: UserEventFillOptions): Promise<void>;Establece el valor del elemento input, textarea o contenteditable actual.
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>;Arrastra el elemento actual a la ubicación 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>;Selecciona uno o más valores de un 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>;Crea una captura de pantalla del elemento que coincide con el selector del localizador.
Puedes especificar la ubicación de guardado para la captura de pantalla usando la opción path, que es relativa al archivo de prueba actual. Si la opción path no está configurada, Vitest utilizará por defecto browser.screenshotDirectory (__screenshot__ por defecto), junto con los nombres del archivo y la prueba para determinar la ruta del archivo de la captura de pantalla.
Si también necesitas el contenido de la captura de pantalla, puedes especificar base64: true para obtenerlo junto con la ruta del archivo donde se guarda la captura de pantalla.
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, // también devuelve la cadena base64
});
// path - ruta completa a la captura de pantalla
// base64 - cadena codificada en base64 de la captura de pantallaADVERTENCIA 3.2.0+
Ten en cuenta que screenshot siempre devolverá una cadena base64 si save se establece en false. La path también se ignora en ese caso.
query
function query(): Element | null;Este método devuelve un único elemento que coincide con el selector del localizador o null si no se encuentra ningún elemento.
Si varios elementos coinciden con el selector, este método lanzará un error. Usa .elements() cuando necesites todos los elementos DOM coincidentes o .all() si necesitas un array de localizadores que coincidan con el selector.
Considera la siguiente estructura DOM:
<div>Hello <span>World</span></div>
<div>Hello</div>Estos localizadores no lanzarán un error:
page.getByText('Hello World').query(); // ✅ HTMLDivElement
page.getByText('Hello Germany').query(); // ✅ null
page.getByText('World').query(); // ✅ HTMLSpanElement
page.getByText('Hello', { exact: true }).query(); // ✅ HTMLSpanElementEstos localizadores lanzarán un error:
// devuelve múltiples elementos
page.getByText('Hello').query(); // ❌
page.getByText(/^Hello/).query(); // ❌element
function element(): Element;Este método devuelve un único elemento que coincide con el selector del localizador.
Si ningún elemento coincide con el selector, se lanza un error. Considera usar .query() cuando solo necesites verificar si el elemento existe.
Si múltiples elementos coinciden con el selector, se lanza un error. Usa .elements() cuando necesites todos los elementos DOM coincidentes o .all() si necesitas un array de localizadores que coincidan con el selector.
TIP
Este método puede ser útil si necesitas pasarlo a una biblioteca externa. Se llama automáticamente cuando el localizador se usa con expect.element cada vez que se reintenta la aserción:
await expect.element(page.getByRole('button')).toBeDisabled();Considera la siguiente estructura DOM:
<div>Hello <span>World</span></div>
<div>Hello Germany</div>
<div>Hello</div>Estos localizadores no lanzarán un error:
page.getByText('Hello World').element(); // ✅
page.getByText('Hello Germany').element(); // ✅
page.getByText('World').element(); // ✅
page.getByText('Hello', { exact: true }).element(); // ✅Estos localizadores lanzarán un error:
// devuelve múltiples elementos
page.getByText('Hello').element(); // ❌
page.getByText(/^Hello/).element(); // ❌
// no devuelve elementos
page.getByText('Hello USA').element(); // ❌elements
function elements(): Element[];Este método devuelve un array de elementos que coinciden con el selector del localizador.
Esta función nunca lanza un error. Si no hay elementos que coincidan con el selector, este método devolverá un array vacío.
Considera la siguiente estructura DOM:
<div>Hello <span>World</span></div>
<div>Hello</div>Estos localizadores siempre tendrán éxito:
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 devuelve un array de nuevos localizadores que coinciden con el selector.
Internamente, este método llama a .elements y envuelve cada elemento usando page.elementLocator.
Propiedades
selector
El selector es una cadena que será utilizada por el proveedor del navegador para localizar el elemento. Playwright utilizará una sintaxis de localizador de playwright mientras que preview y webdriverio usarán CSS.
DANGER
No debes usar esta cadena directamente en tu código de prueba. La cadena del selector solo debe usarse cuando se trabaja con la 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 lo convertirá automáticamente en una cadena
await commands.test(page.getByText('Hello')); // ✅
});Localizadores Personalizados 3.2.0+ avanzado
Puedes extender la API de localizadores incorporados definiendo un objeto de fábricas de localizadores. Estos métodos existirán como métodos en el objeto page y en cualquier localizador creado.
Estos localizadores pueden ser útiles si los localizadores incorporados no son suficientes. Por ejemplo, cuando usas un framework personalizado para tu UI.
La fábrica de localizadores debe devolver una cadena de selector o un localizador en sí mismo.
TIP
La sintaxis del selector es idéntica a la de los localizadores de Playwright. Por favor, lee su guía para comprender mejor cómo trabajar con ellos.
import { locators } from '@vitest/browser/context';
locators.extend({
getByArticleTitle(title) {
return `[data-title="${title}"]`;
},
getByArticleCommentsCount(count) {
return `.comments :text("${count} comments")`;
},
async previewComments() {
// tienes acceso al localizador actual a través de "this"
// ¡Atención! Si el método fue llamado en `page`, `this` será `page`,
// no el localizador!
if (this !== page) {
await this.click();
}
// ...
},
});
// si estás usando typescript, puedes extender la interfaz LocatorSelectors
// para tener autocompletado en locators.extend, page.* y locator.* methods
declare module '@vitest/browser/context' {
interface LocatorSelectors {
// si el método personalizado devuelve una cadena, se convertirá en un localizador
// si devuelve cualquier otra cosa, se devolverá como de costumbre
getByArticleTitle(title: string): Locator;
getByArticleCommentsCount(count: number): Locator;
// Vitest devolverá una promesa y no intentará convertirla en un localizador
previewComments(this: Locator): Promise<void>;
}
}Si el método se llama en el objeto global page, el selector se aplicará a toda la página. En el ejemplo siguiente, getByArticleTitle encontrará todos los elementos con un atributo data-title cuyo valor sea title. Sin embargo, si el método se llama en el localizador, su alcance se restringirá a ese localizador.
<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(); // ❌