API de Aserciones
Vitest ofrece una amplia gama de aserciones DOM listas para usar, derivadas de la librería @testing-library/jest-dom
, con soporte adicional para localizadores y capacidad de reintento incorporada.
Soporte de TypeScript
Si utilizas TypeScript o deseas tener sugerencias de tipo correctas en expect
, asegúrate de que @vitest/browser/context
esté referenciado en algún lugar. Si nunca lo has importado, puedes añadir un comentario de reference
en cualquier archivo cubierto por tu tsconfig.json
:
/// <reference types="@vitest/browser/context" />
Las pruebas en el navegador pueden fallar de forma inconsistente debido a su naturaleza asíncrona. Por ello, es crucial asegurar que las aserciones se cumplan incluso si la condición se retrasa (por ejemplo, debido a un tiempo de espera, una solicitud de red o una animación). Para este propósito, Vitest proporciona aserciones con capacidad de reintento por defecto a través de las APIs expect.poll
y expect.element
:
import { expect, test } from 'vitest';
import { page } from '@vitest/browser/context';
test('error banner is rendered', async () => {
triggerError();
// Esto crea un localizador que intentará encontrar el elemento cuando se invoque cualquiera de sus métodos.
// Esta llamada por sí misma no verifica la existencia del elemento.
const banner = page.getByRole('alert', {
name: /error/i,
});
// Vitest proporciona `expect.element` con capacidad de reintento incorporada.
// Verificará repetidamente que el elemento existe en el DOM y que el contenido de `element.textContent` es igual a "Error!" hasta que se cumplan todas las condiciones.
await expect.element(banner).toHaveTextContent('Error!');
});
Recomendamos siempre usar expect.element
al trabajar con localizadores page.getBy*
para reducir la inestabilidad de las pruebas. Ten en cuenta que expect.element
acepta una segunda opción:
interface ExpectPollOptions {
// El intervalo en milisegundos para reintentar la aserción.
// Por defecto es la opción de configuración "expect.poll.interval".
interval?: number;
// El tiempo en milisegundos para reintentar la aserción.
// Por defecto es la opción de configuración "expect.poll.timeout".
timeout?: number;
// El mensaje que se imprime cuando la aserción falla.
message?: string;
}
TIP
expect.element
es una abreviatura de expect.poll(() => element)
y funciona exactamente de la misma manera.
toHaveTextContent
y todas las demás aserciones siguen estando disponibles en un expect
regular sin un mecanismo de reintento incorporado:
// Fallará inmediatamente si .textContent no es `'Error!'`.
expect(banner).toHaveTextContent('Error!');
toBeDisabled
function toBeDisabled(): Promise<void>;
Permite comprobar si un elemento está deshabilitado desde la perspectiva del usuario.
Coincide si el elemento es un control de formulario y el atributo disabled
está especificado en este elemento, o si el elemento es un descendiente de un elemento de formulario con un atributo disabled
.
Ten en cuenta que solo los elementos de control nativos como HTML button
, input
, select
, textarea
, option
, optgroup
pueden ser deshabilitados estableciendo el atributo "disabled". El atributo "disabled" en otros elementos es ignorado, a menos que sea un elemento personalizado.
<button data-testid="button" type="submit" disabled>submit</button>
await expect.element(getByTestId('button')).toBeDisabled(); // ✅
await expect.element(getByTestId('button')).not.toBeDisabled(); // ❌
toBeEnabled
function toBeEnabled(): Promise<void>;
Permite comprobar si un elemento no está deshabilitado desde la perspectiva del usuario.
Funciona como not.toBeDisabled()
. Utiliza este matcher para evitar la doble negación en tus pruebas.
<button data-testid="button" type="submit" disabled>submit</button>
await expect.element(getByTestId('button')).toBeEnabled(); // ✅
await expect.element(getByTestId('button')).not.toBeEnabled(); // ❌
toBeEmptyDOMElement
function toBeEmptyDOMElement(): Promise<void>;
Esto permite afirmar si un elemento no tiene contenido visible para el usuario. Ignora los comentarios, pero fallará si el elemento contiene espacios en blanco.
<span data-testid="not-empty"><span data-testid="empty"></span></span>
<span data-testid="with-whitespace"> </span>
<span data-testid="with-comment"><!-- comment --></span>
await expect.element(getByTestId('empty')).toBeEmptyDOMElement();
await expect.element(getByTestId('not-empty')).not.toBeEmptyDOMElement();
await expect.element(getByTestId('with-whitespace')).not.toBeEmptyDOMElement();
toBeInTheDocument
function toBeInTheDocument(): Promise<void>;
Afirma si un elemento está presente en el documento o no.
<svg data-testid="svg-element"></svg>
await expect.element(getByTestId('svg-element')).toBeInTheDocument();
await expect.element(getByTestId('does-not-exist')).not.toBeInTheDocument();
WARNING
Este matcher no encuentra elementos desconectados del DOM. El elemento debe ser añadido al documento para ser encontrado por toBeInTheDocument
. Si deseas buscar en un elemento desconectado, por favor usa: toContainElement
.
toBeInvalid
function toBeInvalid(): Promise<void>;
Esto permite comprobar si un elemento es actualmente inválido.
Un elemento es inválido si tiene un aria-invalid
attribute sin valor o con un valor de "true"
, o si el resultado de checkValidity()
es false
.
<input data-testid="no-aria-invalid" />
<input data-testid="aria-invalid" aria-invalid />
<input data-testid="aria-invalid-value" aria-invalid="true" />
<input data-testid="aria-invalid-false" aria-invalid="false" />
<form data-testid="valid-form">
<input />
</form>
<form data-testid="invalid-form">
<input required />
</form>
await expect.element(getByTestId('no-aria-invalid')).not.toBeInvalid();
await expect.element(getByTestId('aria-invalid')).toBeInvalid();
await expect.element(getByTestId('aria-invalid-value')).toBeInvalid();
await expect.element(getByTestId('aria-invalid-false')).not.toBeInvalid();
await expect.element(getByTestId('valid-form')).not.toBeInvalid();
await expect.element(getByTestId('invalid-form')).toBeInvalid();
toBeRequired
function toBeRequired(): Promise<void>;
Esto te permite comprobar si un elemento de formulario es actualmente requerido.
Un elemento es requerido si tiene un atributo required
o aria-required="true"
.
<input data-testid="required-input" required />
<input data-testid="aria-required-input" aria-required="true" />
<input data-testid="conflicted-input" required aria-required="false" />
<input data-testid="aria-not-required-input" aria-required="false" />
<input data-testid="optional-input" />
<input data-testid="unsupported-type" type="image" required />
<select data-testid="select" required></select>
<textarea data-testid="textarea" required></textarea>
<div data-testid="supported-role" role="tree" required></div>
<div data-testid="supported-role-aria" role="tree" aria-required="true"></div>
await expect.element(getByTestId('required-input')).toBeRequired();
await expect.element(getByTestId('aria-required-input')).toBeRequired();
await expect.element(getByTestId('conflicted-input')).toBeRequired();
await expect.element(getByTestId('aria-not-required-input')).not.toBeRequired();
await expect.element(getByTestId('optional-input')).not.toBeRequired();
await expect.element(getByTestId('unsupported-type')).not.toBeRequired();
await expect.element(getByTestId('select')).toBeRequired();
await expect.element(getByTestId('textarea')).toBeRequired();
await expect.element(getByTestId('supported-role')).not.toBeRequired();
await expect.element(getByTestId('supported-role-aria')).toBeRequired();
toBeValid
function toBeValid(): Promise<void>;
Esto te permite comprobar si el valor de un elemento es actualmente válido.
Un elemento es válido si no tiene un atributo aria-invalid
o un valor de atributo de "false". El resultado de checkValidity()
también debe ser true
si es un elemento de formulario.
<input data-testid="no-aria-invalid" />
<input data-testid="aria-invalid" aria-invalid />
<input data-testid="aria-invalid-value" aria-invalid="true" />
<input data-testid="aria-invalid-false" aria-invalid="false" />
<form data-testid="valid-form">
<input />
</form>
<form data-testid="invalid-form">
<input required />
</form>
await expect.element(getByTestId('no-aria-invalid')).toBeValid();
await expect.element(getByTestId('aria-invalid')).not.toBeValid();
await expect.element(getByTestId('aria-invalid-value')).not.toBeValid();
await expect.element(getByTestId('aria-invalid-false')).toBeValid();
await expect.element(getByTestId('valid-form')).toBeValid();
await expect.element(getByTestId('invalid-form')).not.toBeValid();
toBeVisible
function toBeVisible(): Promise<void>;
Esto te permite comprobar si un elemento es actualmente visible para el usuario.
Un elemento se considera visible cuando tiene un cuadro de límites no vacío y no tiene el estilo computado visibility:hidden
.
Ten en cuenta que, según esta definición:
- Los elementos de tamaño cero no se consideran visibles.
- Los elementos con
display:none
no se consideran visibles. - Los elementos con
opacity:0
sí se consideran visibles.
Para comprobar que al menos un elemento de la lista es visible, utiliza locator.first()
.
// Un elemento específico es visible.
await expect.element(page.getByText('Welcome')).toBeVisible();
// Al menos un elemento de la lista es visible.
await expect.element(page.getByTestId('todo-item').first()).toBeVisible();
// Al menos uno de los dos elementos es visible, posiblemente ambos.
await expect
.element(
page
.getByRole('button', { name: 'Sign in' })
.or(page.getByRole('button', { name: 'Sign up' }))
.first()
)
.toBeVisible();
toContainElement
function toContainElement(
element: HTMLElement | SVGElement | null
): Promise<void>;
Esto te permite afirmar si un elemento contiene otro elemento como descendiente o no.
<span data-testid="ancestor"><span data-testid="descendant"></span></span>
const ancestor = getByTestId('ancestor');
const descendant = getByTestId('descendant');
const nonExistantElement = getByTestId('does-not-exist');
await expect.element(ancestor).toContainElement(descendant);
await expect.element(descendant).not.toContainElement(ancestor);
await expect.element(ancestor).not.toContainElement(nonExistantElement);
toContainHTML
function toContainHTML(htmlText: string): Promise<void>;
Afirma si una cadena que representa un elemento HTML está contenida en otro elemento. La cadena debe contener HTML válido, y no HTML incompleto.
<span data-testid="parent"><span data-testid="child"></span></span>
// Estos son usos válidos
await expect
.element(getByTestId('parent'))
.toContainHTML('<span data-testid="child"></span>');
await expect
.element(getByTestId('parent'))
.toContainHTML('<span data-testid="child" />');
await expect.element(getByTestId('parent')).not.toContainHTML('<br />');
// Estos no funcionarán
await expect
.element(getByTestId('parent'))
.toContainHTML('data-testid="child"');
await expect.element(getByTestId('parent')).toContainHTML('data-testid');
await expect.element(getByTestId('parent')).toContainHTML('</span>');
WARNING
Es probable que no necesites usar este matcher. Se recomienda probar desde la perspectiva de cómo el usuario percibe la aplicación en un navegador. Por lo tanto, no se aconseja probar contra una estructura DOM específica.
Podría ser útil en situaciones en las que el código que se está probando renderiza HTML obtenido de una fuente externa, y quieres validar que ese código HTML se utilizó según lo previsto.
No debe usarse para comprobar la estructura DOM que controlas. Por favor, usa toContainElement
en su lugar.
toHaveAccessibleDescription
function toHaveAccessibleDescription(
description?: string | RegExp
): Promise<void>;
Esto te permite afirmar que un elemento tiene la descripción accesible esperada.
Puedes pasar la cadena exacta de la descripción accesible esperada, o puedes hacer una coincidencia parcial pasando una expresión regular, o usando expect.stringContaining
o expect.stringMatching
.
<a
data-testid="link"
href="/"
aria-label="Home page"
title="A link to start over"
>Start</a
>
<a data-testid="extra-link" href="/about" aria-label="About page">About</a>
<img src="avatar.jpg" data-testid="avatar" alt="User profile pic" />
<img
src="logo.jpg"
data-testid="logo"
alt="Company logo"
aria-describedby="t1"
/>
<span id="t1" role="presentation">The logo of Our Company</span>
<img
src="logo.jpg"
data-testid="logo2"
alt="Company logo"
aria-description="The logo of Our Company"
/>
await expect.element(getByTestId('link')).toHaveAccessibleDescription();
await expect
.element(getByTestId('link'))
.toHaveAccessibleDescription('A link to start over');
await expect
.element(getByTestId('link'))
.not.toHaveAccessibleDescription('Home page');
await expect
.element(getByTestId('extra-link'))
.not.toHaveAccessibleDescription();
await expect.element(getByTestId('avatar')).not.toHaveAccessibleDescription();
await expect
.element(getByTestId('logo'))
.not.toHaveAccessibleDescription('Company logo');
await expect
.element(getByTestId('logo'))
.toHaveAccessibleDescription('The logo of Our Company');
await expect
.element(getByTestId('logo2'))
.toHaveAccessibleDescription('The logo of Our Company');
toHaveAccessibleErrorMessage
function toHaveAccessibleErrorMessage(message?: string | RegExp): Promise<void>;
Esto te permite afirmar que un elemento tiene el mensaje de error accesible esperado.
Puedes pasar la cadena exacta del mensaje de error accesible esperado. Alternativamente, puedes realizar una coincidencia parcial pasando una expresión regular o usando expect.stringContaining
o expect.stringMatching
.
<input
aria-label="Has Error"
aria-invalid="true"
aria-errormessage="error-message"
/>
<div id="error-message" role="alert">This field is invalid</div>
<input aria-label="No Error Attributes" />
<input
aria-label="Not Invalid"
aria-invalid="false"
aria-errormessage="error-message"
/>
// Inputs con mensajes de error válidos
await expect
.element(getByRole('textbox', { name: 'Has Error' }))
.toHaveAccessibleErrorMessage();
await expect
.element(getByRole('textbox', { name: 'Has Error' }))
.toHaveAccessibleErrorMessage('This field is invalid');
await expect
.element(getByRole('textbox', { name: 'Has Error' }))
.toHaveAccessibleErrorMessage(/invalid/i);
await expect
.element(getByRole('textbox', { name: 'Has Error' }))
.not.toHaveAccessibleErrorMessage('This field is absolutely correct!');
// Inputs sin mensajes de error válidos
await expect
.element(getByRole('textbox', { name: 'No Error Attributes' }))
.not.toHaveAccessibleErrorMessage();
await expect
.element(getByRole('textbox', { name: 'Not Invalid' }))
.not.toHaveAccessibleErrorMessage();
toHaveAccessibleName
function toHaveAccessibleName(name?: string | RegExp): Promise<void>;
Esto te permite afirmar que un elemento tiene el nombre accesible esperado. Es útil, por ejemplo, para afirmar que los elementos de formulario y los botones están correctamente etiquetados.
Puedes pasar la cadena exacta del nombre accesible esperado, o puedes hacer una coincidencia parcial pasando una expresión regular, o usando expect.stringContaining
o expect.stringMatching
.
<img data-testid="img-alt" src="" alt="Test alt" />
<img data-testid="img-empty-alt" src="" alt="" />
<svg data-testid="svg-title"><title>Test title</title></svg>
<button data-testid="button-img-alt"><img src="" alt="Test" /></button>
<p><img data-testid="img-paragraph" src="" alt="" /> Test content</p>
<button data-testid="svg-button"><svg><title>Test</title></svg></p>
<div><svg data-testid="svg-without-title"></svg></div>
<input data-testid="input-title" title="test" />
await expect.element(getByTestId('img-alt')).toHaveAccessibleName('Test alt');
await expect.element(getByTestId('img-empty-alt')).not.toHaveAccessibleName();
await expect
.element(getByTestId('svg-title'))
.toHaveAccessibleName('Test title');
await expect.element(getByTestId('button-img-alt')).toHaveAccessibleName();
await expect.element(getByTestId('img-paragraph')).not.toHaveAccessibleName();
await expect.element(getByTestId('svg-button')).toHaveAccessibleName();
await expect
.element(getByTestId('svg-without-title'))
.not.toHaveAccessibleName();
await expect.element(getByTestId('input-title')).toHaveAccessibleName();
toHaveAttribute
function toHaveAttribute(attribute: string, value?: unknown): Promise<void>;
Esto te permite comprobar si el elemento dado tiene un atributo o no. También puedes comprobar opcionalmente que el atributo tiene un valor esperado específico o una coincidencia parcial usando expect.stringContaining
o expect.stringMatching
.
<button data-testid="ok-button" type="submit" disabled>ok</button>
const button = getByTestId('ok-button');
await expect.element(button).toHaveAttribute('disabled');
await expect.element(button).toHaveAttribute('type', 'submit');
await expect.element(button).not.toHaveAttribute('type', 'button');
await expect
.element(button)
.toHaveAttribute('type', expect.stringContaining('sub'));
await expect
.element(button)
.toHaveAttribute('type', expect.not.stringContaining('but'));
toHaveClass
function toHaveClass(
...classNames: string[],
options?: { exact: boolean }
): Promise<void>;
function toHaveClass(...classNames: (string | RegExp)[]): Promise<void>;
Esto te permite comprobar si el elemento dado tiene ciertas clases dentro de su atributo class
. Debes proporcionar al menos una clase, a menos que estés afirmando que un elemento no tiene ninguna clase.
La lista de nombres de clase puede incluir cadenas y expresiones regulares. Las expresiones regulares se comparan con cada clase individual en el elemento de destino, y NO se comparan con el valor completo de su atributo class
en su totalidad.
WARNING
Ten en cuenta que no puedes usar la opción exact: true
cuando solo se proporcionan expresiones regulares.
<button data-testid="delete-button" class="btn extra btn-danger">
Delete item
</button>
<button data-testid="no-classes">No Classes</button>
const deleteButton = getByTestId('delete-button');
const noClasses = getByTestId('no-classes');
await expect.element(deleteButton).toHaveClass('extra');
await expect.element(deleteButton).toHaveClass('btn-danger btn');
await expect.element(deleteButton).toHaveClass(/danger/, 'btn');
await expect.element(deleteButton).toHaveClass('btn-danger', 'btn');
await expect.element(deleteButton).not.toHaveClass('btn-link');
await expect.element(deleteButton).not.toHaveClass(/link/);
// ⚠️ la expresión regular coincide con clases individuales, no con la lista de clases completa
await expect.element(deleteButton).not.toHaveClass(/btn extra/);
// el elemento tiene EXACTAMENTE un conjunto de clases (en cualquier orden)
await expect.element(deleteButton).toHaveClass('btn-danger extra btn', {
exact: true,
});
// si tiene más de lo esperado, fallará
await expect.element(deleteButton).not.toHaveClass('btn-danger extra', {
exact: true,
});
await expect.element(noClasses).not.toHaveClass();
toHaveFocus
function toHaveFocus(): Promise<void>;
Esto te permite afirmar si un elemento tiene el foco o no.
<div><input type="text" data-testid="element-to-focus" /></div>
const input = page.getByTestId('element-to-focus');
input.element().focus();
await expect.element(input).toHaveFocus();
input.element().blur();
await expect.element(input).not.toHaveFocus();
toHaveFormValues
function toHaveFormValues(
expectedValues: Record<string, unknown>
): Promise<void>;
Esto te permite comprobar si un formulario o un conjunto de campos (fieldset
) contiene controles de formulario para cada nombre dado, y que tienen el valor especificado.
TIP
Es importante destacar que este matcher solo puede invocarse en un elemento form o fieldset.
Esto le permite aprovechar la propiedad .elements
en form
y fieldset
para obtener de forma fiable todos los controles de formulario dentro de ellos.
Esto también evita la posibilidad de que los usuarios proporcionen un contenedor que contenga más de un form
, mezclando así controles de formulario que no están relacionados e incluso podrían entrar en conflicto entre sí.
Este matcher abstrae las particularidades con las que se obtiene el valor de un control de formulario dependiendo del tipo de control de formulario. Por ejemplo, los elementos <input>
tienen un atributo value
, pero los elementos <select>
no. Aquí hay una lista de todos los casos cubiertos:
- Los elementos
<input type="number">
devuelven el valor como un número, en lugar de una cadena. - Elementos
<input type="checkbox">
:- si hay uno solo con el atributo
name
dado, se trata como un booleano, devolviendotrue
si el checkbox está marcado,false
si no está marcado. - si hay más de un checkbox con el mismo atributo
name
, todos se tratan colectivamente como un único control de formulario, que devuelve el valor como un array que contiene todos los valores de los checkboxes seleccionados en la colección.
- si hay uno solo con el atributo
- Los elementos
<input type="radio">
se agrupan por el atributoname
, y dicho grupo se trata como un único control de formulario. Este control de formulario devuelve el valor como una cadena correspondiente al atributovalue
del radio button seleccionado dentro del grupo. - Los elementos
<input type="text">
devuelven el valor como una cadena. Esto también se aplica a los elementos<input>
que tienen cualquier otro atributotype
posible que no esté explícitamente cubierto en reglas diferentes anteriores (por ejemplo,search
,email
,date
,password
,hidden
, etc.) - Los elementos
<select>
sin el atributomultiple
devuelven el valor como una cadena correspondiente al atributovalue
de laoption
seleccionada, oundefined
si no hay ninguna opción seleccionada. - Los elementos
<select multiple>
devuelven el valor como un array que contiene todos los valores de las opciones seleccionadas. - Los elementos
<textarea>
devuelven su valor como una cadena. El valor corresponde a su contenido de nodo.
Las reglas anteriores facilitan, por ejemplo, cambiar de un control de selección único a un grupo de radio buttons. O cambiar de un control de selección múltiple a un grupo de checkboxes. El conjunto resultante de valores de formulario utilizados por este matcher para comparar sería el mismo.
<form data-testid="login-form">
<input type="text" name="username" value="jane.doe" />
<input type="password" name="password" value="12345678" />
<input type="checkbox" name="rememberMe" checked />
<button type="submit">Sign in</button>
</form>
await expect.element(getByTestId('login-form')).toHaveFormValues({
username: 'jane.doe',
rememberMe: true,
});
toHaveStyle
function toHaveStyle(css: string | Partial<CSSStyleDeclaration>): Promise<void>;
Esto te permite comprobar si un determinado elemento tiene algunas propiedades CSS específicas con valores específicos aplicados. Coincide solo si el elemento tiene todas las propiedades esperadas aplicadas, no solo algunas de ellas.
<button
data-testid="delete-button"
style="display: none; background-color: red"
>
Delete item
</button>
const button = getByTestId('delete-button');
await expect.element(button).toHaveStyle('display: none');
await expect.element(button).toHaveStyle({ display: 'none' });
await expect.element(button).toHaveStyle(`
background-color: red;
display: none;
`);
await expect.element(button).toHaveStyle({
backgroundColor: 'red',
display: 'none',
});
await expect.element(button).not.toHaveStyle(`
background-color: blue;
display: none;
`);
await expect.element(button).not.toHaveStyle({
backgroundColor: 'blue',
display: 'none',
});
Esto también funciona con reglas que se aplican al elemento a través de un nombre de clase para el cual algunas reglas están definidas en una hoja de estilos actualmente activa en el documento. Se aplican las reglas habituales de precedencia de CSS.
toHaveTextContent
function toHaveTextContent(
text: string | RegExp,
options?: { normalizeWhitespace: boolean }
): Promise<void>;
Esto te permite comprobar si el nodo dado tiene contenido de texto o no. Esto es compatible con elementos, pero también con nodos de texto y fragmentos.
Cuando se pasa un argumento string
, realizará una coincidencia parcial que distingue entre mayúsculas y minúsculas con el contenido del nodo.
Para realizar una coincidencia que no distinga entre mayúsculas y minúsculas, puedes usar una RegExp
con el modificador /i
.
Si quieres que coincida con todo el contenido, puedes usar una RegExp
para hacerlo.
<span data-testid="text-content">Text Content</span>
const element = getByTestId('text-content');
await expect.element(element).toHaveTextContent('Content');
// para que coincida con todo el contenido
await expect.element(element).toHaveTextContent(/^Text Content$/);
// para usar una coincidencia que no distinga entre mayúsculas y minúsculas
await expect.element(element).toHaveTextContent(/content$/i);
await expect.element(element).not.toHaveTextContent('content');
toHaveValue
function toHaveValue(value: string | string[] | number | null): Promise<void>;
Esto te permite comprobar si el elemento de formulario dado tiene el valor especificado. Acepta elementos <input>
, <select>
y <textarea>
con la excepción de <input type="checkbox">
y <input type="radio">
, que solo pueden coincidir significativamente usando toBeChecked
o toHaveFormValues
.
También acepta elementos con los roles meter
, progressbar
, slider
o spinbutton
y comprueba su atributo aria-valuenow
(como un número).
Para todos los demás elementos de formulario, el valor se compara utilizando el mismo algoritmo que en toHaveFormValues
.
<input type="text" value="text" data-testid="input-text" />
<input type="number" value="5" data-testid="input-number" />
<input type="text" data-testid="input-empty" />
<select multiple data-testid="select-number">
<option value="first">First Value</option>
<option value="second" selected>Second Value</option>
<option value="third" selected>Third Value</option>
</select>
const textInput = getByTestId('input-text');
const numberInput = getByTestId('input-number');
const emptyInput = getByTestId('input-empty');
const selectInput = getByTestId('select-number');
await expect.element(textInput).toHaveValue('text');
await expect.element(numberInput).toHaveValue(5);
await expect.element(emptyInput).not.toHaveValue();
await expect.element(selectInput).toHaveValue(['second', 'third']);
toHaveDisplayValue
function toHaveDisplayValue(
value: string | RegExp | (string | RegExp)[]
): Promise<void>;
Esto te permite comprobar si el elemento de formulario dado tiene el valor mostrado especificado (el que verá el usuario final). Acepta elementos <input>
, <select>
y <textarea>
con la excepción de <input type="checkbox">
y <input type="radio">
, que solo pueden coincidir significativamente usando toBeChecked
o toHaveFormValues
.
<label for="input-example">First name</label>
<input type="text" id="input-example" value="Luca" />
<label for="textarea-example">Description</label>
<textarea id="textarea-example">An example description here.</textarea>
<label for="single-select-example">Fruit</label>
<select id="single-select-example">
<option value="">Select a fruit...</option>
<option value="banana">Banana</option>
<option value="ananas">Ananas</option>
<option value="avocado">Avocado</option>
</select>
<label for="multiple-select-example">Fruits</label>
<select id="multiple-select-example" multiple>
<option value="">Select a fruit...</option>
<option value="banana" selected>Banana</option>
<option value="ananas">Ananas</option>
<option value="avocado" selected>Avocado</option>
</select>
const input = page.getByLabelText('First name');
const textarea = page.getByLabelText('Description');
const selectSingle = page.getByLabelText('Fruit');
const selectMultiple = page.getByLabelText('Fruits');
await expect.element(input).toHaveDisplayValue('Luca');
await expect.element(input).toHaveDisplayValue(/Luc/);
await expect
.element(textarea)
.toHaveDisplayValue('An example description here.');
await expect.element(textarea).toHaveDisplayValue(/example/);
await expect.element(selectSingle).toHaveDisplayValue('Select a fruit...');
await expect.element(selectSingle).toHaveDisplayValue(/Select/);
await expect.element(selectMultiple).toHaveDisplayValue([/Avocado/, 'Banana']);
toBeChecked
function toBeChecked(): Promise<void>;
Esto te permite comprobar si el elemento dado está marcado. Acepta un input
de tipo checkbox
o radio
y elementos con un role
de checkbox
, radio
o switch
con un atributo aria-checked
válido de "true"
o "false"
.
<input type="checkbox" checked data-testid="input-checkbox-checked" />
<input type="checkbox" data-testid="input-checkbox-unchecked" />
<div role="checkbox" aria-checked="true" data-testid="aria-checkbox-checked" />
<div
role="checkbox"
aria-checked="false"
data-testid="aria-checkbox-unchecked"
/>
<input type="radio" checked value="foo" data-testid="input-radio-checked" />
<input type="radio" value="foo" data-testid="input-radio-unchecked" />
<div role="radio" aria-checked="true" data-testid="aria-radio-checked" />
<div role="radio" aria-checked="false" data-testid="aria-radio-unchecked" />
<div role="switch" aria-checked="true" data-testid="aria-switch-checked" />
<div role="switch" aria-checked="false" data-testid="aria-switch-unchecked" />
const inputCheckboxChecked = getByTestId('input-checkbox-checked');
const inputCheckboxUnchecked = getByTestId('input-checkbox-unchecked');
const ariaCheckboxChecked = getByTestId('aria-checkbox-checked');
const ariaCheckboxUnchecked = getByTestId('aria-checkbox-unchecked');
await expect.element(inputCheckboxChecked).toBeChecked();
await expect.element(inputCheckboxUnchecked).not.toBeChecked();
await expect.element(ariaCheckboxChecked).toBeChecked();
await expect.element(ariaCheckboxUnchecked).not.toBeChecked();
const inputRadioChecked = getByTestId('input-radio-checked');
const inputRadioUnchecked = getByTestId('input-radio-unchecked');
const ariaRadioChecked = getByTestId('aria-radio-checked');
const ariaRadioUnchecked = getByTestId('aria-radio-unchecked');
await expect.element(inputRadioChecked).toBeChecked();
await expect.element(inputRadioUnchecked).not.toBeChecked();
await expect.element(ariaRadioChecked).toBeChecked();
await expect.element(ariaRadioUnchecked).not.toBeChecked();
const ariaSwitchChecked = getByTestId('aria-switch-checked');
const ariaSwitchUnchecked = getByTestId('aria-switch-unchecked');
await expect.element(ariaSwitchChecked).toBeChecked();
await expect.element(ariaSwitchUnchecked).not.toBeChecked();
toBePartiallyChecked
function toBePartiallyChecked(): Promise<void>;
Esto te permite comprobar si el elemento dado está parcialmente marcado. Acepta un input
de tipo checkbox
y elementos con un role
de checkbox
con un aria-checked="mixed"
, o un input
de tipo checkbox
con indeterminate
establecido en true
.
<input type="checkbox" aria-checked="mixed" data-testid="aria-checkbox-mixed" />
<input type="checkbox" checked data-testid="input-checkbox-checked" />
<input type="checkbox" data-testid="input-checkbox-unchecked" />
<div role="checkbox" aria-checked="true" data-testid="aria-checkbox-checked" />
<div
role="checkbox"
aria-checked="false"
data-testid="aria-checkbox-unchecked"
/>
<input type="checkbox" data-testid="input-checkbox-indeterminate" />
const ariaCheckboxMixed = getByTestId('aria-checkbox-mixed');
const inputCheckboxChecked = getByTestId('input-checkbox-checked');
const inputCheckboxUnchecked = getByTestId('input-checkbox-unchecked');
const ariaCheckboxChecked = getByTestId('aria-checkbox-checked');
const ariaCheckboxUnchecked = getByTestId('aria-checkbox-unchecked');
const inputCheckboxIndeterminate = getByTestId('input-checkbox-indeterminate');
await expect.element(ariaCheckboxMixed).toBePartiallyChecked();
await expect.element(inputCheckboxChecked).not.toBePartiallyChecked();
await expect.element(inputCheckboxUnchecked).not.toBePartiallyChecked();
await expect.element(ariaCheckboxChecked).not.toBePartiallyChecked();
await expect.element(ariaCheckboxUnchecked).not.toBePartiallyChecked();
inputCheckboxIndeterminate.element().indeterminate = true;
await expect.element(inputCheckboxIndeterminate).toBePartiallyChecked();
toHaveRole
function toHaveRole(role: ARIARole): Promise<void>;
Esto te permite afirmar que un elemento tiene el rol esperado.
Esto es útil en casos en los que ya tienes acceso a un elemento a través de alguna consulta que no sea el rol en sí, y quieres hacer afirmaciones adicionales con respecto a su accesibilidad.
El rol puede coincidir con un rol explícito (a través del atributo role
), o con uno implícito a través de la semántica ARIA implícita.
<button data-testid="button">Continue</button>
<div role="button" data-testid="button-explicit">Continue</button>
<button role="switch button" data-testid="button-explicit-multiple">Continue</button>
<a href="/about" data-testid="link">About</a>
<a data-testid="link-invalid">Invalid link<a/>
await expect.element(getByTestId('button')).toHaveRole('button');
await expect.element(getByTestId('button-explicit')).toHaveRole('button');
await expect
.element(getByTestId('button-explicit-multiple'))
.toHaveRole('button');
await expect
.element(getByTestId('button-explicit-multiple'))
.toHaveRole('switch');
await expect.element(getByTestId('link')).toHaveRole('link');
await expect.element(getByTestId('link-invalid')).not.toHaveRole('link');
await expect.element(getByTestId('link-invalid')).toHaveRole('generic');
WARNING
Los roles se comparan literalmente por igualdad de cadenas, sin heredar de la jerarquía de roles ARIA. Como resultado, consultar un rol de superclase como checkbox
no incluirá elementos con un rol de subclase como switch
.
También ten en cuenta que, a diferencia de testing-library
, Vitest ignora todos los roles personalizados excepto el primero válido, siguiendo el comportamiento de Playwright:
<div data-testid="switch" role="switch alert"></div>;
await expect.element(getByTestId('switch')).toHaveRole('switch'); // ✅
await expect.element(getByTestId('switch')).toHaveRole('alert'); // ❌
toHaveSelection
function toHaveSelection(selection?: string): Promise<void>;
Esto permite afirmar que un elemento tiene una selección de texto.
Esto es útil para comprobar si el texto o parte del texto está seleccionado dentro de un elemento. El elemento puede ser un input
de tipo texto, un textarea
, o cualquier otro elemento que contenga texto, como un párrafo
, un span
, un div
, etc.
WARNING
La selección esperada es una cadena, no permite comprobar los índices del rango de selección.
<div>
<input type="text" value="text selected text" data-testid="text" />
<textarea data-testid="textarea">text selected text</textarea>
<p data-testid="prev">prev</p>
<p data-testid="parent">
text <span data-testid="child">selected</span> text
</p>
<p data-testid="next">next</p>
</div>
getByTestId('text').element().setSelectionRange(5, 13);
await expect.element(getByTestId('text')).toHaveSelection('selected');
getByTestId('textarea').element().setSelectionRange(0, 5);
await expect.element('textarea').toHaveSelection('text ');
const selection = document.getSelection();
const range = document.createRange();
selection.removeAllRanges();
selection.empty();
selection.addRange(range);
// la selección del hijo también se aplica al padre
range.selectNodeContents(getByTestId('child').element());
await expect.element(getByTestId('child')).toHaveSelection('selected');
await expect.element(getByTestId('parent')).toHaveSelection('selected');
// selección que se aplica desde el anterior, el texto del padre antes del hijo y parte del hijo.
range.setStart(getByTestId('prev').element(), 0);
range.setEnd(getByTestId('child').element().childNodes[0], 3);
await expect.element(queryByTestId('prev')).toHaveSelection('prev');
await expect.element(queryByTestId('child')).toHaveSelection('sel');
await expect.element(queryByTestId('parent')).toHaveSelection('text sel');
await expect.element(queryByTestId('next')).not.toHaveSelection();
// selección que se aplica desde parte del hijo, texto del padre después del hijo y parte del siguiente.
range.setStart(getByTestId('child').element().childNodes[0], 3);
range.setEnd(getByTestId('next').element().childNodes[0], 2);
await expect.element(queryByTestId('child')).toHaveSelection('ected');
await expect.element(queryByTestId('parent')).toHaveSelection('ected text');
await expect.element(queryByTestId('prev')).not.toHaveSelection();
await expect.element(queryByTestId('next')).toHaveSelection('ne');