L'art du test de mise en page avec le cadre Galen

Publié: 2022-03-10
Résumé rapide ↬ Lors de la conception d'une interface utilisateur graphique, il y a toujours une question ouverte : comment automatiser les tests pour celle-ci ? Et comment s'assurer que la mise en page du site Web reste réactive et s'affiche correctement sur tous les types d'appareils avec différentes résolutions ? Ajoutez à cela les complications liées au contenu dynamique, aux exigences d'internationalisation et de localisation, et cela devient un véritable défi. Dans cet article, je vais vous guider à travers une nouvelle technique de test de mise en page intéressante. En utilisant Galen Framework , je fournirai un tutoriel détaillé pour écrire des tests de mise en page généralisés significatifs, qui peuvent être exécutés dans n'importe quel navigateur et sur n'importe quel appareil et en même temps utilisés comme source unique de vérité dans votre documentation de conception.

Lors de la conception d'une interface utilisateur graphique, il y a toujours une question ouverte : comment automatiser les tests pour celle-ci ? Et comment s'assurer que la mise en page du site Web reste réactive et s'affiche correctement sur tous les types d'appareils avec différentes résolutions ? Ajoutez à cela les complications liées au contenu dynamique, aux exigences d'internationalisation et de localisation, et cela devient un véritable défi.

Dans cet article, je vais vous guider à travers une nouvelle technique de test de mise en page intéressante. En utilisant Galen Framework, je fournirai un tutoriel détaillé pour écrire des tests de mise en page généralisés significatifs, qui peuvent être exécutés dans n'importe quel navigateur et sur n'importe quel appareil et en même temps utilisés comme source unique de vérité dans votre documentation de conception.

Lectures complémentaires sur SmashingMag :

  • Développement visuel piloté par les tests pour une conception d'interface réactive
  • Les bases de l'automatisation des tests pour les applications, les jeux et le Web mobile
  • Divers cadres d'automatisation des tests pour les applications natives React

Je montrerai également comment j'ai trouvé un test optimisé pour une page de messagerie sur notre site de petites annonces, Marktplaats. Nous apprendrons comment étendre la syntaxe de Galen avec notre propre langage, comment améliorer le code de test et comment transformer une routine de test de mise en page en art.

Plus après saut! Continuez à lire ci-dessous ↓

Introduction au cadre Galien

Galen Framework a été couvert il y a un an dans "Visual Test-Driven Development for Responsive Interface Design". A l'époque, sa syntaxe était limitée. Il s'est beaucoup amélioré depuis et a obtenu de nombreuses nouvelles fonctionnalités, que nous examinerons ici.

Si vous n'êtes pas familier avec Galen Framework, il s'agit d'un outil de test de mise en page réactif et multi-navigateurs et de test fonctionnel, avec son propre langage de test, nommé Galen Specs. Il est basé sur Selenium WebDriver et possède également une API JavaScript riche qui vous permet de travailler directement avec WebDriver. Comme vous contrôlez WebDriver, vous pouvez exécuter des tests dans n'importe quel navigateur, dans le cloud (SauceLabs, BrowserStack, PerfectoMobile, etc.) ou sur de vrais appareils mobiles à l'aide d'Appium.

Installation et exécution

La configuration de Galen Framework est simple. Exécutez simplement la commande suivante pour l'installer via npm :

 npm install -g galenframework-cli

Si vous n'utilisez pas npm, téléchargez simplement la dernière archive Galen Framework, extrayez le package et suivez les instructions d'installation.

Une fois installé, Galen Framework peut être lancé de différentes manières. Par exemple, vous pouvez utiliser la commande check pour lancer un test rapide d'une seule page. Pour cette commande, vous devez fournir un fichier .gspec avec vos validations de mise en page, puis vous pouvez l'invoquer comme ceci :

 galen check loginPage.gspec --url https://example.com --size 1024x768 --include desktop --htmlreport reports

Cette commande lancera un navigateur, ouvrira l'URL spécifiée, redimensionnera la fenêtre du navigateur à 1024 × 768 pixels et exécutera toutes les validations déclarées dans le fichier loginPage.gspec . En conséquence, vous obtiendrez un rapport HTML détaillé.

Gestion des suites de tests

Dans le monde réel, une application Web réelle ne se compose pas uniquement de pages statiques. Assez souvent vous allez devoir réaliser certaines actions pour vous rendre à l’endroit que vous souhaitez vérifier. Dans ce cas, Galen propose des suites de tests JavaScript et l'API JavaScript GalenPages pour implémenter le modèle d'objet de page. Voici un exemple simple de test JavaScript Galen :

 test("Home page", function() { var driver = createDriver("https://galenframework.com", "1024x768"); checkLayout(driver, "homePage.gspec", ["desktop"]); });

Et voici une implémentation du modèle d'objet de page pour une page de connexion, tirée d'un projet réel.

 WelcomePage = $page("Welcome page", { loginButton: "#welcome-page .button-login" }); LoginPage = $page("Login page", { username: "input[name='login.username']", password: "input[name='login.password']", loginButton: "button.button-login" loginAs: loggedFunction ("Log in as ${_1.username} with password ${_1.password}", function(user) { this.username.typeText(user.username); this.password.typeText(user.password); this.loginButton.click(); }) }); test("Login page", function() { var driver = createDriver("https://testapp.galenframework.com", "1024x768"); var welcomePage = new WelcomePage(driver).waitForIt(); welcomePage.loginButton.click(); new LoginPage(driver).waitForIt(); checkLayout(driver, "loginPage.gspec", ["desktop"]); });

Pour une utilisation avancée, je vous conseille de regarder le projet Galen Bootstrap. Il s'agit d'une extension JavaScript spécialement conçue pour Galen. Il fournit des fonctionnalités supplémentaires pour les tests d'interface utilisateur et un moyen plus simple de configurer les navigateurs et d'exécuter des suites de tests complexes.

Test de mise en page simple

Permettez-moi de commencer par présenter un test de mise en page simple dans Galen Framework. Ensuite, je passerai aux cas d'utilisation avancés et montrerai comment étendre la syntaxe Galen Specs. Pour cela, nous allons regarder un en-tête avec une icône et une légende :

Icône et légende
Icône et légende (Voir la version agrandie)

En code HTML, cela pourrait ressembler à ceci :

 <body> <!-- … --> <div> <img class="header-logo" src="/imgs/header-logo.png"/> <h1>My Blog</h1> </div> <!-- … --> </body>

La forme la plus simple d'un test de mise en page Galien ressemblerait à ce qui suit. Premièrement, nous devons déclarer des objets avec des sélecteurs CSS.

 @objects header #header icon #header img caption #header h1

Ensuite, nous déclarons une section de test avec un nom significatif et mettons toutes nos validations en dessous.

 = Icon and Caption = icon: left-of caption 10 to 15px width 32px height 32px inside header 10px top caption: aligned horizontally all header inside header

Ici, nous avons testé deux éléments d'en-tête : l'icône et la légende. Toutes les validations répertoriées sous l'icône et les éléments de légende sont en fait des spécifications Galen standard. Ces spécifications sont les blocs de construction fondamentaux avec lesquels vous pouvez assembler votre propre solution de test de mise en page. Chaque spécification vérifie une seule propriété (comme la largeur, la hauteur, le texte), le positionnement relatif (comme à l'intérieur, à gauche de, au-dessus) ou les pixels dans la capture d'écran (comme le jeu de couleurs, l'image).

Tester plusieurs éléments à l'aide de boucles forEach

L'exemple précédent illustre un scénario simple. Voyons comment gérer une situation plus compliquée : un menu horizontal. Tout d'abord, essayons une technique de test de mise en page simple.

Menu horizontal
Menu horizontal (Voir la grande version)

Commencez par faire correspondre plusieurs éléments sur la page. Avec le code suivant, nous disons à Galen de rechercher les éléments qui correspondent au sélecteur CSS #menu ul li .

 @objects menu #menu item-* ul li

Plus tard, nous pouvons faire référence à ces éléments avec des noms tels que menu.item-1 et menu.item-2 et parcourir tous les éléments de menu à l'aide d'une boucle @forEach .

 = Menu = menu.item-1: inside menu 0px top left bottom @forEach [menu.item-*] as menuItem, next as nextItem ${menuItem}: left-of ${nextItem} 0px aligned horizontally all ${nextItem}

Comme vous pouvez le constater, même si la vérification proprement dite n'est pas si complexe, le code est déjà devenu moins intuitif. Imaginez si nous avions plus de code similaire dans nos tests. À un moment donné, cela deviendrait un gâchis impossible à maintenir. Il devrait y avoir moyen de l'améliorer.

Repenser les tests de mise en page

Si vous pensez à l'exemple précédent, il semble que nous pourrions exprimer la mise en page en seulement une ou deux phrases. Par exemple, nous pourrions dire quelque chose comme : « Tous les éléments de menu doivent être alignés horizontalement, sans marge entre eux. Le premier élément de menu doit être situé sur le côté gauche du menu, sans marge. » Parce que nous avons formulé des phrases pour expliquer la mise en page que nous voulons, pourquoi ne pouvons-nous pas simplement les utiliser dans notre code ? Imaginez si nous pouvions écrire le code comme ceci :

 = Menu = |first menu.item-* is in top left corner of menu |menu.item-* are aligned horizontally next to each other

En fait, c'est du vrai code de travail, copié de mon projet. Dans ces deux dernières lignes (en commençant par le tube, | ), nous invoquons des fonctions personnalisées qui collectent leurs arguments en analysant ces deux instructions. Bien sûr, l'exemple ci-dessus ne fonctionnera pas tel quel. Pour qu'il compile, nous devons implémenter les gestionnaires pour ces deux instructions. Nous reviendrons sur cette implémentation plus tard.

Le point clé de l'exemple ci-dessus est que les tests de mise en page sont passés des tests basés sur les objets aux tests basés sur les expressions . Ce n'est peut-être pas évident à partir d'un exemple aussi mineur, mais c'est certainement perceptible à plus grande échelle. Alors, pourquoi est-ce important? La réponse courte est que cela change notre état d'esprit et affecte la façon dont nous concevons notre logiciel et rédigeons des tests pour celui-ci.

En utilisant cette technique, nous ne traitons pas notre page comme un ensemble d'objets avec des relations spécifiques entre eux. Nous ne testons pas les propriétés CSS des éléments individuels. Et nous évitons d'écrire du code compliqué non trivial. Au lieu de cela, nous essayons de penser à des modèles de mise en page communs et à des déclarations significatives. Plutôt que de tester séparément l'élément de menu 1, l'élément de menu 2, etc., nous appliquons des instructions génériques qui :

  • sont reproductibles sur d'autres éléments ;
  • ne contiennent pas de valeurs de pixel codées en dur ;
  • s'appliquent à des abstractions et non à des objets concrets ;
  • et, enfin et surtout, ont un sens lorsque nous les lisons.

Comment ça fonctionne

Permettez-moi d'expliquer le mécanisme des expressions de mise en page personnalisées à l'aide de cet exemple simple :

Esquisse simplifiée
Croquis simple (Voir la grande version)

Dans cet exemple, nous sommes censés vérifier que le bouton s'étend jusqu'au panneau, sans marge à gauche ou à droite. Sans règles personnalisées, nous pouvons l'aborder de différentes manières, mais je préfère la solution suivante :

 button: inside some_panel 0px left right

Le code ci-dessus nous donne la possibilité de déclarer une marge personnalisée sur les côtés, et il teste également implicitement que le bouton est entièrement contenu dans le panneau. L'inconvénient est qu'il n'est pas très lisible, c'est pourquoi je vais mettre cette validation derrière l'expression button stretches to some_panel . Pour que cela fonctionne, nous devons écrire une règle personnalisée comme celle-ci :

 @rule %{elementName} stretches to %{parentName} ${elementName}: inside ${parentName} 0px left right

C'est ça. Maintenant, nous pouvons le mettre dans notre test en une seule ligne :

 | button stretches to some_panel

Comme vous pouvez le voir, cette règle prend deux arguments : elementName et parentName . Cela nous permet de l'appliquer également à d'autres éléments. Remplacez simplement les noms de ces deux objets.

 | login_panel stretches to main_container | header stretches to screen | footer stretches to screen # etc.

Implémentation de votre propre langage de test

Revenons aux exemples initiaux d'expressions de mise en page pour le menu horizontal.

 = Menu = | first menu.item-* is in top left corner of menu | menu.item-* are aligned horizontally next to each other

Nous pouvons implémenter la première règle de la manière suivante :

 @rule first %{itemPattern} is in %{cornerSides} corner of %{parentElement} @if ${count(itemPattern) > 0} ${first(itemPattern).name}: inside ${parentElement} 0px ${cornerSides}

Lorsqu'il est utilisé dans notre exemple, il analyserait les arguments comme suit :

  • itemPattern = menu.item-*
  • cornerSides = en top left
  • parentElement = menu

Comme nous en avons fini avec notre première expression, nous pouvons passer à la suivante. Dans la deuxième expression, nous sommes censés tester l'alignement horizontal de tous les éléments de menu. Je propose trois étapes simples :

  1. Trouver tous les éléments du menu.
  2. Itérer sur chacun d'eux jusqu'à l'avant-dernier élément.
  3. Vérifiez que l'élément n est situé à gauche de l'élément n+1 et que leurs bords supérieur et inférieur sont alignés.

Pour que cela fonctionne, nous devons prendre une boucle @forEach et des spécifications left-of et aligned . Heureusement, dans Galen, vous pouvez vous référer à l'élément précédent ou suivant dans une boucle. Dans le cas où vous avez déclaré une référence à l'élément suivant, il itérera uniquement jusqu'à l'avant-dernier élément, ce qui est exactement ce dont nous avons besoin.

 @rule %{itemPattern} are aligned horizontally next to each other @forEach [${itemPattern}] as item, next as nextItem ${item}: left-of ${nextItem} 0px aligned horizontally all ${nextItem}

Vous pourriez demander, et si nous devions spécifier une marge dans notre test (comme ~ 20px ou 10 to 20px ) ? Ensuite, je suggère soit d'implémenter une règle distincte, soit d'étendre celle qui existe pour prendre en charge un argument %{margin} .

 @rule %{itemPattern} are aligned horizontally next to each other with %{margin} margin @forEach [${itemPattern}] as item, next as nextItem ${item}: left-of ${nextItem} ${margin} aligned horizontally all ${nextItem}

C'est ça! Nous avons créé une expression générique qui nous aide à valider le menu horizontal. Cependant, en raison de sa flexibilité, nous pouvons faire bien plus que cela. Nous pouvons l'utiliser pour tester d'autres éléments de la page. On peut même l'utiliser pour tester l'alignement de deux boutons :

Boutons de formulaire
Boutons de formulaire (Voir la grande version)
 | menu.item-* are aligned horizontally next to each other with 0px margin | submit_button, cancel_button are aligned horizontally next to each other with 20px margin

Vous remarquerez peut-être dans ces deux exemples que nous avons déclaré le premier argument de deux manières différentes. Dans la première expression, le premier argument est “menu.item-*” , et dans la seconde expression, il est déclaré comme “submit_button, cancel_button” . Cela est possible car la boucle @forEach nous permet d'utiliser une liste d'objets séparés par des virgules avec l'opérateur étoile. Mais nous n'en avons pas encore fini avec le refactoring. Nous pourrions encore améliorer le code et le rendre plus lisible. Si nous créons des groupes pour les éléments de menu et les boutons du formulaire de connexion, nous pourrions accomplir quelque chose comme ceci :

 @groups menu_items menu_item-* login_form_buttons submit_button, cancel_button = Testing login page = | &menu_items are aligned horizontally next to each other with 0px margin | &login_form_buttons are aligned horizontally next to each other with 20px margin

Dans ce cas, nous devons utiliser le symbole & , qui représente une déclaration de groupe. C'est déjà un bon test. Tout d'abord, cela fonctionne, et nous sommes en mesure de tester ce dont nous avons besoin. De plus, le code est clair et lisible. Si une autre personne vous demandait à quoi devrait ressembler la page de connexion et quelles sont les exigences de conception, vous pourriez lui dire de regarder le test.

Comme vous pouvez le constater, la mise en œuvre d'expressions personnalisées pour des modèles de mise en page complexes n'est pas vraiment un gros problème. Cela peut être difficile au début, mais cela ressemble toujours à une activité créative.

Marges dynamiques

Examinons un autre modèle de mise en page rare que vous pourriez trouver parfois sur divers sites Web. Et si nous voulions tester que les éléments ont une distance égale entre eux ? Essayons d'implémenter une autre règle pour cela, mais cette fois en utilisant une implémentation JavaScript. Je propose une telle déclaration : “box_item-* are aligned horizontally next to each other with equal distance” . Cela va être un peu délicat car nous ne connaissons pas la marge entre les éléments et nous ne pouvons pas simplement coder en dur les valeurs de pixel. Par conséquent, la première chose que nous devons faire est de récupérer la marge réelle entre le premier et le dernier élément.

Tout aussi éloigné
À distance égale (Voir la version agrandie)

Une fois que nous obtenons cette marge, nous pouvons la déclarer dans une boucle @forEach similaire à ce que nous faisions auparavant. Je propose d'implémenter cette règle à l'aide de l'API JavaScript car la logique requise est un peu plus complexe que dans tous nos exemples précédents. Créons un fichier nommé my-rules.js et tapons ce code :

 rule("%{objectPattern} are aligned horizontally next to each other with equal margin", function (objectName, parameters) { var allItems = findAll(parameters.objectPattern), distance = Math.round(Math.abs(allItems[1].left() - allItems[0].right())), expectedMargin = (distance - 1) + " to " + (distance + 1) + "px"; if (allItems.length > 0) { for (var i = 0; i < allItems.length - 1; i += 1) { var nextElementName = allItems[i + 1].name; this.addObjectSpecs(allItems[i].name, [ "aligned horizontally all " + nextElementName, "left-of " + nextElementName + " " + expectedMargin ]); } } });

Dans notre code de test, nous l'utiliserons comme ceci :

 @script my-rules.js # … = Boxes = | box_item-* are aligned horizontally next to each other with equal distance

Comme vous pouvez le voir, dans Galen Framework, nous pouvons choisir entre deux langages lors de l'implémentation des règles : Galen Specs et JavaScript. Pour les expressions simples, Galen Specs est plus facile à utiliser, mais pour les expressions complexes, je choisis toujours JavaScript. Si vous souhaitez en savoir plus sur les règles JavaScript, reportez-vous à la documentation.

Suppléments de Galien

Après avoir suffisamment joué avec divers modèles de mise en page, j'ai réalisé que toutes ces règles de Galen pouvaient être facilement appliquées dans n'importe quel autre projet de test. Cela m'a donné l'idée de compiler les expressions de mise en page les plus courantes dans leur propre bibliothèque. C'est ainsi que j'ai créé le projet Galen Extras. Voici quelques exemples de ce dont cette bibliothèque est capable :

 | header.icon should be squared | amount of &menu_items should be > 3 | &menu_items are aligned horizontally next to each other | &list_items are aligned vertically above each other with equal distance | every &menu_item is inside menu 0px top and has width > 50px | first &menu_item is inside menu 0px top left | &menu_items are rendered in 2 column table | &menu_items are rendered in 2 column table, with 0 to 1px vertical and 10px horizontal margin | &login_form_elements sides are vertically inside content_container with 20px margin login_panel: | located on the left side of panel and takes 70 % of its width # etc …

La bibliothèque Galen Extras contient de nombreux modèles de mise en page que vous trouverez couramment sur les sites Web, et je continue de la mettre à jour dès que je découvre un modèle utile. Une fois cette bibliothèque mise en place, j'ai décidé de l'essayer sur un vrai projet de test.

Test de l'application de messagerie

Actuellement, je travaille comme ingénieur logiciel chez Marktplaats. À un moment donné, j'ai décidé d'appliquer toute l'expérience que j'avais acquise à un vrai projet. J'avais besoin de tester la page de messagerie sur notre site Web. Voici à quoi cela ressemble:

Messagerie
Page de messagerie (Voir la grande version)

Pour être honnête, la mise en œuvre de tests pour de telles pages m'a toujours semblé un peu effrayante, en particulier les tests de mise en page. Mais avec la bibliothèque Galen Extras en place, tout s'est plutôt bien passé, et bientôt j'ai pu trouver ce code :

 @import ../selected-conversation.gspec @groups (message, messages) messenger.message-* first_two_messages messenger.message-1,messenger.message-2 first_message messenger.message-1 second_message messenger.message-2 third_message messenger.message-3 (message_date_label, message_date_labels) messenger.date_label-* first_date_label messenger.date_label-1 second_date_label messenger.date_label-2 = Messages panel = = Messages and Date labels = |amount of visible &message_date_labels should be 1 |first &message_date_label has text is "17 november 2015" |amount of visible &messages should be 3 |&first_two_messages should be located at the left inside messenger with ~ 20px margin |&third_message should be located at the right inside messenger with ~ 20px margin |&messages are placed above each other with 10 to 15px margin |text of all &messages should be ["Hi there!", "I want to buy something", "Hello! Sure, it's gonna be 100 euros"] = Styling = |&first_two_messages should be styled as others message |&third_message should be styled as own message

Extraction de plages de pixels

Le test avait l'air correct : il était compact et lisible mais encore loin d'être parfait. Je n'aimais pas vraiment toutes ces définitions de marge ( ~ 20px , 10 to 15px ). Certains d'entre eux étaient répétés, et il était difficile de comprendre ce que chacun d'eux représentait. C'est pourquoi j'ai décidé de cacher chaque marge derrière une variable significative.

 # ... @set messages_side_margin ~ 20px messages_vertical_margin 10 to 15px = Messages panel = = Messages and Date labels = |amount of visible &message_date_labels should be 1 |first &message_date_label has text is "17 november 2015" |amount of visible &messages should be 3 |&first_two_messages should be located at the left inside messenger with ${messages_side_margin} margin |&third_message should be located at the right inside messenger with ${messages_side_margin} margin |&messages are placed above each other with ${messages_vertical_margin} margin # ...

Comme vous pouvez le voir, j'ai déplacé les marges vers messages_vertical_margin et messages_side_margin . J'ai également déclaré une marge minimal , qui est comprise entre 0 et 1 pixel.

 # ... @set minimal 0 to 1px = Conversations Panel = | &conversations are aligned above each other with ${minimal} margin # ...

Validation basée sur l'image et expressions personnalisées

Après avoir couvert le positionnement de tous les éléments principaux sur la page, j'ai décidé également de tester le style. Je voulais valider que chaque message a une couleur de fond spécifique au rôle de l'utilisateur. Lorsque les utilisateurs sont connectés, les messages ont un fond bleu clair. Les messages destinés aux autres utilisateurs auraient un fond blanc. Au cas où un message n'aurait pas été envoyé, l'alerte d'erreur aurait un fond rose. Voici la règle qui m'a aidé à valider ces styles :

 @set OWN_MESSAGE_COLOR #E1E8F5 OTHERS_MESSAGE_COLOR white ERROR_MESSAGE_COLOR #FFE6E6 @rule %{item} should be styled as %{style} message ${item}: @if ${style === "own"} color-scheme > 60% ${OWN_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR} @elseif ${style === "error"} color-scheme > 60% ${ERROR_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR} @else color-scheme > 60% ${OTHERS_MESSAGE_COLOR}, 0.2 to 20 % ${MAJOR_TEXT_MESSAGE_COLOR}

La spécification color-scheme de couleurs vérifie la distribution proportionnelle des couleurs dans un élément. Il recadre une capture d'écran de la page et analyse la distribution des couleurs. Ainsi, pour vérifier la couleur de fond d'un élément, on vérifie simplement que sa répartition est supérieure à 60% de la gamme de couleurs totale. Dans le test, cette règle est invoquée comme suit :

 = Styling = |&first_two_messages should be styled as others message |&third_message should be styled as own message

Configuration des suites de tests

L'application de messagerie est une application dynamique qui fonctionne avec l'API RESTful Messaging. Par conséquent, pour tester ses mises en page dans tous les états différents, nous devons préparer des données de test. J'ai décidé de modéliser l'API de messagerie afin de pouvoir configurer tous mes messages de test dans la suite de tests. Voici un fragment de ma suite de tests qui montre comment nos tests sont structurés.

 // ... testOnAllDevices("Unselected 2 conversations", "/", function (driver, device) { mock.onGetMyConversationsReturn(sampleConversations); refresh(driver); new MessageAppPage(driver).waitForIt(); checkLayout(driver, "specs/tests/unselected-conversations.gspec", device.tags); }); testOnAllDevices("When clicking a conversation it should reveal messages", "/", function (driver, device) { mock.onGetMyConversationsReturn(sampleConversations); mock.onGetSingleConversationReturn(sampleMessages); refresh(driver); var page = new MessageAppPage(driver).waitForIt(); page.clickFirstConversation(); checkLayout({ driver: driver, spec: "specs/tests/three-simple-messages-test.gspec", tags: device.tags, vars: { expectedTextProvider: textProvider({ "messenger.message-1": "Hi there!\n11:02", "messenger.message-2": "I want to buy something\n12:02", "messenger.message-3": "Hello! Sure, it's gonna be 100 euros\n13:02" }) } }); }); // ...

Attraper des bogues

La mise en œuvre de ces expressions simples porte ses fruits assez rapidement. Passons en revue les types de bogues que nous pouvons détecter avec notre suite de tests.

Problème de style

Voici un exemple de cas où quelque chose ne va pas dans notre base de code CSS et, par conséquent, tous les messages sont rendus avec le même arrière-plan.

Mauvaise couleur d'arrière-plan du message
Mauvaise couleur d'arrière-plan du message (Afficher la version agrandie)

Si vous comparez cette capture d'écran avec l'original, vous remarquerez que le dernier message a un fond blanc, alors qu'il est censé être bleu clair. Voyons comment Galen signale ce problème :

Capture d'écran avec message d'erreur
Capture d'écran avec message d'erreur (Voir la version agrandie)

Pour l'objet en surbrillance, il affiche la color #e1e8f5 on “messenger.message-3” is 0% but it should be greater than 60% . Pour être honnête, ce message d'erreur n'a pas l'air très clair, mais comme cette vérification a été générée à partir d'une règle personnalisée, nous pouvons toujours rechercher son nom d'origine dans une branche de rapport :

Signaler l'échec du test
Signaler l'échec du test (Voir la grande version)

Si vous faites défiler vers le haut, vous verrez que la déclaration d'origine est &third_message should be styled as own message . C'est un autre avantage de l'utilisation d'expressions personnalisées : elles vous aident à comprendre l'échec et décrivent bien toutes ces validations générées.

Problème de positionnement

Voici un autre exemple de problème de mise en page dû à un alignement incorrect d'un élément. Dans la capture d'écran suivante, vous pouvez voir que le dernier message est positionné sur le côté gauche de la fenêtre de messagerie, au lieu de la droite.

Mauvaise position du message
Mauvaise position du message (Voir la version agrandie)

Reprenons la capture d'écran avec le message d'erreur :

Mauvaise position du message
Mauvaise position du message (Voir la version agrandie)

La capture d'écran met en évidence le conteneur de messagerie et le dernier élément de message. Parallèlement à cela, il affiche le message d'erreur suivant : “messenger.message-3” is 285px right which is not in range of 22 to 28px . Un développeur Web peut ne pas comprendre pourquoi une marge de 22 à 28 pixels est attendue sur le côté droit. Encore une fois, vous devrez rechercher une déclaration de validation dans la branche de rapport :

Mauvaise position du message
Mauvaise position du message (Voir la version agrandie)

La déclaration d'origine pour cette vérification est &third_message should be located at the right inside messenger with ~ 25px margin . Cela a beaucoup plus de sens. De plus, d'autres ingénieurs frontaux comprendront ce rapport de test, même s'ils n'ont pas écrit les tests.

Directives de test de mise en page

Avec toutes ces différentes expériences à l'esprit, j'ai décidé de formaliser tout l'apprentissage dans des directives générales de test de mise en page. Voici une liste de contrôle rapide des étapes à suivre pour faciliter votre routine de test.

  • Identifiez les modèles de mise en page dans la conception.
  • Généraliser les instructions de validation. Essayez de condenser la plupart des validations en phrases simples.
  • Composez ! Il est toujours préférable de déplacer les tests d'éléments répétés dans des composants dédiés.
  • Utilisez des noms significatifs pour les sections, les règles et les objets.
  • Évitez les pixels. Essayez de remplacer les valeurs de pixel (qu'il s'agisse de valeurs exactes ou de plages) par des variables significatives.
  • Ajustez le code de votre site Web pour le rendre plus facile à tester. Cela vous aidera à structurer et à maintenir à la fois votre code de production et de test.

Critères d'acceptation à la rescousse

Souvent, je reçois des questions telles que : "A quel point un test de mise en page doit-il être détaillé ? Et que devrions-nous tester spécifiquement ? » Une réponse générale est difficile à donner. Le problème est que lorsque la couverture du test est faible, vous manquez des bugs. D'un autre côté, si vous avez des tests trop détaillés, vous pourriez obtenir beaucoup de faux positifs et, à l'avenir, vous pourriez vous perdre dans la maintenance des tests. Donc, il y a un compromis. Mais j'ai trouvé une ligne directrice générale pour moi-même. Si vous divisez le travail en histoires d'utilisateurs plus petites, il devient alors plus facile de structurer la conception d'une page sous la forme de critères d'acceptation. En fin de compte, vous pourriez mettre ces critères d'acceptation directement dans votre code de test. Par exemple, certaines de ces instructions peuvent être définies sous la forme de règles personnalisées, comme indiqué dans tous les exemples de code précédents. Un bon exemple de critères d'acceptation serait quelque chose comme ceci :

  • Les popups doivent être centrés verticalement et horizontalement sur l'écran.
  • Ils doivent avoir une largeur de 400 pixels.
  • Les boutons doivent être alignés horizontalement.
  • Etc

Une fois que vous avez décrit la conception en phrases simples, il devient plus facile de les convertir en instructions réutilisables et d'organiser votre code de test.

Conclusion

Comme vous pouvez le constater, un tel exercice vous aide à structurer une conception et à découvrir des modèles de mise en page généraux pouvant être partagés entre plusieurs composants de page. Même si la page est complexe et se compose de nombreux éléments, vous pouvez toujours trouver un moyen de les regrouper dans vos expressions de mise en page. Avec cette approche, les tests de mise en page deviennent davantage un outil de développement piloté par les tests, vous aidant à concevoir, implémenter et fournir des logiciels de manière incrémentielle, ce qui est particulièrement utile dans un environnement agile.

Ressources

  • Cadre Galien (site officiel)
  • Cadre Galien, GitHub
  • Galen Extras (bibliothèque), GitHub
  • Galen Bootstrap, GitHub
  • "Tutoriels sur le cadre Galen", YouTube