PrestaFlow : tester une preprod derrière un htpasswd
Décor
Cas typique : votre préproduction PrestaShop est planquée derrière un htpasswd (Basic Auth nginx ou Apache), pour empêcher les crawlers, les curieux, ou un client qui découvrirait un module en avant-première. Vos scénarios PrestaFlow, en l’état, se prennent un 401 à la première requête — Chrome bascule sur chrome-error://net::ERR_INVALID_AUTH_CREDENTIALS, plus rien ne fonctionne.
Cette annexe montre comment passer l’auth Basic à PrestaFlow proprement, et explique pourquoi la solution qui vient d’abord à l’esprit (mettre les creds dans l’URL) est cassée.
La fausse bonne idée : https://user:pass@preprod.example.com
Le premier réflexe, c’est d’incorporer les identifiants directement dans les URLs du .env :
PRESTAFLOW_FO_URL=https://preview:supersecret@preprod.example.com/
PRESTAFLOW_BO_URL=https://preview:supersecret@preprod.example.com/admin-dev/
Ça marche pour la navigation top-level. Un goToPage('home') charge la home sans souci, Chrome décode les creds inline et pose le header pour cette requête.
Ça ne marche pas pour :
- Les requêtes XHR — Chrome n’applique pas l’auth inline sur les requêtes AJAX. Un scénario qui déclenche un ajout au panier via AJAX (parcours d’achat, chargement AJAX de la pagination du catalogue) se prend un 401 sur le XHR — la home avait chargé, mais l’action métier tombe silencieusement.
- Les redirections — pas toujours suivies avec les creds. Une redirection front → BO peut perdre l’auth en cours de route.
- Les sous-ressources — images, CSS, JS. Les captures de régression visuelle ressemblent à une page cassée parce que les assets manquent.
Résultat : le scénario semble démarrer, il tombe sur une erreur qui n’a rien à voir avec le vrai problème métier. Vous cherchez pendant une heure avant de suspecter l’auth.
La bonne mécanique : PRESTAFLOW_BASIC_*
PrestaFlow expose deux variables d’environnement dédiées :
PRESTAFLOW_FO_URL=https://preprod.example.com/
PRESTAFLOW_BO_URL=https://preprod.example.com/admin-dev/
PRESTAFLOW_BASIC_USER=preview
PRESTAFLOW_BASIC_PASS=un-mot-de-passe-partagé
Au boot de chaque suite, PrestaFlow calcule le header Authorization: Basic <base64(user:pass)> et le pose au niveau de la connexion navigateur. Chaque page créée ensuite hérite du header — navigation top-level, XHR, sous-ressources, tout.
Rien à changer côté scénarios. Vos suites tournent comme si la boutique était accessible sans htpasswd.
Le code de référence est la méthode presetBasicAuth() de TestsSuite.php (version 1.7.1).
Pourquoi ça bat l’URL avec creds inline
Le point clef est où le header est attaché. L’approche URL pose l’auth au niveau d’une requête. Chrome décode, pose l’auth pour cette requête, oublie ensuite. Toute nouvelle requête part vierge, à charge à Chrome de re-décoder l’URL — ce qu’il ne fait pas pour les XHR.
L’approche PrestaFlow pose l’auth au niveau de la connexion du navigateur, via setConnectionHttpHeaders() sur la connexion chrome-php ($browser->getConnection()). Chaque nouvelle page créée ensuite hérite de ce header. Et comme goToPage() en front ferme la page courante pour en créer une neuve, PrestaFlow réapplique aussi explicitement le header sur la page courante, avec Page::setExtraHTTPHeaders(). C’est ceinture et bretelles — mais c’est indispensable, sinon la première navigation partirait sans auth.
Résultat : une seule config .env, tous les cas couverts, y compris ceux qui cassaient avec l’URL inline.
En CI : passer par des secrets
Standard GitHub Actions. Ajoutez PRESTAFLOW_BASIC_USER et PRESTAFLOW_BASIC_PASS en secrets du dépôt (Settings → Secrets and variables → Actions).
Attention à la façon de les transmettre. La version 1.7.1 de la lib lit ces variables dans $_ENV, qui reste vide quand PHP est configuré sans le E de variables_order (le réglage du php.ini de production, courant sur les runners). Une variable passée par le bloc env: de l’étape peut donc être ignorée sans message, et elle empêche même le .env de la remplacer. Un correctif est en préparation côté lib. D’ici là, écrivez les variables dans le .env à la racine du projet, lors d’une étape préalable : la lib charge ce fichier depuis le répertoire où vous lancez prestaflow, sauf si un .env.local s’y trouve (il est alors lu à sa place).
- name: Préparer le .env PrestaFlow
env:
BASIC_USER: ${{ secrets.PRESTAFLOW_BASIC_USER }}
BASIC_PASS: ${{ secrets.PRESTAFLOW_BASIC_PASS }}
run: |
if [ -f .env.local ]; then
echo "::error::.env.local présent, le .env ne serait pas chargé"
exit 1
fi
{
echo "PRESTAFLOW_FO_URL=https://preprod.example.com/"
echo "PRESTAFLOW_BO_URL=https://preprod.example.com/admin-dev/"
printf "PRESTAFLOW_BASIC_USER='%s'\n" "$BASIC_USER"
printf "PRESTAFLOW_BASIC_PASS='%s'\n" "$BASIC_PASS"
} >> .env
- name: Run PrestaFlow (preprod protégée)
run: composer prestaflow -- run ./tests/prestaflow
Les guillemets simples protègent les caractères spéciaux du mot de passe (sauf une apostrophe, à éviter dans ce secret). Le .env ainsi produit disparaît avec le runner.
Notez qu’avec l’Action officielle, le cas Flashlight ne se pose pas — Flashlight lance sa propre boutique dans un conteneur, sans htpasswd. PRESTAFLOW_BASIC_* est utile quand vous testez une preprod hébergée ailleurs — un serveur staging, une Netlify PR preview, un environnement client.
Combiner les trois couches d’auth
PrestaFlow gère deux autres mécanismes d’auth, qui se cumulent avec Basic Auth :
- HTTP Basic (cette annexe) — l’accès au domaine
- Cookies pré-injectés (
PRESTAFLOW_COOKIES) — la session BO déjà ouverte login()dans unit— le login programmatique classique
Ordre dans lequel PrestaFlow les applique :
before()pose le header Basic Auth avant toute navigationbefore()pose ensuite les cookies avant toute navigation- Vos scénarios peuvent choisir de faire un
login()ou pas — les cookies pré-injectés ayant potentiellement rendu cette étape inutile
Les trois cohabitent sans conflit. Cas pratique : testez une preprod protégée par htpasswd, avec un cookie de session admin BO déjà valide → vos suites vont directement à l’action métier, sans fenêtre d’authentification Basic ni formulaire de login.
Cas particulier : creds différents front vs BO
Parfois le htpasswd n’est appliqué qu’au BO (le front est public), ou l’inverse. Deux configurations possibles :
- Le plus courant — le htpasswd couvre l’ensemble du domaine, mêmes creds partout,
PRESTAFLOW_BASIC_*suffit tel quel. - Cas plus rare — creds différents front / BO, ou htpasswd sur un seul des deux. Il faut alors renoncer à
PRESTAFLOW_BASIC_*(qui est global) et gérer soi-même viasetExtraHTTPHeaders()dans un override debefore(), en conditionnant selon l’URL cible. Solution qu’on ne détaille pas ici — c’est un cas de bord suffisamment rare pour justifier un peu de code custom quand il se présente.
Notes
Dans la Série PrestaFlow — article 8 sur 23