PrestaFlow au service de la documentation
Une doc qui décroche du produit
Un manuel utilisateur ou une release note contient presque toujours des captures d’écran. Le BO PrestaShop qui montre l’onglet Modules, la page de configuration d’un module tiers avec un champ à remplir, le résultat côté front pour valider ce que le lecteur doit voir.
Ces captures vieillissent vite. Une refonte du BO entre versions PS, un renommage d’onglet, un changement de thème classic, et vos captures sont obsolètes. En pratique, elles sont refaites à la main à chaque nouvelle release — quand elles sont refaites. Le plus souvent, elles ne le sont pas, et la doc décroche silencieusement du produit.
Cette annexe propose un détournement d’usage : PrestaFlow sait déjà naviguer de manière déterministe et prendre des captures. Rien n’oblige à en faire un outil de test. On peut l’utiliser pour générer les captures de la doc, avec l’avantage de pouvoir les régénérer à volonté quand le produit évolue.
Le même outil, une autre intention
Aux tests, PrestaFlow répond à « la page rend-elle comme prévu ? ». Aux docs, il répond à « mets-toi précisément dans cet état, et sauve la capture pour que je l’affiche dans mon manuel ».
La mécanique est déjà là. $page->getPage()->screenshot([...])->saveToFile($path) produit un PNG au chemin de votre choix — c’est l’API chrome-php sous-jacente, distincte de visualCheckpoint qui, elle, est orientée baseline/comparaison. Pour la doc on veut la première, pas la seconde.
Un mini-guide pour psflowdemo
Objectif : produire trois captures pour un mini-guide “comment configurer psflowdemo”.
01-module-list.png— le module dans la liste BO02-config-with-highlight.png— la page de config avec le champ titre mis en avant03-home-result.png— le résultat sur la home
Les suites de doc ne doivent pas tourner avec les tests : run tests/prestaflow parcourt récursivement tout le dossier, donc un sous-dossier Suites/Documentation/ serait ramassé à chaque run. On les range à part, dans tests/documentation/, avec leur propre namespace déclaré dans le composer.json du projet :
{
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/prestaflow/",
"Docs\\": "tests/documentation/"
}
}
}
Puis composer dump-autoload. Sans cette entrée, la classe n’est pas chargeable : PrestaFlow l’ignore sans message et le run annonce un dossier vide.
Créez tests/documentation/PsflowdemoQuickstart.php :
<?php
namespace Docs;
use PrestaFlow\Library\Tests\TestsSuite;
class PsflowdemoQuickstart extends TestsSuite
{
public function init()
{
$this->importPage('BackOffice\Login');
$this->importPage('BackOffice\Modules');
$this->importPage('Modules\Psflowdemo\Configuration', domain: 'Tests');
$this->importPage('Modules\Psflowdemo\Home', domain: 'Tests');
extract($this->pages);
@mkdir($this->outDir(), 0777, true);
$this
->describe('Doc — Quickstart psflowdemo')
->it('se connecte au BO', function () use ($backOfficeLoginPage) {
$backOfficeLoginPage->goToPage('login');
$backOfficeLoginPage->login();
})
->it('capture la liste des modules', function () use ($backOfficeModulesPage) {
$backOfficeModulesPage->goTo();
// La liste est rendue côté client : on attend la ligne du module.
$backOfficeModulesPage->waitVisible('[data-tech-name="psflowdemo"]', 10000);
$this->capture($backOfficeModulesPage, '01-module-list.png');
})
->it('capture la page config avec highlight', function () use ($modulesPsflowdemoConfigurationPage) {
$modulesPsflowdemoConfigurationPage->openConfiguration(
$modulesPsflowdemoConfigurationPage->getGlobals()['BO']['URL']
);
$modulesPsflowdemoConfigurationPage->waitVisible('input[name="PSFLOWDEMO_TITLE"]', 5000);
// Mise en avant visuelle du champ à documenter, avant la capture.
$modulesPsflowdemoConfigurationPage->getPage()->evaluate("
document.querySelector('input[name=\"PSFLOWDEMO_TITLE\"]').style.outline =
'3px solid #ff6600';
");
$this->capture($modulesPsflowdemoConfigurationPage, '02-config-with-highlight.png');
})
->it('capture le résultat sur la home', function () use ($modulesPsflowdemoHomePage) {
$modulesPsflowdemoHomePage->goToPage('home');
$modulesPsflowdemoHomePage->waitVisible('#psflowdemo-block', 5000);
$this->capture($modulesPsflowdemoHomePage, '03-home-result.png');
});
}
private function outDir(): string
{
// Le CLI est lancé depuis la racine du projet.
return getcwd() . '/docs-screenshots';
}
private function capture($page, string $filename): void
{
$tab = $page->getPage();
// Rendu 2× (voir « Résolution retina ») : reposé à chaque capture, car
// goToPage() côté front recrée l'onglet et perd ce réglage.
$tab->setDeviceMetricsOverride([
'width' => 1440,
'height' => 900,
'deviceScaleFactor' => 2,
])->await();
usleep(300_000); // laisse la page se remettre en page à la nouvelle largeur
$tab->screenshot([
'captureBeyondViewport' => true,
'clip' => $tab->getFullPageClip(),
'format' => 'png',
])->saveToFile($this->outDir() . '/' . $filename);
}
}
Lancez-la seule :
composer prestaflow -- run ./tests/documentation
Le run génère les trois PNG dans docs-screenshots/. Vous les référencez ensuite depuis votre Markdown de doc :
## Configurer psflowdemo

1. Ouvrez le menu Modules...

2. Remplissez le champ **Titre** (surligné en orange)...
Résolution retina
Pour un site de doc qui sert des assets 2× (retina, écrans haute densité), une capture standard 1440×900 pixels rendra floue une fois affichée en display CSS. On peut demander à Chrome de rendre en 2× avec setDeviceMetricsOverride() de chrome-php (la commande CDP Emulation.setDeviceMetricsOverride), comme dans la méthode capture() ci-dessus :
$page->getPage()->setDeviceMetricsOverride([
'width' => 1440,
'height' => 900,
'deviceScaleFactor' => 2,
])->await();
deviceScaleFactor: 2 produit des captures de 2880 pixels de large, nettes, qui restent affichables en 1440 pixels CSS.
Où poser ce réglage compte : il est attaché à l’onglet. Côté front, goToPage() ferme l’onglet et en ouvre un neuf à chaque appel ; un réglage posé dans before() ou en tête de init() serait perdu dès la première navigation front. D’où le choix de le reposer dans capture(), juste avant chaque capture.
Highlight visuel programmatique
Le pattern utilisé dans le second it (injecter du CSS via evaluate()) est un couteau suisse. Trois variantes utiles :
// Border colorée sur un élément à documenter
document.querySelector('...').style.outline = '3px solid #ff6600';
// Overlay avec un numéro d'étape
const el = document.querySelector('...');
const badge = document.createElement('div');
badge.textContent = '1';
badge.style.cssText = 'position:absolute;background:#ff6600;color:#fff;padding:8px 12px;border-radius:50%;font-weight:bold';
el.style.position = 'relative';
el.appendChild(badge);
// Masquer un élément (bandeau cookies qui pollue la capture)
document.querySelector('.cookie-banner').style.display = 'none';
Toujours moins fragile qu’une retouche manuelle post-capture, et rejouable identique à chaque régénération.
Combiner avec les annexes existantes
- Fixtures — vos captures montrent un produit à 9,99€ ? Fixez-le en seed pour qu’il soit toujours à 9,99€, pas au dernier prix modifié à la main.
- Cookies pré-injectés — sautez le
itde login pour aller directement à l’écran à documenter. Quelques secondes gagnées par suite. - Multi-locales — bouclez sur
PRESTAFLOW_LOCALEet faites dépendre le dossier de sortie de la locale (getcwd() . '/docs-screenshots/' . $this->getLocale()dansoutDir()) pour générerdocs-screenshots/fr/*.png+docs-screenshots/en/*.pngen une boucle. La boutique doit avoir ces langues installées (l’image Flashlight n’installe que l’anglais). Votre doc multilingue reste alignée.
Réutilisation
Deux patterns qui marchent bien en pratique :
Dossier versionné. docs-screenshots/ committé dans le repo à côté du Markdown de doc, régénéré au besoin via composer run docs:screenshots, un script Composer qui appelle PrestaFlow sur le seul dossier de doc :
{
"scripts": {
"docs:screenshots": "./vendor-dev/prestaflow/php-library/bin/prestaflow run ./tests/documentation"
}
}
Simple, tout est reproductible.
Upload CI vers un CMS. Un job GitHub Actions qui, sur push main, régénère les captures et les pousse vers votre CMS de doc (S3, Contentful, Payload, WordPress via API). La doc en ligne suit toujours le produit sans intervention humaine.
Notes
Dans la Série PrestaFlow — article 23 sur 23