API d'assertions
Vitest intègre une vaste gamme d'assertions DOM, héritées de la bibliothèque @testing-library/jest-dom
, enrichies d'un support étendu pour les localisateurs et d'une capacité de réessai native.
Support TypeScript
Si vous utilisez TypeScript ou souhaitez bénéficier d'un typage correct pour expect
, assurez-vous que @vitest/browser/context
est référencé quelque part. Si vous n'avez jamais importé depuis ce module, vous pouvez ajouter un commentaire de référence dans n'importe quel fichier couvert par votre tsconfig.json
:
/// <reference types="@vitest/browser/context" />
Les tests dans le navigateur peuvent échouer de manière intermittente en raison de leur nature asynchrone. Il est donc crucial de s'assurer que les assertions réussissent, même si la condition est retardée (par exemple, par un délai d'attente, une requête réseau ou une animation). À cette fin, Vitest propose des assertions avec un mécanisme de réessai intégré via les API expect.poll
et expect.element
:
import { expect, test } from 'vitest';
import { page } from '@vitest/browser/context';
test('error banner is rendered', async () => {
triggerError();
// Ceci crée un localisateur qui tentera de trouver l'élément lorsque l'une de ses méthodes est appelée.
// Cet appel seul ne vérifie pas l'existence de l'élément.
const banner = page.getByRole('alert', {
name: /error/i,
});
// Vitest propose `expect.element` avec une fonctionnalité de réessai intégrée.
// Il vérifiera de manière répétée que l'élément existe dans le DOM et que le contenu de `element.textContent` est égal à "Error!" jusqu'à ce que toutes les conditions soient remplies.
await expect.element(banner).toHaveTextContent('Error!');
});
Nous recommandons d'utiliser systématiquement expect.element
avec les localisateurs page.getBy*
pour réduire la volatilité des tests. Notez que expect.element
accepte une deuxième option :
interface ExpectPollOptions {
// Intervalle de réessai de l'assertion (en millisecondes)
// Par défaut : option de configuration "expect.poll.interval"
interval?: number;
// Délai d'expiration du réessai (en millisecondes)
// Par défaut : option de configuration "expect.poll.timeout"
timeout?: number;
// Message affiché en cas d'échec de l'assertion
message?: string;
}
TIP
expect.element
est un raccourci pour expect.poll(() => element)
et fonctionne exactement de la même manière.
toHaveTextContent
et toutes les autres assertions sont toujours disponibles sur un expect
régulier sans mécanisme de réessai intégré :
// échouera immédiatement si .textContent n'est pas égal à `'Error!'`
expect(banner).toHaveTextContent('Error!');
toBeDisabled
function toBeDisabled(): Promise<void>;
Permet de vérifier si un élément est désactivé pour l'utilisateur.
La correspondance est établie si l'élément est un contrôle de formulaire et que l'attribut disabled
y est spécifié, ou s'il est un descendant d'un élément de formulaire possédant un attribut disabled
.
Notez que seuls les éléments de contrôle natifs tels que HTML button
, input
, select
, textarea
, option
, optgroup
peuvent être désactivés en leur attribuant l'attribut disabled
. L'attribut disabled
est ignoré sur les autres éléments, à moins qu'il ne s'agisse d'un élément personnalisé.
<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>;
Permet de vérifier si un élément n'est pas désactivé du point de vue de l'utilisateur.
Fonctionne comme not.toBeDisabled()
. Utilisez ce matcher pour éviter la double négation dans vos tests.
<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>;
Cela vous permet de vérifier qu'un élément ne contient aucun contenu visible pour l'utilisateur. Il ignore les commentaires mais échouera si l'élément contient des espaces.
<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>;
Vérifie si un élément est présent dans le document.
<svg data-testid="svg-element"></svg>
await expect.element(getByTestId('svg-element')).toBeInTheDocument();
await expect.element(getByTestId('does-not-exist')).not.toBeInTheDocument();
WARNING
Ce matcher ne trouve pas les éléments détachés. L'élément doit être présent dans le document pour que toBeInTheDocument
le trouve. Si vous souhaitez rechercher dans un élément détaché, utilisez plutôt : toContainElement
.
toBeInvalid
function toBeInvalid(): Promise<void>;
Cela vous permet de vérifier si un élément est invalide.
Un élément est invalide s'il possède un attribut aria-invalid
(sans valeur ou avec la valeur "true"
), ou si le résultat de checkValidity()
est 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>;
Cela vous permet de vérifier si un élément de formulaire est requis.
Un élément est requis s'il a un attribut required
ou 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>;
Cela vous permet de vérifier si la valeur d'un élément est valide.
Un élément est valide s'il n'a pas d'attribut aria-invalid
ou si cet attribut a la valeur "false"
. De plus, si c'est un élément de formulaire, le résultat de checkValidity()
doit être true
.
<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>;
Cela vous permet de vérifier si un élément est actuellement visible pour l'utilisateur.
Un élément est considéré comme visible s'il possède une boîte de délimitation non vide et que son style calculé n'est pas visibility:hidden
.
Notez que selon cette définition :
- Les éléments de dimension nulle ne sont pas considérés comme visibles.
- Les éléments avec
display:none
ne sont pas considérés comme visibles. - Les éléments avec
opacity:0
sont considérés comme visibles.
Pour vérifier qu'au moins un élément de la liste est visible, utilisez locator.first()
.
// Un élément spécifique est visible.
await expect.element(page.getByText('Welcome')).toBeVisible();
// Au moins un des éléments de la liste est visible.
await expect.element(page.getByTestId('todo-item').first()).toBeVisible();
// Au moins l'un des deux éléments est visible, voire les deux.
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>;
Cela vous permet d'affirmer si un élément contient un autre élément en tant que descendant ou non.
<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>;
Vérifie si une chaîne représentant un élément HTML est incluse dans un autre élément. La chaîne doit être du HTML valide, et non un fragment incomplet.
<span data-testid="parent"><span data-testid="child"></span></span>
// Exemples d'utilisations valides :
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 />');
// Ces exemples ne fonctionneront pas :
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
Il est probable que vous n'ayez pas besoin d'utiliser ce matcher. Nous encourageons les tests du point de vue de l'utilisateur, c'est-à-dire de la manière dont il perçoit l'application dans un navigateur. C'est pourquoi tester contre une structure DOM spécifique n'est pas conseillé.
Cela peut être utile lorsque le code testé génère du HTML provenant d'une source externe, et que vous souhaitez valider que ce code HTML a été utilisé comme prévu.
Il ne doit pas être utilisé pour vérifier la structure DOM dont vous avez la maîtrise. Veuillez utiliser toContainElement
à la place.
toHaveAccessibleDescription
function toHaveAccessibleDescription(
description?: string | RegExp
): Promise<void>;
Cela vous permet de vérifier qu'un élément possède la description accessible attendue.
Vous pouvez fournir la chaîne exacte de la description accessible attendue, ou effectuer une correspondance partielle en utilisant une expression régulière, ou encore expect.stringContaining
ou 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>;
Cela vous permet de vérifier qu'un élément possède le message d'erreur accessible attendu.
Vous pouvez passer la chaîne exacte du message d'erreur accessible attendu. Alternativement, vous pouvez effectuer une correspondance partielle en utilisant une expression régulière ou expect.stringContaining
ou 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"
/>
// Champs de saisie avec des messages d'erreur valides
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!');
// Champs de saisie sans messages d'erreur valides
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>;
Cela vous permet de vérifier qu'un élément possède le nom accessible attendu. C'est utile, par exemple, pour s'assurer que les éléments de formulaire et les boutons sont correctement étiquetés.
Vous pouvez fournir la chaîne exacte du nom accessible attendu, ou effectuer une correspondance partielle en utilisant une expression régulière, ou encore expect.stringContaining
ou 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>;
Cela vous permet de vérifier si l'élément donné possède un attribut. Vous pouvez également vérifier que l'attribut a une valeur spécifique attendue, ou qu'il correspond partiellement en utilisant expect.stringContaining
ou 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>;
Cela vous permet de vérifier si l'élément donné possède certaines classes dans son attribut class
. Vous devez fournir au moins une classe, à moins que vous ne vérifiiez qu'un élément n'en a aucune.
La liste des noms de classes peut inclure des chaînes et des expressions régulières. Les expressions régulières sont comparées à chaque classe individuelle de l'élément cible, et non à la valeur complète de son attribut class
.
WARNING
Notez que l'option exact: true
ne peut pas être utilisée lorsque seules des expressions régulières sont spécifiées.
<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/);
// ⚠️ les expressions régulières s'appliquent aux classes individuelles, pas à la liste de classes entière
await expect.element(deleteButton).not.toHaveClass(/btn extra/);
// l'élément possède EXACTEMENT l'ensemble de classes spécifié (dans n'importe quel ordre)
await expect.element(deleteButton).toHaveClass('btn-danger extra btn', {
exact: true,
});
// s'il possède plus de classes que prévu, cela échouera
await expect.element(deleteButton).not.toHaveClass('btn-danger extra', {
exact: true,
});
await expect.element(noClasses).not.toHaveClass();
toHaveFocus
function toHaveFocus(): Promise<void>;
Cela vous permet de vérifier si un élément a le focus.
<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>;
Cela vous permet de vérifier si un formulaire ou un fieldset contient des contrôles de formulaire pour chaque nom donné, avec la valeur spécifiée.
TIP
Il est important de souligner que ce matcher ne peut être invoqué que sur un élément form ou fieldset.
Cela lui permet d'utiliser la propriété .elements
des éléments form
et fieldset
pour récupérer de manière fiable tous les contrôles de formulaire qu'ils contiennent.
Cela évite également que les utilisateurs ne fournissent un conteneur avec plusieurs form
, ce qui pourrait mélanger des contrôles de formulaire non liés et potentiellement conflictuels.
Ce matcher fait abstraction des spécificités de récupération de la valeur d'un contrôle de formulaire en fonction de son type. Par exemple, les éléments <input>
ont un attribut value
, contrairement aux éléments <select>
. Voici une liste de tous les cas couverts :
- Les éléments
<input type="number">
renvoient la valeur sous forme de nombre, au lieu d'une chaîne. - Éléments
<input type="checkbox">
:- si un seul élément possède l'attribut
name
donné, il est traité comme un booléen, renvoyanttrue
si la case est cochée,false
si elle est décochée. - si plusieurs cases à cocher partagent le même attribut
name
, elles sont toutes traitées collectivement comme un seul contrôle de formulaire, qui renvoie la valeur sous forme de tableau contenant toutes les valeurs des cases à cocher sélectionnées dans la collection.
- si un seul élément possède l'attribut
- Les éléments
<input type="radio">
sont tous regroupés par l'attributname
, et ce groupe est traité comme un seul contrôle de formulaire. Ce contrôle de formulaire renvoie la valeur sous forme de chaîne, correspondant à l'attributvalue
du bouton radio sélectionné dans le groupe. - Les éléments
<input type="text">
renvoient la valeur sous forme de chaîne. Cela s'applique également aux éléments<input>
ayant tout autre attributtype
non explicitement couvert par les règles précédentes (par exemple,search
,email
,date
,password
,hidden
, etc.) - Les éléments
<select>
sans l'attributmultiple
renvoient la valeur sous forme de chaîne correspondant à l'attributvalue
de l'option sélectionnée, ouundefined
si aucune option n'est sélectionnée. - Les éléments
<select multiple>
renvoient la valeur sous forme de tableau contenant toutes les valeurs des options sélectionnées. - Les éléments
<textarea>
renvoient leur valeur sous forme de chaîne. Cette valeur correspond à leur contenu textuel.
Les règles ci-dessus facilitent, par exemple, le passage d'un contrôle de sélection unique à un groupe de boutons radio. Ou le passage d'un contrôle de sélection multiple à un groupe de cases à cocher. L'ensemble résultant des valeurs de formulaire utilisées par ce matcher pour la comparaison serait le même.
<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>;
Cela vous permet de vérifier si un certain élément possède des propriétés CSS spécifiques avec des valeurs définies. Il ne correspond que si l'élément possède toutes les propriétés attendues, et non seulement une partie d'entre elles.
<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',
});
Cela fonctionne également avec les règles appliquées à l'élément via un nom de classe, lorsque ces règles sont définies dans une feuille de style actuellement active dans le document. Les règles habituelles de précédence CSS sont respectées.
toHaveTextContent
function toHaveTextContent(
text: string | RegExp,
options?: { normalizeWhitespace: boolean }
): Promise<void>;
Cela vous permet de vérifier si le nœud donné possède un contenu textuel. Cela s'applique aux éléments, ainsi qu'aux nœuds de texte et aux fragments.
Lorsqu'un argument de type string
est fourni, il effectuera une correspondance partielle sensible à la casse avec le contenu du nœud.
Pour une correspondance insensible à la casse, utilisez une RegExp
avec le modificateur /i
.
Si vous souhaitez correspondre à l'intégralité du contenu, utilisez une RegExp
.
<span data-testid="text-content">Text Content</span>
const element = getByTestId('text-content');
await expect.element(element).toHaveTextContent('Content');
// pour correspondre à l'intégralité du contenu
await expect.element(element).toHaveTextContent(/^Text Content$/);
// pour une correspondance insensible à la casse
await expect.element(element).toHaveTextContent(/content$/i);
await expect.element(element).not.toHaveTextContent('content');
toHaveValue
function toHaveValue(value: string | string[] | number | null): Promise<void>;
Cela vous permet de vérifier si l'élément de formulaire donné possède la valeur spécifiée. Il accepte les éléments <input>
, <select>
et <textarea>
, à l'exception de <input type="checkbox">
et <input type="radio">
, qui ne peuvent être comparés de manière pertinente qu'avec toBeChecked
ou toHaveFormValues
.
Il accepte également les éléments avec les rôles meter
, progressbar
, slider
ou spinbutton
et vérifie leur attribut aria-valuenow
(interprété comme un nombre).
Pour tous les autres éléments de formulaire, la valeur est comparée selon le même algorithme que 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>;
Cela vous permet de vérifier si l'élément de formulaire donné possède la valeur affichée spécifiée (celle visible par l'utilisateur final). Il accepte les éléments <input>
, <select>
et <textarea>
, à l'exception de <input type="checkbox">
et <input type="radio">
, qui ne peuvent être comparés de manière pertinente qu'avec toBeChecked
ou 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>;
Cela vous permet de vérifier si l'élément donné est sélectionné (coché). Il accepte un input
de type checkbox
ou radio
, ainsi que des éléments avec un role
de checkbox
, radio
ou switch
et un attribut aria-checked
valide ("true"
ou "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>;
Cela vous permet de vérifier si l'élément donné est partiellement sélectionné (coché). Il accepte un input
de type checkbox
et des éléments avec un role
de checkbox
ayant un aria-checked="mixed"
, ou un input
de type checkbox
dont la propriété indeterminate
est 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>;
Cela vous permet de vérifier qu'un élément possède le rôle attendu.
C'est utile lorsque vous avez déjà accès à un élément par une requête autre que le rôle lui-même, et que vous souhaitez effectuer des assertions supplémentaires concernant son accessibilité.
Le rôle peut correspondre à un rôle explicite (via l'attribut role
) ou à un rôle implicite via les sémantiques ARIA implicites.
<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
Les rôles sont comparés littéralement par leur valeur de chaîne, sans hériter de la hiérarchie des rôles ARIA. Par conséquent, une requête sur un rôle de superclasse comme checkbox
n'inclura pas les éléments ayant un rôle de sous-classe comme switch
.
Notez également que, contrairement à testing-library
, Vitest ignore tous les rôles personnalisés à l'exception du premier rôle valide, conformément au comportement 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>;
Cela permet de vérifier qu'un élément possède une sélection de texte.
C'est utile pour vérifier si du texte ou une partie du texte est sélectionné au sein d'un élément. L'élément peut être un champ de saisie de type texte, une zone de texte, ou tout autre élément contenant du texte (par exemple, un paragraphe, un span
, un div
, etc.).
WARNING
La sélection attendue est une chaîne ; elle ne permet pas de vérifier les indices de plage de sélection.
<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 sélection de l'enfant est également prise en compte pour le parent
range.selectNodeContents(getByTestId('child').element());
await expect.element(getByTestId('child')).toHaveSelection('selected');
await expect.element(getByTestId('parent')).toHaveSelection('selected');
// sélection s'étendant de l'élément précédent, incluant le texte parent avant l'enfant, et une partie de l'enfant.
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();
// sélection s'étendant d'une partie de l'enfant, incluant le texte parent après l'enfant, et une partie de l'élément suivant.
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');