Docker

Chrome headless... c'est la révolution (partie 1)

Sylvain Touret, Tech Lead @DeliaTechnologies
Sylvain Touret, Tech Lead @DeliaTechnologies
May 10, 2022
8 min

Alors non le roi Chrome n'est pas mort, mais on va bien parler de sa décapitation. Plus précisément, de l'utilisation du mode headless de Chrome pour faire des tests E2E.

Le cas de figure aujourd'hui que je voulais présenter était son utilisation lors de tests Selenium sur Docker.

Dans le cas normal, les tests s'exécutent sur votre machine en ouvrant une instance de chrome et vous pouvez ainsi voir devant vos petits yeux ébahis les instructions s'appliquer les unes à la suite des autres. Pour ceux qui écrivent les tests, cela a un côté pratique et rassurant de voir les tests se dérouler ainsi afin de voir les points bloquants, vérifier que les locators pointent au bon endroit, etc.

L'étape d'après est d'inclure ces tests dans vos pipelines devops et là souvent, vous ne serez plus dans le contexte de votre PC vous allez devoir reconfigurer chrome dans son ensemble pour être capable de faire tourner votre pipeline correctement.

Dans mon cas de figure, nous utilisons gitlab-ci pour la partie devops avec un runner sur Kubernetes. Qui dit Kubernetes, dit aussi que nous allons recourir à des dockers pour faire tourner les tests.

Oui mais voilà... dans docker, il n'y a pas d'écran...

https://media.giphy.com/media/cfQhyCeFxuUj6/giphy.gif

J'ai donc passé un petit moment à trifouiller dans les configurations pour trouver celle qui me permettait de lancer mes tests sous docker et j'espère que cela évite à d'autres de le faire.

Réalisation

Ce que l'on va construire ensemble sera constitué:

Docker

Partons d'une image docker simple comme debian:buster-slim.

On peut rendre paramétrable les versions que l'on souhaite pour Chrome et chromedriver.

On a besoin de quelques outils comme pip, wget et unzip pour faire les installations.

En peut passer à l'installation de Chrome

Et enfin de Chromedriver

Et c'est tout bon, notre image est prête. On peut la compiler en lançant

Et on peut passer à la suite s'il n'y pas d'erreur.

Librarie RobotFramework

Pour configurer Chrome lors de nos tests on va se fabriquer une petite librairie python que l'on va appeler ChromeHeadless.py. Elle va nous servir à paramétrer Chrome avec toutes les fonctionnalités qu'ils nous faut pour nos tests, et il y en a pas mal.

Commençons simplement par configurer le mode headless (Qui permet de tourner sans écran sous docker notamment). J'envisage par la suite d'agrémenter cette librairie avec d'autre cas de figure comme la configuration du répertoire de téléchargement ou bien encore l'activation de la géolocalisation qui peut être requises pour certain tests.

Voilà assez brutalement l'ossature de la librairie écrite en python.

Bon oui, ok, balancer du code comme çà c'est sur ca requiert quelques remarques, alors les voilà :

1. Lorsque je travaille avec robotframework, j'ai pour habitude de déclarer explicitement la library et les keywordsen utilisant les décorateurs fournis. Je trouve cela simplement plus propre et explicite à la lecture du code que de se baser sur les mécanismes de découvertes automatiques.

Cela me permet aussi de distinguer le nom que je souhaite donner à la fonction et le nom que je souhaite donner au keyword. Personnellement, je développe toujours en anglais mais pour mon client, peut être qu'il souhaite avoir ses keywords en français.

Pour la déclaration de ma librairie, j'ai également définit l'option scope à SUITE car je souhaite que l'instance de ma librairie soit commune à toute ma suite de tests.

2. La fonction qui fait le travail sera donc chrome_config

Les options qui nous intéresse pour le headless sont :

A la fin de la méthode on utilise

Car c'est ce que nous allons utiliser dans notre tests pour la configuration du webdriver Selenium

Test Robotframework

C'est la partie la plus facile, tout le travail est fait en amont et nous pouvons directement appliquer tout cela en une fois.

On va écrire un petit test en robotframework que l'on va appeler simple.robot.

Settings

Tout d'abord, on va faire les imports en définissant les Settings

On peut remarquer que je désactive tout d'abord le run_on_failure de Selenium. Par défaut, Selenium prend une capture d'écran en cas de problème. Ceci ne nous intéresse pas vraiment dans le cas d'une pipeline car cela ne représente qu'une capture d'écran sur les tests qui ont échoués. Les logs d'exécution et les logs générés en html par robotframework sont plus complets et pertinents qu'une image.

Ensuite on peut voir l'import de notre librairie (situé dans le même répertoire) en lui définissant le paramètre headless.

Keyword

Techniquement c'est ici que cela va se passer. On va créer un keyword, qui va permettre de configurer la fonction Selenium Open Browser et lui passer nos paramètres.

Grosso modo, c'est un keyword qui prend en argument l'url que l'on souhaite atteindre.

On appelle ensuite nos options grâce à notre librairie et le keyword get chrome options et on stocke ca dans une variable local options. Et c'est en appelant le keyword Selenium Open Browser que l'on lui passe l'url, que l'on souhaite utiliser chrome et nos options.

La dernière étape est de bien préciser la taille de la fenêtre, ce qui est important en headless car on risque de faire planter nos tests s'il ne trouve pas les locators correctement à l'écran. Qu'on a pas... certes.

Testcase

Et enfin, on peut faire un simple test qui va ouvrir une url, au hasard la page web de Delia.

Basique. Simple.

Assemblage

Voici notre arborescence de travail

Pour le Dockerfile, une petite mise à jour s'impose pour rajouter l'exécution du test.

Et voici le lien Github pour les fichiers au complet

Crash Test

On va déjà compiler notre docker:

Et maintenant on l'exécute, on obtient:

https://media.giphy.com/media/xT0GqssRweIhlz209i/giphy.gif

Conclusion

Voilà comment j'ai construit un peu mon environnement de test pour être capable de faire tourner mes tests sous docker.

La suite? Et bien une fois que les tests basiques passent (comme celui montré plus haut), on peut passer à des cas un peu plus réaliste. Et là encore des surprises nous attendent.

Mais ca serait pour une prochaine fois...

Alors non le roi Chrome n'est pas mort, mais on va bien parler de sa décapitation. Plus précisément, de l'utilisation du mode headless de Chrome pour faire des tests E2E.

Le cas de figure aujourd'hui que je voulais présenter était son utilisation lors de tests Selenium sur Docker.

Dans le cas normal, les tests s'exécutent sur votre machine en ouvrant une instance de chrome et vous pouvez ainsi voir devant vos petits yeux ébahis les instructions s'appliquer les unes à la suite des autres. Pour ceux qui écrivent les tests, cela a un côté pratique et rassurant de voir les tests se dérouler ainsi afin de voir les points bloquants, vérifier que les locators pointent au bon endroit, etc.

L'étape d'après est d'inclure ces tests dans vos pipelines devops et là souvent, vous ne serez plus dans le contexte de votre PC vous allez devoir reconfigurer chrome dans son ensemble pour être capable de faire tourner votre pipeline correctement.

Dans mon cas de figure, nous utilisons gitlab-ci pour la partie devops avec un runner sur Kubernetes. Qui dit Kubernetes, dit aussi que nous allons recourir à des dockers pour faire tourner les tests.

Oui mais voilà... dans docker, il n'y a pas d'écran...

https://media.giphy.com/media/cfQhyCeFxuUj6/giphy.gif

J'ai donc passé un petit moment à trifouiller dans les configurations pour trouver celle qui me permettait de lancer mes tests sous docker et j'espère que cela évite à d'autres de le faire.

Réalisation

Ce que l'on va construire ensemble sera constitué:

Docker

Partons d'une image docker simple comme debian:buster-slim.

On peut rendre paramétrable les versions que l'on souhaite pour Chrome et chromedriver.

On a besoin de quelques outils comme pip, wget et unzip pour faire les installations.

En peut passer à l'installation de Chrome

Et enfin de Chromedriver

Et c'est tout bon, notre image est prête. On peut la compiler en lançant

Et on peut passer à la suite s'il n'y pas d'erreur.

Librarie RobotFramework

Pour configurer Chrome lors de nos tests on va se fabriquer une petite librairie python que l'on va appeler ChromeHeadless.py. Elle va nous servir à paramétrer Chrome avec toutes les fonctionnalités qu'ils nous faut pour nos tests, et il y en a pas mal.

Commençons simplement par configurer le mode headless (Qui permet de tourner sans écran sous docker notamment). J'envisage par la suite d'agrémenter cette librairie avec d'autre cas de figure comme la configuration du répertoire de téléchargement ou bien encore l'activation de la géolocalisation qui peut être requises pour certain tests.

Voilà assez brutalement l'ossature de la librairie écrite en python.

Bon oui, ok, balancer du code comme çà c'est sur ca requiert quelques remarques, alors les voilà :

1. Lorsque je travaille avec robotframework, j'ai pour habitude de déclarer explicitement la library et les keywordsen utilisant les décorateurs fournis. Je trouve cela simplement plus propre et explicite à la lecture du code que de se baser sur les mécanismes de découvertes automatiques.

Cela me permet aussi de distinguer le nom que je souhaite donner à la fonction et le nom que je souhaite donner au keyword. Personnellement, je développe toujours en anglais mais pour mon client, peut être qu'il souhaite avoir ses keywords en français.

Pour la déclaration de ma librairie, j'ai également définit l'option scope à SUITE car je souhaite que l'instance de ma librairie soit commune à toute ma suite de tests.

2. La fonction qui fait le travail sera donc chrome_config

Les options qui nous intéresse pour le headless sont :

A la fin de la méthode on utilise

Car c'est ce que nous allons utiliser dans notre tests pour la configuration du webdriver Selenium

Test Robotframework

C'est la partie la plus facile, tout le travail est fait en amont et nous pouvons directement appliquer tout cela en une fois.

On va écrire un petit test en robotframework que l'on va appeler simple.robot.

Settings

Tout d'abord, on va faire les imports en définissant les Settings

On peut remarquer que je désactive tout d'abord le run_on_failure de Selenium. Par défaut, Selenium prend une capture d'écran en cas de problème. Ceci ne nous intéresse pas vraiment dans le cas d'une pipeline car cela ne représente qu'une capture d'écran sur les tests qui ont échoués. Les logs d'exécution et les logs générés en html par robotframework sont plus complets et pertinents qu'une image.

Ensuite on peut voir l'import de notre librairie (situé dans le même répertoire) en lui définissant le paramètre headless.

Keyword

Techniquement c'est ici que cela va se passer. On va créer un keyword, qui va permettre de configurer la fonction Selenium Open Browser et lui passer nos paramètres.

Grosso modo, c'est un keyword qui prend en argument l'url que l'on souhaite atteindre.

On appelle ensuite nos options grâce à notre librairie et le keyword get chrome options et on stocke ca dans une variable local options. Et c'est en appelant le keyword Selenium Open Browser que l'on lui passe l'url, que l'on souhaite utiliser chrome et nos options.

La dernière étape est de bien préciser la taille de la fenêtre, ce qui est important en headless car on risque de faire planter nos tests s'il ne trouve pas les locators correctement à l'écran. Qu'on a pas... certes.

Testcase

Et enfin, on peut faire un simple test qui va ouvrir une url, au hasard la page web de Delia.

Basique. Simple.

Assemblage

Voici notre arborescence de travail

Pour le Dockerfile, une petite mise à jour s'impose pour rajouter l'exécution du test.

Et voici le lien Github pour les fichiers au complet

Crash Test

On va déjà compiler notre docker:

Et maintenant on l'exécute, on obtient:

https://media.giphy.com/media/xT0GqssRweIhlz209i/giphy.gif

Conclusion

Voilà comment j'ai construit un peu mon environnement de test pour être capable de faire tourner mes tests sous docker.

La suite? Et bien une fois que les tests basiques passent (comme celui montré plus haut), on peut passer à des cas un peu plus réaliste. Et là encore des surprises nous attendent.

Mais ca serait pour une prochaine fois...

D'autres articles pour vous

Tous nos articles →