Composants Blazor pilotés par les tests d'accessibilité

L'utilisation du développement piloté par les tests avec un accent sur l'accessibilité améliore la qualité des composants Blazor.
Le modèle de composants de Blazor est l'un des plus grands atouts du framework. La création de composants dans le framework est intuitive et créative. La plupart du temps, les choses « fonctionnent ». Combinez l'architecture des composants avec un riche ensemble d'outils de test et vous constaterez que Blazor offre une expérience de développeur productive qui ne ressemble à rien d'autre. Bien que ce dernier morceau puisse sembler sensationnel, ma dernière expérience le rend justifié.
Dans un effort pour en savoir plus sur l'accessibilité sur le Web, j'ai décidé d'expérimenter une idée. J'ai entrepris de créer un composant en utilisant le développement piloté par les tests (TDD), mais cette fois en mettant l'accent sur l'accessibilité. Bien que je ne pense pas que ce soit une idée particulièrement unique, j'ai eu du mal à trouver des ressources ou des conseils sur le sujet. Cependant, j'ai pu trouver quelques exemples génériques de meilleures pratiques pour guider le chemin.
Lorsque l'expérience a été terminée, j'avais un exemple complet qui a été soigneusement testé selon les spécifications. La meilleure partie était tout ce que j'ai appris sur l'accessibilité, la navigation au clavier et les composants de test unitaire. Dans cet article, je décrirai les concepts clés et les conclusions du processus et comment les appliquer dans votre prochaine application.
Blazor dispose d'un écosystème de test assez étendu qui comprend : bUnit, xUnit, Visual Studio et autres. Étant donné que Blazor est écrit à l'aide de .NET, certains de ces outils ont évolué au cours de la vie de la plate-forme, tandis que d'autres, comme bUnit, ont été nouvellement créés pour tester exclusivement les composants Blazor.
bUnit est une bibliothèque de test pour les composants Blazor. Son objectif est de faciliter l'écriture de tests unitaires complets et stables.
Citant directement le site Web bUnit« bUnit est une bibliothèque de test pour les composants Blazor. Son objectif est de faciliter l'écriture de tests unitaires complets et stables. bUnit est développé par un membre de la communauté .NET Egil Hansen et le projet est le standard de facto des tests unitaires de composants pour Blazor.
bUnit fonctionne avec des frameworks de test populaires tels que : xUnit, NUnit et MSTest . Ces frameworks configurent l'environnement de test, tandis que bUnit se concentre sur le rendu et la navigation des composants et leur balisage rendu.
Dans cette expérience, nous utiliserons xUnit et bUnit, avec l'ajout d'une troisième bibliothèque d'aide appelée FluentAssertions. FluentAssertions n'est pas nécessaire ici, mais il améliore considérablement la lisibilité du code de test en fournissant une syntaxe facile à suivre lors de l'écriture d'assertions.
L'installation, les instructions de configuration et la documentation sont faciles à trouver et à suivre sur le site Web de bUnit. Une fois le projet de test créé et configuré, les tests bUnit sont écrits en tant que composants Razor. Cette expérience de C# dans le balisage apporte un facteur de facilité d'utilisation aux tests de composants en éliminant presque le besoin d'échapper au HTML lors de la composition des tests.
Jetons un coup d'œil à un scénario de test simple dans le code ci-dessous. Les tests peuvent être exécutés avec Visual Studio ou la commande CLI dotnet test
. Nous allons prendre un composant simple qui restitue une balise h3
avec du texte, et nous appellerons ce composant à tester Example.razor
.
Example.razor[19659013]Example Pour tester le composant, nous allons créer un appareil de test appelé Ensuite, nous utiliserons xUnit pour définir un Example_Tests.razor C'est le principe de base du test avec bUnit. Plus tard, nous utiliserons des techniques plus avancées pour affirmer des valeurs d'attribut HTML spécifiques et déclencher des événements de composant. Par exemple, nous pouvons utiliser bUnit et FluentAssertions pour valider l' Maintenant que nous sommes prêts à écrire des tests, nous devons définir la spécification de notre composant. Créer une spécification pour un composant en mettant l'accent sur l'accessibilité est la partie la plus importante du processus . La spécification va dicter tout ce qui va se passer ensuite, elle doit donc être aussi détaillée que possible. Le vrai défi ici est de trouver des conseils d'experts si vous (comme moi) n'êtes pas un expert en accessibilité. L'utilisation incorrecte d'éléments sémantiques et d'attributs ARIA peut en fait faire plus de mal que de bien, il est donc important d'être conscient des nuances des technologies d'assistance et de la façon dont elles interprètent les balises et les attributs HTML. Un bon point de départ si vous en apprenez davantage sur l'accessibilité est WAI-ARIA Authoring Practices by the W3C Working Group . Dans ce document, vous trouverez les spécifications d'un composant accordéonqui sont utilisés dans cette expérience. Les spécifications décrivent un plan détaillé pour la mise en œuvre des attributs de rôle, de propriété, d'état et de tabindex appropriés, ainsi que la prise en charge du clavier. Les tableaux suivants sont inclus sur le site Authoring Practices. Pour avoir une idée de quoi est en cours de construction et de test dans cette expérience, voir le Blazor REPL interactif intégré ci-dessous. Cet exemple représente le composant terminé selon les spécifications écrites dans Blazor. Avec la spécification décrite, l'étape suivante consiste à créer un fichier de test. Personnellement, j'aime utiliser la convention AriaAccordion_Tests.razor Comme pour tout processus TDD, il y a un peu un moment de poule et d'œuf où les tests doivent être définis, mais il n'y a rien à tester. Selon la façon dont votre processus est piloté par les tests, vous souhaiterez peut-être écrire des tests avant de définir des composants. Actuellement, nous avons un appareil de test vide avec 13 spécifications d'accessibilité. Ces spécifications ne suffisent pas à elles seules pour commencer – nous aurons également besoin d'un balisage de base pour le rendu. À ce stade, nous avons suffisamment d'informations pour écrire un test de balisage attendu avant de passer à des tests plus ciblés. C'est un peu un exercice d'équilibrage lorsque nous soustrayons le composant et ses sous-composants pour atteindre certaines fonctionnalités de base. C'est un peu un exercice d'équilibrage lorsque nous soustrayons le composant et ses sous-composants pour atteindre certaines fonctionnalités de base. Commençons par la structure HTML de base fournie dans la spécification . À l'aide du code HTML, nous allons créer deux composants : Utilisation des composants Mon contenu pour le panneau A Mon contenu pour le panneau B Voir un exemple entièrement interactif ci-dessous utilisant Telerik REPL pour Blazor. Notre premier test unitaire validera l'état de rendu initial du composant. Pour cela, nous allons écrire un test qui utilise Render et MarkupMatches. Contenu P1 Contenu P2 Contenu P1 Maintenant que nous avons un test fonctionnel et des composants, nous pouvons commencer à ajouter des fonctionnalités. Lors de la rédaction de nos tests, nous allons travailler sur les éléments dans un ordre logique. Dans le cas de notre accordéon, nous avons besoin de fonctionnalités pour développer et réduire les panneaux avant que d'autres fonctionnalités puissent être prises en compte. Commençons par la spécification de Pour cette spécification, nous allons d'abord mettre à jour notre test Example_Tests.razor
. Il utilisera également l'extension .razor
pour pouvoir utiliser la syntaxe razor. Nous pouvons éventuellement hériter de TestContext
ce qui nous donne un accès rapide aux API de test.Fact
un type de méthode de test. Ensuite, le composant à tester (cut
) est rendu par bUnit en utilisant la méthode Render. Une fois rendu, nous pouvons affirmer que le balisage du composant a été rendu correctement en appelant MarkupMatches
.@inherits TestContext
@code {
[Fact]
public void ShouldRunTests()
{
var ctx = Rendu(@
Exemple
);
}
}
id
d'un bouton à l'aide de l'instruction ci-dessous.// Cette div a-t-elle l'identifiant attendu ?
cut.Find("div").Id.Should().Be(value);
Spécification du composant
Role, Property, State and Tabindex Attributes
h3
aria-expanded="true"
button
Défini sur true
lorsque le panneau Accordéon est développé, sinon défini sur faux
.aria-controls="ID"
bouton
Pointe vers l'ID du panneau que l'en-tête contrôle. aria-disabled="true"
button
Si le panneau accordéon est développé et ne peut pas être réduit, définissez-le sur true
.region
div
Crée une région de point de repère qui contient le panneau accordéon actuellement étendu. aria-labelledby="IDREF"
div
région Élément
.Les éléments region
doivent avoir un nom accessible pour être identifié comme un point de repère.Prise en charge du clavier.
Espace ou Entrée Lorsque le focus est sur l'en-tête accordéon d'une section réduite, développe la section. Tab Shift + Tab Flèche vers le bas Flèche vers le haut Accueil Lorsque le focus est sur un en-tête d'accordéon, déplace le focus vers le premier en-tête d'accordéon. Fin Lorsque le focus est sur un en-tête d'accordéon, déplace le focus vers le dernier en-tête d'accordéon. Notre expérience
ComponentName_Tests.razor
mais n'hésitez pas à utiliser une pratique que vous aimez. Pour cet exemple, nous utiliserons AriaAccordion_Tests.razor
. Dans le nouveau test, nous allons configurer un appareil de test, puis copier la spécification directement à l'intérieur sous forme de commentaires.@inherits TestContext
@code {
// Tests d'attributs
// Élément qui sert d'en-tête d'accordéon.
// Chaque élément d'en-tête accordéon contient un bouton qui contrôle la visibilité de son panneau de contenu.
// L'exemple utilise le niveau d'en-tête 3 afin qu'il s'intègre correctement dans le contour de la page ; l'exemple est contenu dans une section intitulée avec un titre de niveau 2.
// bouton aria-expanded="true"
// Défini sur true lorsque le panneau Accordéon est développé, sinon défini sur false.
... les spécifications ont continué
// Finir
// Lorsque le focus est sur un en-tête d'accordéon, déplace le focus vers le dernier en-tête d'accordéon.
}
Tests de rendu
AriaAccordion
et AccordionPanel
. Les composants sont ajoutés au projet pour servir de blocs de construction de base. Leur utilisation est décrite dans l'extrait ci-dessous.[Fact]
public void FirstRenderMarkupCorrect()
{
var cut = Render(@
Tests d'attributs
aria-expanded
car elle est directement liée à la fonctionnalité que nous devons implémenter en premier.FirstRenderMarkupCorrect
pour inclure l'état par défaut de deux panneaux lorsqu'ils sont rendus pour la première fois. Cela garantira qu'un nouvel accordéon sera rendu dans l'état par défaut attendu avant que les modifications ne soient appliquées. L'assertion MarkupMatches est mise à jour de sorte que le premier bouton a l'attribut aria-expanded="true"
et le deuxième panneau a l'attribut hidden
.cut.MarkupMatches(@