Automatiser ses scénarios PrestaFlow en CI
Préambule
Dans l’article précédent, nous avons mis en place trois suites PrestaFlow pour le module psflowdemo — un parcours d’achat fourni, plus deux suites custom — et nous les avons lancées en local avec composer prestaflow -- run ./tests/prestaflow. La librairie y est installée dans vendor-dev/, avec un script Composer prestaflow : voir la section Installation de l’article précédent.
Fonctionnel, mais rapidement fastidieux : à chaque commit, sur chaque version de PrestaShop qu’on prétend supporter, il faudrait relancer ces scénarios à la main. C’est très exactement le même argumentaire que celui du précédent article sur PHPStan en CI, transposé au fonctionnel.
Voyons comment déléguer cette exécution à GitHub Actions — d’abord en pilotant la CLI PrestaFlow depuis un workflow (sans dépendance externe), puis en passant à l’Action officielle pour bénéficier des remontées sur la plateforme.
Le défi propre au E2E en CI
Faire tourner PHPStan en CI est facile : composer install, puis on lance l’analyse statique. Rien ne s’exécute vraiment.
Pour du E2E, il faut une boutique PrestaShop réellement démarrée, contre laquelle PrestaFlow va naviguer. C’est là que se joue tout le confort du CI.
La solution standard, à l’heure de cet article, est Flashlight : une image Docker officielle de la communauté PrestaShop qui livre une instance PS installée, prête à répondre en HTTP, sans persistance. Idéale pour les tests : on démarre, on teste, on jette.
Toute la suite de l’article repose dessus.
Niveau 1 : la CLI PrestaFlow dans un workflow
Objectif : lancer nos scénarios à chaque push, sans compte prestaflow.io, sans token. Juste le workflow, Docker, et la CLI.
Créez .github/workflows/prestaflow.yml :
name: PrestaFlow
on:
push:
pull_request:
jobs:
e2e:
name: E2E — PrestaShop 8.1.7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP 8.2
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: gd
tools: composer:v2
ini-values: variables_order=EGPCS
- name: Install dependencies
run: composer install --prefer-dist --no-progress
- name: Start MariaDB
run: |
docker network create prestashop
docker run -d --name mysql --network prestashop \
-e MARIADB_ROOT_PASSWORD=prestashop \
-e MARIADB_DATABASE=prestashop \
-e MARIADB_USER=prestashop \
-e MARIADB_PASSWORD=prestashop \
--health-cmd "healthcheck.sh --connect" --health-interval 5s \
mariadb:11
for i in $(seq 1 30); do
[ "$(docker inspect -f '{{.State.Health.Status}}' mysql)" = "healthy" ] && exit 0
sleep 2
done
echo "MariaDB never became healthy" && exit 1
- name: Start PrestaShop (Flashlight)
run: |
docker run -d --name ps --network prestashop \
-p 80:80 \
-e PS_DOMAIN=localhost \
-e MYSQL_HOST=mysql \
-v "$PWD":/var/www/html/modules/psflowdemo \
-v "$PWD/tests/flashlight-init":/tmp/init-scripts:ro \
prestashop/prestashop-flashlight:8.1.7
- name: Wait for PrestaShop to be ready
run: |
for i in $(seq 1 60); do
code=$(curl -s -o /dev/null -w '%{http_code}' http://localhost/admin-dev/ || true)
if [ "$code" = "302" ] || [ "$code" = "200" ]; then
echo "Le back office répond $code"
exit 0
fi
sleep 2
done
docker logs ps
echo "Timeout" && exit 1
- name: Run PrestaFlow scenarios
env:
PRESTAFLOW_PS_VERSION: 8.1.7
PRESTAFLOW_LOCALE: en
PRESTAFLOW_FO_URL: http://localhost/
PRESTAFLOW_BO_URL: http://localhost/admin-dev/
PRESTAFLOW_BO_EMAIL: admin@prestashop.com
PRESTAFLOW_BO_PASSWD: prestashop
PRESTAFLOW_HEADLESS: 'true'
run: composer prestaflow -- run ./tests/prestaflow
- name: Upload PrestaFlow screenshots on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: prestaflow-output
path: prestaflow/
if-no-files-found: ignore
Ce workflow fait, dans l’ordre :
- Cloner le module (
actions/checkout). - Installer PHP et Composer, puis les dépendances du module (
shivammathur/setup-php,composer install, qui les range dansvendor-dev/). Le réglagevariables_order=EGPCSn’est pas décoratif : la librairie v1.7.1 lit sa configuration dans$_ENV, que le PHP installé par setup-php ne remplit pas par défaut. Sans lui, les variables du blocenv:n’atteignent pas PrestaFlow, qui retombe sur ses valeurs par défaut (https://localhost/, identifiants de la boutique de démo). - Démarrer une base MariaDB. Flashlight embarque nginx et php-fpm, mais pas MySQL : sans base à côté, le conteneur boucle indéfiniment sur « Cannot connect to MySQL, retrying » et la boutique ne répond jamais. Attendre le healthcheck de la base fait échouer le job tout de suite, avec un message clair, si elle ne démarre pas.
- Démarrer Flashlight sur le même réseau Docker, avec l’image PS 8.1.7, en y montant le module (le dépôt cloné) dans
modules/psflowdemo.PS_DOMAINest obligatoire (sans lui, le conteneur s’arrête aussitôt avec le code 2 : « Missing PS_DOMAIN ») et doit correspondre à l’URL vue depuis le runner, port compris : icilocalhost, puisque-p 80:80expose le port 80. - Installer le module : monter le dossier ne suffit pas, PrestaShop doit encore l’installer. C’est le rôle de l’init-script monté dans
/tmp/init-scripts, décrit juste après. - Attendre que PrestaShop réponde en interrogeant
/admin-dev/jusqu’à obtenir un 302 (redirection vers la page de connexion). Un 200 sur/ne suffit pas : il prouve seulement que quelque chose écoute sur le port, et le front répond avant la fin des post-scripts éventuels. - Lancer PrestaFlow via le script Composer, avec les variables d’environnement pointant vers
http://localhost/. La locale esten: l’image Flashlight n’installe que l’anglais. Le./devanttests/prestaflowest indispensable sous Linux : la CLI v1.7.1 met en majuscule la première lettre du chemin, etTests/prestaflown’existe pas. - Uploader le dossier
prestaflow/en artifact si le job échoue. Il n’y a pas de rapport HTML : on y trouve les captures pleine page prises au moment où une assertion a échoué (prestaflow/screens/errors/), à inspecter depuis l’interface GitHub sans avoir à rejouer. Ajoutez--junità la commande si vous voulez aussi unprestaflow/junit.xml.
L’init-script, à versionner dans le dépôt du module sous tests/flashlight-init/10-install-module.sh (et à rendre exécutable avec chmod +x, sinon Flashlight le saute) :
#!/bin/sh
set -eu
php /var/www/html/bin/console prestashop:module install psflowdemo
Flashlight exécute les init-scripts au premier démarrage, une fois la base restaurée et avant de servir la boutique : quand le back office répond, le module est installé.
Pour aller plus loin sur l’image elle-même (choix du tag, post-scripts, matrice de versions en docker compose, pièges), voir l’annexe PrestaShop Flashlight : des boutiques jetables pour tester.
C’est déjà utile en l’état : chaque push est testé, les échecs d’assertion sont visibles, les captures sont téléchargeables. Le tout sans avoir créé un seul compte externe.
Niveau 2 : l’Action officielle PrestaFlow/github-action
Le niveau 1 marche, mais il laisse plusieurs choses à désirer :
- Aucune synthèse dans la PR. Il faut aller lire les logs pour savoir ce qui a échoué.
- Pas d’historique. Chaque run repart de zéro, sans comparaison possible avec les précédents.
- Pas de suivi des régressions visuelles. Les références d’images ne sont pas partagées d’un run à l’autre : on ne détecte pas qu’un template s’est cassé si aucun sélecteur ne bouge.
- Le workflow YAML gonfle dès qu’on ajoute des versions de PS.
L’Action officielle PrestaFlow résout tout cela, en s’appuyant sur la plateforme prestaflow.io.
Prérequis
Trois choses à faire, une seule fois :
- Créer un compte via la waitlist — dès validation, la plateforme vous fournit un projectId de la forme
pk_01ABCDEF...pour chaque projet créé. - Générer un token d’API depuis les réglages du projet.
- Ajouter le token en secret GitHub du dépôt, sous le nom
PRESTAFLOW_TOKEN(Settings → Secrets and variables → Actions).
Déclarer le script Composer
L’Action attend un script Composer nommé prestaflow:json:file, qui lance PrestaFlow avec le format de sortie qu’elle sait consommer (prestaflow/results.json). Ajoutez-le à côté du script prestaflow déclaré dans l’article précédent :
"scripts": {
"prestaflow": "./vendor-dev/prestaflow/php-library/bin/prestaflow",
"prestaflow:json:file": "@prestaflow run --output=JSON ./tests --file"
}
Le workflow
Créez (ou remplacez) .github/workflows/prestaflow.yml :
name: PrestaFlow
on:
push:
pull_request:
permissions:
contents: read
pull-requests: write
jobs:
e2e:
name: E2E — PrestaShop 8.1.7
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP 8.2
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: gd
tools: composer:v2
ini-values: variables_order=EGPCS
- name: Install dependencies
run: composer install --prefer-dist --no-progress
- name: Run PrestaFlow
id: prestaflow
uses: PrestaFlow/github-action@v2
env:
PRESTAFLOW_LOCALE: en
PRESTAFLOW_BO_EMAIL: admin@prestashop.com
PRESTAFLOW_BO_PASSWD: prestashop
with:
token: ${{ secrets.PRESTAFLOW_TOKEN }}
projectId: 'pk_01ABCDEFGHIJKLMNOP'
flashlight: true
ps-version: '8.1.7'
flashlight-init-scripts: tests/flashlight-init
Nettement plus court que le niveau 1. Ce que l’Action fait à votre place :
- Démarre Flashlight et sa base MariaDB avec la version demandée via l’input
ps-version, et monte le dépôt dansmodules/: letypeprestashop-moduleet lenameprestaflow/psflowdemode votrecomposer.jsondonnentmodules/psflowdemo. Plus dedocker runmanuel, plus de bouclecurl. Le module est monté, pas installé : l’inputflashlight-init-scriptsréutilise l’init-script du niveau 1 pour l’installer. - Transmet l’URL de la boutique et la version : l’Action ne fournit que
PRESTAFLOW_FO_URLetPRESTAFLOW_PS_VERSION(elle les écrit aussi dans un.env.local). L’URL du BO s’en déduit (/admin-dev/est le dossier par défaut de la lib, et celui de Flashlight). Les identifiants BO et la locale, eux, ne sont pas injectés : c’est le rôle du blocenv:de l’étape, qui n’atteint la librairie qu’avecvariables_order=EGPCScôté setup-php, comme au niveau 1. - Lance le script Composer
prestaflow:json:filepuis pousse le résultat à la plateforme. - Poste un commentaire de synthèse sur la PR si le workflow tourne sur un
pull_request(d’où le blocpermissions: pull-requests: write). - Téléverse
prestaflow/results.jsonet les captures d’échec en artifact (inputupload-artifacts, actif par défaut). - Synchronise les régressions visuelles avec la plateforme, si vos suites posent des points de contrôle visuels (
visualCheckpoint()) : les baselines sont téléchargées avant l’exécution, les nouvelles captures et les diffs sont envoyés à la fin. Un template modifié qui casse le rendu apparaît alors dans le rapport visuel de la plateforme, même si aucunitne tombe.
Consommer les outputs
L’Action expose des outputs consommables par les étapes suivantes :
- name: Show summary
if: always()
run: |
echo "Status : ${{ steps.prestaflow.outputs.status }}"
echo "Passed : ${{ steps.prestaflow.outputs.passed }}"
echo "Failed : ${{ steps.prestaflow.outputs.failed }}"
echo "Report : ${{ steps.prestaflow.outputs.report-url }}"
Utile pour brancher une notification Slack, un statut custom, ou un gate sur status == 'success' avant de publier votre module.
Matrix multi-versions
C’est ici que le passage à l’Action prend tout son sens. Pour tester votre module contre 1.7.8.11, 8.1.7 et 9.0.0 en parallèle :
jobs:
e2e:
name: E2E — PrestaShop ${{ matrix.ps-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ps-version: ['1.7.8.11', '8.1.7', '9.0.0']
steps:
- uses: actions/checkout@v4
# ... setup PHP (avec variables_order=EGPCS), composer install ...
- uses: PrestaFlow/github-action@v2
env:
PRESTAFLOW_LOCALE: en
PRESTAFLOW_BO_EMAIL: admin@prestashop.com
PRESTAFLOW_BO_PASSWD: prestashop
with:
token: ${{ secrets.PRESTAFLOW_TOKEN }}
projectId: 'pk_01ABCDEFGHIJKLMNOP'
flashlight: true
ps-version: ${{ matrix.ps-version }}
flashlight-init-scripts: tests/flashlight-init
Côté plateforme, chaque job de la matrice envoie son propre run. Sur la PR, en revanche, il n’y a qu’un seul commentaire PrestaFlow : chaque job le retrouve et le réécrit avec son propre bilan. Seul le bilan du dernier job terminé reste visible (le commentaire indique sa version PS). Pour comparer les trois versions, passez par la plateforme ou par le statut de chaque job dans l’onglet Checks : c’est là que vous voyez que votre nouveau template casse spécifiquement en 1.7 sans toucher au reste.
C’est exactement le pattern que nous avions installé pour PHPStan en 2024, transposé au fonctionnel.
Notes
Le niveau 1 reste une option légitime pour un projet expérimental ou personnel, ou pour un module dont vous ne souhaitez pas remonter les résultats sur la plateforme. Il fait ce qu’il promet : rougir le CI quand un scénario casse, avec la réserve du code de sortie vue plus haut.
Dès que le module vit en production, que plusieurs personnes contribuent, ou que vous supportez plus d’une version de PrestaShop, le niveau 2 s’amortit vite. Le commentaire PR évite d’aller lire les logs pour savoir si ça passe, l’historique remplace la mémoire humaine, et les régressions visuelles rattrapent la classe de bugs “j’ai touché un CSS et je ne l’ai pas vu”.
Dans la Série PrestaFlow — article 2 sur 23