Fermer

décembre 3, 2021

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é Example_Tests.razor. Il utilisera également l'extension .razor pour pouvoir utiliser la syntaxe razor. Nous pouvons éventuellement hériter de TestContextce qui nous donne un accès rapide aux API de test.

Ensuite, nous utiliserons xUnit pour définir un Factun 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.

Example_Tests.razor

@inherits TestContext
@code {

    [Fact]
    public void ShouldRunTests()
    {
        var ctx = Rendu(@);
        ctx.MarkupMatches(@

Exemple

); } }

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'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);

Maintenant que nous sommes prêts à écrire des tests, nous devons définir la spécification de notre composant.

Spécification du 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.

Role, Property, State and Tabindex Attributes

h3
  • Élément qui sert d'en-tête d'accordéon.
  • Chaque élément d'en-tête d'accordéon contient un bouton qui contrôle le visibilité de son panneau de contenu.
  • L'exemple utilise le niveau de titre 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.
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.
regiondivCrée une région de point de repère qui contient le panneau accordéon actuellement étendu.
aria-labelledby="IDREF"div
  • Définit le nom accessible pour la région Élément .
  • Référence au bouton d'en-tête accordéon qui agrandit et réduit la région.
  • 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éeLorsque le focus est sur l'en-tête accordéon d'une section réduite, développe la section.
Tab
  • Déplace le focus vers l'élément focusable suivant.
  • Tous les éléments focusables de l'accordéon sont inclus dans la séquence de page Tab.
Shift + Tab
  • Déplace le focus sur l'élément focusable précédent.
  • Tous les éléments focusables de l'accordéon sont inclus dans la séquence de la page Tab.
Flèche vers le bas
  • Lorsque le focus est sur un en-tête d'accordéon, déplace le focus vers l'en-tête d'accordéon suivant.
  • Lorsque le focus est sur le dernier en-tête d'accordéon, déplace le focus vers le premier en-tête d'accordéon.
Flèche vers le haut
  • Lorsque le focus est sur un en-tête d'accordéon, déplace le focus vers l'en-tête d'accordéon précédent.
  • Lorsque le focus est sur le premier en-tête d'accordéon, déplace le focus vers le dernier en-tête d'accordéon.
AccueilLorsque le focus est sur un en-tête d'accordéon, déplace le focus vers le premier en-tête d'accordéon.
FinLorsque 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

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 ComponentName_Tests.razormais 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.

AriaAccordion_Tests.razor

@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

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 : 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.

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.

[Fact]
public void FirstRenderMarkupCorrect()
{
    var cut = Render(@
                     
                       

Contenu P1

Contenu P2

); cut.MarkupMatches( @

Contenu P1

... html du deuxième panneau
);

Maintenant que nous avons un test fonctionnel et des composants, nous pouvons commencer à ajouter des fonctionnalités.

Tests d'attributs

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 aria-expanded car elle est directement liée à la fonctionnalité que nous devons implémenter en premier.

Pour cette spécification, nous allons d'abord mettre à jour notre test 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(@
... html du premier panneau



Source link

Revenir vers le haut