Comme vous le savez les outils d’automatisation des tests UI comme Selenium , WebdriverIO , etc utilisent le même principe de fonctionnement et partagent les mêmes problématiques.
Tous les tests réalisés avec un outil webdriver sont principalement basés sur le contenu du DOM et utilisent les sélecteurs web pour interagir avec l’interface utilisateur via des drivers (chromedriver, geckodriver, etc.).
Cette réalité représente un vrai problème de dépendance entre les tests et la structure de l’interface utilisateur, un changement ainsi au niveau de l’UI implique une mise a jour a faire au niveau des tests.
Il est donc essentiel de choisir soigneusement la meilleure stratégie pour résister au changement de l’interface utilisateur afin :
Dans cet article je vais vous présenter les sélecteurs d’éléments web officiellement supportés par le W3C, évaluer leurs inconvénients et leurs avantages afin de vous aider à choisir la meilleure stratégie pour mener à bien votre projet d’automatisation d’UI.
Sans trop entrer dans les détails techniques de chaque outil, framework ou api, le principe de fonctionnement simplifié est le suivant:
1. Sélection de l’élément web (bouton, lien, menu déroulant, etc.) 2. Interaction avec l’élément sélectionné (simple clique, saisie d’un texte, récupération de texte, etc.) 3. Vérification des résultats à travers des assertions
Souvent les tests échouent durant l’étape de sélection de l’élément web et vous perdrez donc le temps dans l’analyse des messages d’erreur de type:
Not found exception
An element could not be located on the page
Unable to locate element
NoSuchElementError
X exception
Après analyse des erreurs, vous vous rendez compte qu’une simple balise html div à été supprimée par les développeurs ou la valeur de l’ID à été mise à jour de: <input type="text" id="user" name="user">
a <input type="text" id="username" name="username">
Cette problématique se multiplie notamment si les automaticiens et les développeurs ne sont pas dans la même équipe et / ou sans réelle collaboration.
Sans surprise, les résultats sont les suivants :
L’élément essentiel de la solution est la capacité d’identifier le bon sélecteur / sélecteur (locator).
Indépendamment du débat sur Xpath vs CSS, un bon sélecteur possède les caractéristiques suivantes:
Nous passons maintenant à l’analyse des différentes stratégies supportés par le W3C afin d’identifier la meilleure stratégie possible.
Petit rappel de la liste des des stratégies officielles du W3C:
Pour garder le focus sur l’essentiel et afin d’éviter d’entrer dans les détails de chaque stratégie qui ne sont pas nécessairement utiles, les différentes stratégies seront classés en grandes catégories:
Link Text
, Partial Link Text
et Tag Name
CSS
et Xpath
ID
et Class
data-*
avec les sélecteurs CSS
Link Text
, Partial Link Text
et Tag Name
Les sélecteurs Link Text, Partial Link Text, et Tag Name ont le même problème, c’est le manque de résistance au changement qui peut avoir une page ou un composant html durant le cycle de vie d’un projet et donc les flaky tests !
Voici un simple exemple pour mieux comprendre la problématique:
Supposons que nous avons le code HTML suivant:
<h1 class="heading">Welcome to the-internet</h1>
<h2>Available Examples</h2>
<ul>
<li><a href="/upload">File Upload</a></li>
<li><a href="/floating_menu">Floating Menu</a></li>
<li><a href="/forgot_password">Reset Password</a></li>
</ul>
Maintenant pour automatiser notre scénario de test forgot_password
, nous avons besoin de cliquer sur le lien /forgot_password, la solution la plus simple pour sélectionner l’élément web c’est d’utiliser la stratégie Link Text
avec l’instruction selenium webdriver suivante await driver.findElement(By.linkText("Reset Password")).click()
Bien, le test (click) devrait fonctionner !
Maintenant le développeur repasse sur le code HTML, il trouve que Reset Password
n’est pas trop sémantique et il serait super bien de changer le texte Reset Password
par Forgot Password
, un simple changement qui ne coûte rien !
Suite à cette modification, nous avons donc le nouveau code html suivant:
<h1 class="heading">Welcome to the-internet</h1>
<h2>Available Examples</h2>
<ul>
<li><a href="/upload">File Upload</a></li>
<li><a href="/floating_menu">Floating Menu</a></li>
<li><a href="/forgot_password">Forgot Password</a></li>
</ul>
Nous exécutons à nouveau le même test forgot_password
pour vérifier si tout va bien !
Exécution des tests en cours …
Boom !
Le test ne passe plus!, Ona la fameuse exception NoSuchElementException
.
Vous devez comprendre maintenant que cette stratégie n’est pas la meilleure façon de faire ce travail, une telle stratégie axée sur le contenu est sans doute une mauvaise stratégie !
Utilisez-les uniquement si vous avez un besoin spécifique et qu’aucune autre option n’est disponible !
CSS
et Xpath
Indépendamment du débat sur Xpath vs CSS, ces deux sélecteurs sont conceptuellement très similaires, c’est pour cela je les ai rassemblés pour cette catégorie.
XPath dispose la possibilité de sélectionner des éléments parents, cette option est particulièrement intéressante pour certains scénarios et CSS dispose une syntaxe relativement simple !
Quelques points d’attention:
Ces types de sélecteurs avec des combinaisons de nom de balise, d’éléments descendants, de classe CSS (ou d’attribut d’élément) rendent le modèle de sélection strict ou lâche, ce qui signifie que de petites modifications HTML l’invalideront et perdront le sens qu’il pourrait correspondre à plus d’un élément HTML.
Lors de l’écriture d’un sélecteur Xpath ou CSS, il s’agit de trouver l’équilibre entre strict et lâche
Suffisamment stable et durable pour résister au changement HTML
Suffisamment strict pour échouer lorsque l’application échoue.
XPath ne fonctionne pas correctement dans Internet Explorer.
Les sélecteurs XPath absolus ne sont pas bons.
ID
et Class
L’ID est la stratégie de sélection la plus sûre et doit toujours être votre premier choix. Selon les normes du W3C, l’ID est sensé d’être unique dans la page (by design), il est également indépendant du type et de l’emplacement de l’élément web. Les navigateurs possèdent également des méthodes efficaces pour récupérer un objet sur une page en utilisant leurs identifiants.
Comme l’ID, l’utilisation de l’attribut Class a l’avantage d’être moins impacté par les changements structurels de la page web et donc plus stable.
Lorsque vous utilisez les deux stratégies ID et Class, vous cibler directement des éléments spécifiques au lieu de vous fier à la structure de la page.
Bien évidemment si le développeur modifier un ID ou un l’attribut Class qui est déjà utilisé dans le framework de tests UI automatisés cela aura un impact sur vos scénario de test tests. Comme je l’ai toujours dit, l’automatisation commence par la communication, discuter avec les développeurs c’est toujours important et nécessaire.
data-*
avec les sélecteurs CSS
Si vous avez la possibilité de collaborer avec les développeurs, la meilleure solution que je vous recommande très fortement est d’ajouter des attributs HTML personnalisés pour aider à identifier les éléments que vous devez sélectionner.
C’est une pratique populaire pour industrialiser les tests d’acceptation basés sur l’interface utilisateur, cette stratégie peut vraiment vous aider à avoir des tests UI plus stable et de minimiser les coûts de maintenance.
HTML5 a introduit un type d’attribut data-* formel dont nous pouvons tirer parti dans nos tests UI.
C’est très simple à mettre en place, il suffit d’ajouter un attribut personnalisé à vos composants HTML. Cet attribut sera utilisé uniquement pour localiser les éléments web pour les besoins de tests d’acceptation au niveau de l’UI.
Voici un simple exemple d’utilisation des attributs HTML personnalisés (data-testid):
username
<form name="login" id="login" action="/authenticate" method="post">
<div class="row">
<div class="large-6 small-12 columns">
<label for="username">Username</label>
<input data-testid="username" type="text" name="username" id="username" />
</div>
</div>
<div class="row">
<div class="large-6 small-12 columns">
<label for="password">Password</label>
<input
data-testid="password"
type="password"
name="password"
id="password"
/>
</div>
</div>
<button data-testid="login-submit" class="radius" type="submit">
<i class="fa fa-2x fa-sign-in"> Login</i>
</button>
</form>
Dans cet exemple (login), j’ai ajouté un attribut data-testid à tous les éléments web utilisés par les tests UI.
Ce n’était pas forcément nécessaire d’ajouter les attributs HTML personnalisés (car nous avons déjà les ID username, password pour les champs username, password et nous avons aussi la classe radius pour le bouton login, mais je l’ai fait exprès 😀
Vous vous posez peut-être la question “Pourquoi ?”
Le véritable avantage de cela est qu’il est beaucoup moins susceptible d’être modifié au cours de la durée de vie du projet.
Les autres attributs ID, name, class, etc. peuvent être changés par les développeurs et les raisons sont multiples:
Mais un attribut personnalisé nommé avec data-testid est beaucoup moins susceptible d’être modifié sans avertissement.
Nous allons maintenant compter sur nos attributs HTML personnalisés (data-testid) pour sélectionner d’une manière simple et efficace les éléments web pour nos tests UI.
Nous pouvons donc utiliser les sélecteurs suivants pour sélectionner les éléments nécessaires pour notre page login:
[data-testid="username"]
[data-testid="password"]
[data-testid="login-submit"]
Mais pourquoi utiliser les sélecteurs CSS ?
C’est simple, quand vous rencontrez une personne qui préfère parler anglais, le plus simple est de parler anglais avec lui ! C’est le même principe ici, les développeurs d’une manière générale préfèrent la simplicité du CSS.
Le choix d’une stratégie de sélecteurs web est un élément essentiel au succès de l’automatisation des tests d’acceptation UI.
Il faut garder à l’esprit qu’un bon sélecteur possède les caractéristiques:
Assurez-vous de:
L’utilisation des attributs data-* avec les sélecteurs CSS reste la meilleure solution pour minimiser les coûts de maintenance et limiter les flaky tests.
Si vous avez aimé cet article, n’hésitez pas à le partager !