tests Behat/Mink sous docker en Symfony3 & 4

Récemment, j’ai dû mettre en place des tests BEHAT/MINK sous docker. Je l’avais fait sur mon poste en local en faisant tourner un jar selenium et m’étais dit: « oh, ça ne va pas être bien compliqué ». Que nenni! J’ai littéralement lutté pour faire tourner le tout (sachant qu’en plus, je devais le faire tourner sur un gitlab-ci après).

J’aimerais vous épargner de longues heures de recherche. La plupart des tutoriaux sur lesquels je suis tombé étaient soit obsolètes (Symfony2), soit ne fonctionnaient pas, soit faisaient appel à des outils n’étant plus maintenus.

J’ai tenté phantomJS pour avoir un browser headless mais il n’est plus maintenu et ça n’a pas fonctionné à cause du GhostDriver.

J’ai aussi tenté l’option selenium + chromedriver + chrome en version headless mais les perfs n’étaient pas terribles.

J’ai réussi à trouver deux solutions:

  • une avec selenium et chrome en mode headless (à partir de la version 59)
  • une sans selenium en connexion directe avec chrome en mode headless

Autant vous dire que les perfs ne sont pas les mêmes. Une même page peut mettre 1,6s à s’afficher avec selenium contre 0.5s uniquement avec chrome.

Commençons avec le fichier composer.json

behatch/contexts permet de rajouter des steps supplémentaires à ceux existants.

 

D’abord, un test avec le tag @javascript

En fait, ce test ici n’a que peu de sens car je ne teste pas de javascript. Mais pour tester la solution en mode browser headless, je dois rajouter ce tag:

 

Sans plus attendre, voici les deux solutions que j’ai trouvées:

AVEC SELENIUM

Le docker-compose

Je n’ai pas mis le container de base de données dedans pour simplifier le docker-compose.

Plusieurs points à noter:

  • depends_on du container php par rapport au container chrome
  • le VIRTUAL_HOST, très important, car il va servir au reverse proxy pour enregistrer ce host
  • la propriété external_links pour permettre au container de l’image chrome de « demander » le host au reverse proxy nginx (sinon behat ignore l’host à appeler pour chaque uri)

Je vous avoue que j’ai trouvé ça tordu de devoir faire intervenir un reverse proxy pour ça mais si j’avais lié l’image chrome à l’image php (et que j’avais dit que l’url était alors php et pas galerie-local.fr), j’aurais eu un problème de référence circulaire puisque l’image php est déjà liée à l’image chrome par le « depends_on ». Pas simple, n’est-ce pas?

 

La config behat.yml en Symfony3

 

La config behat.yml en Symfony4

 

Il n’y a plus qu’à faire un docker-compose up -d, puis à lancer les tests behat:

 

SANS SELENIUM AVEC CHROME HEADLESS

La config docker-compose

Là, du coup, la config reste la même que celle que vous aviez: pas de container chrome ou hub. La seule chose est qu’il faut avoir pour le container php un extra_hosts et monter un volume supplémentaire (/dev/shm):

Sans le montage du volume /dev/shm vers /dev/shm, chrome essaiera d’écrire dans /tmp et ce dernier étant limité à 63M dans un container, il vous dira que  vous devez en avoir au moins 64 pour qu’il puisse fonctionner.

De même, l’extra_hosts est important sinon il sera impossible d’atteindre le site à partir du container (tentez de faire un curl http://votresite.local dans le container php_galerie et vous aurez une erreur).

Dans votre Dockerfile, vous devez installer chrome:

 

Le script sh de lancement dans docker

Ensuite, dans votre script docker de lancement (mon fichier s’appelle run.sh et se lance au build du container php), vous devez mettre:

 

Mise à jour du composer.json

Vous devez rajouter ce vendor: "dmore/behat-chrome-extension": "^1.3"

 

Mise à jour du fichier behat.yml

Je l’ai mis en Symfony4, mais les ajouts sont facilement transposables en Symfony3.

Les changements sont:

  • Rajout de l’extension: DMore\ChromeExtension\Behat\ServiceContainer\ChromeExtension: ~
  • Rajout d’un nouveau profil. Si vous vous demandez pourquoi j’ai mis php à la place d’une ip, c’est parce que j’ai besoin de l’ip dynamique du container php_galerie pour que chrome puisse s’exécuter (en local sans docker, ce serait 127.0.0.1)

J’ai laissé la configuration selenium pour vous montrer que l’on peut combiner les deux, mais si vous désirez la version minimaliste, ce serait:

 

Il n’y a plus qu’à faire un docker-compose up -d, puis à lancer les tests behat:


ou avec la config allégée:

 

Conclusion

J’espère vous avoir épargné de longues heures de recherche. J’ai trouvé vraiment très peu de doc sur le net et elles étaient souvent pour Symfony2. La solution avec selenium fonctionnait bien mais était un peu lente à mon goût et je voulais que mes tests s’exécutent le plus rapidement possible. La solution avec chrome headless me paraît idéale.

Avatar
Rédigé par

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.