GitHub Actions
On this page
#GitHub Actions
#Introduction
The PrestaFlow GitHub Action runs
your PrestaFlow test suites inside a GitHub workflow. It wraps the PHP library
(composer run prestaflow:json:file), optionally provisions a full
PrestaShop Flashlight
instance on the runner so you can test a module or a theme against a real shop
without any prior setup, uploads the results to the PrestaFlow API, publishes a
GitHub artifact with the raw report and the failure screenshots, and posts (or
updates) a summary comment on the pull request. It is a drop-in replacement for
the previous shell-based workflow and can run in almost any CI matrix.
#Requirements
- PHP library —
prestaflow/php-library^1.5.2or newer. Earlier versions read the runtime configuration only from$_ENV, which is not populated from the process environment on most CI setups;1.5.2introduced theEnvhelper that also readsgetenv(), so the environment variables exported by the action (PRESTAFLOW_FO_URL,PRESTAFLOW_PS_VERSION,PRESTAFLOW_SUITES) are picked up transparently. suitesinput — needsprestaflow/php-library^1.8.0. Earlier versions never readPRESTAFLOW_SUITESand run every suite.- PHP
8.2or newer on the runner. - Docker, only when
flashlight: true— the runner must beubuntu-latest(or another Linux runner with a working Docker daemon).
#Quick start
The minimal workflow below runs the action on every push and pull request. It covers 90% of use cases: check out the code, install PHP + Composer dependencies, then hand over to the action.
1name: PrestaFlow 2 3on: 4 push: 5 branches: [main] 6 pull_request: 7 branches: [main] 8 9jobs:10 tests:11 runs-on: ubuntu-latest12 steps:13 - uses: actions/checkout@v414 15 - name: Setup PHP16 uses: shivammathur/setup-php@v217 with:18 php-version: '8.2'19 extensions: gd20 tools: composer:v221 22 - name: Install dependencies23 run: composer install --prefer-dist --no-progress24 25 - name: Run PrestaFlow tests26 uses: PrestaFlow/github-action@v227 with:28 token: ${{ secrets.PRESTAFLOW_TOKEN }}29 projectId: '42'
Store your PrestaFlow API token as a repository secret named
PRESTAFLOW_TOKEN, replace 42 with your actual project id, and the workflow
is ready.
#Migration from v1
If you were using PrestaFlow/github-action@v1, migrating is essentially a
version bump: the two required inputs (token and projectId) still work the
same way, and the action still runs composer run prestaflow:json:file by
default. Your existing workflow should keep passing.
What v2 brings on top:
- Flashlight provisioning — spin up a real PrestaShop instance in the
runner with a single
flashlight: trueinput. - Suite filtering — pick which suites to run via the
suitesCSV input, ideal for matrix parallelization. - PR comment — an auto-updating comment summarising pass/fail counts and the first failing tests, kept in sync across pushes on the same pull request.
- GitHub artifact —
results.jsonand failure screenshots are uploaded as a workflow artifact so they can be downloaded or consumed by downstream jobs. - Richer outputs —
id,report-url,passed,failed,skipped,total,duration-ms,statusare exposed as step outputs. - TypeScript rewrite — the action is now a compiled JavaScript action, no container pull, faster cold starts.
The moving @v2 tag currently points at v2.1.0. Pin a specific patch (@v2.1.0)
if you want reproducible upgrades; use @v2 for automatic bugfix and minor
pickups.
#Inputs reference
| Input | Required | Default | Description |
|---|---|---|---|
token |
yes | — | PrestaFlow API token used to upload results. Store as a secret. |
projectId |
no | — | Numerical PrestaFlow project id to associate the run with. |
execute |
no | true |
Run composer run prestaflow:json:file before uploading. Set to false if you already produced the results file. |
suites |
no | (empty — all suites) | Comma-separated sub-folders of the suites path to run, e.g. BackOffice,FrontOffice/Checkout. Needs php-library ^1.8.0. |
flashlight |
no | false |
Start a PrestaShop Flashlight Docker instance before running the tests. |
ps-version |
no | latest |
PrestaShop version tag used when flashlight: true. |
flashlight-mount |
no | auto |
Where to mount the workspace inside the container: auto (detect from composer.json), root (custom PrestaShop, /var/www/html), modules, or themes. |
flashlight-install-module |
no | true |
When the workspace is a composer prestashop-module, install it in the container once the shop is ready (since v2.3.0). |
flashlight-init-scripts |
no | (empty — none) | Directory (absolute or relative to workspace) mounted read-only at /tmp/init-scripts; Flashlight runs its executable shebang scripts at boot. |
pr-comment |
no | true on pull_request, else false |
Post (or update) a summary comment on the pull request. |
github-token |
no | ${{ github.token }} |
Token used to post the PR comment. Provide a PAT if the default token lacks the required scope. |
upload-artifacts |
no | true |
Upload results.json and failure screenshots as a workflow artifact. |
#Outputs reference
| Output | Type | Description |
|---|---|---|
id |
string | Unique run id assigned by the PrestaFlow API. |
report-url |
string | URL to the full report on prestaflow.io. |
passed |
number | Number of tests that passed. |
failed |
number | Number of tests that failed. |
skipped |
number | Number of tests that were skipped. |
total |
number | Total number of tests executed. |
duration-ms |
number | Total run duration in milliseconds. |
status |
success | failure |
Overall status of the run. |
A downstream step can consume these outputs directly. For example, to fail the job as soon as at least one test regresses:
1name: PrestaFlow 2 3on: 4 pull_request: 5 6jobs: 7 tests: 8 runs-on: ubuntu-latest 9 steps:10 - uses: actions/checkout@v411 12 - name: Setup PHP13 uses: shivammathur/setup-php@v214 with:15 php-version: '8.2'16 extensions: gd17 tools: composer:v218 19 - name: Install dependencies20 run: composer install --prefer-dist --no-progress21 22 - name: Run PrestaFlow tests23 id: prestaflow24 uses: PrestaFlow/github-action@v225 with:26 token: ${{ secrets.PRESTAFLOW_TOKEN }}27 projectId: '42'28 29 - name: Fail fast on regressions30 if: steps.prestaflow.outputs.failed != '0'31 run: exit 1
#Guide: Flashlight
Flashlight provisions a functional PrestaShop instance inside the runner in
seconds, saving you from installing PHP, MySQL and the shop by hand. Enable it
by passing flashlight: true; the action pulls the
prestashop/prestashop-flashlight image, starts it, waits for the shop to be
reachable, and points the tests at it.
1name: PrestaFlow with Flashlight 2 3on: 4 pull_request: 5 6jobs: 7 tests: 8 runs-on: ubuntu-latest 9 steps:10 - uses: actions/checkout@v411 12 - name: Setup PHP13 uses: shivammathur/setup-php@v214 with:15 php-version: '8.2'16 extensions: gd17 tools: composer:v218 19 - name: Install dependencies20 run: composer install --prefer-dist --no-progress21 22 - name: Run PrestaFlow tests against Flashlight23 uses: PrestaFlow/github-action@v224 with:25 token: ${{ secrets.PRESTAFLOW_TOKEN }}26 projectId: '42'27 flashlight: true28 ps-version: '9.0.0'
Because Flashlight requires Docker, the workflow must run on
ubuntu-latest (or another Linux runner where Docker is available). macOS and
Windows runners do not ship with Docker and the action will fail with a clear
error.
#What the action provisions
Flashlight does not embed a database, so the action writes a fully-managed
docker-compose.yml on the fly with:
prestashop— theprestashop/prestashop-flashlight:<ps-version>image, bound to a free host port (starting at8000, falling back to8001/8002if occupied). Waits for the MySQL sidecar's health check before starting.mysql— amariadb:ltssidecar with the credentials Flashlight expects. Pulled and health-checked automatically; no user configuration needed.
Cold-boot on a clean GitHub-hosted runner takes roughly 90–150 seconds (image
pull, MySQL health check, PrestaShop first-run install). The shop counts as
ready when /admin-dev/ answers 302 or 200: that proves PrestaShop is
really serving, where a response on / only proved the web server was up. The
poll gives up after 240 seconds. On timeout the action prints
docker compose logs, tears the stack down, and fails with the URL and the
last status it got.
#How the tests are configured
When the container is ready, the action writes one .env.local for the run,
built from (highest priority first):
- every
PRESTAFLOW_*variable set on the step withenv:; - the values imposed by the container:
PRESTAFLOW_FO_URL(e.g.http://localhost:8000/),PRESTAFLOW_BO_URL(<fo>admin-dev/) andPRESTAFLOW_PS_VERSION(theps-versioninput, so the library loads the matching page namespace); - your own dotenv file, copied as is:
.env.localif it exists, otherwise.env; - the Flashlight back-office credentials,
PRESTAFLOW_BO_EMAIL=admin@prestashop.comandPRESTAFLOW_BO_PASSWD=prestashop.
If your repository already has a .env.local, it is merged and put back at the
end of the run. Otherwise the generated file is removed.
1- uses: PrestaFlow/github-action@v22 env:3 PRESTAFLOW_LOCALE: fr4 with:5 token: ${{ secrets.PRESTAFLOW_TOKEN }}6 flashlight: true7 ps-version: '8.1.7'
If your committed .env sets PRESTAFLOW_BO_EMAIL / PRESTAFLOW_BO_PASSWD for
your local shop, they win over the Flashlight defaults. Remove them from .env,
or set the Flashlight ones with env: on the step.
Before v2.3.0 the file only held the front-office URL and the PS version: your
.env was ignored and the library fell back to back-office credentials that do
not exist on Flashlight.
#Module installation
When composer.json has "type": "prestashop-module", the workspace is mounted
in modules/<name> and, once the shop is ready, the action runs
php bin/console prestashop:module install <name> in the container. You no
longer need an init-script just for that.
If an init-script already installed the module, PrestaShop upgrades it instead,
which is harmless. A failed install only emits a warning: the tests then tell
whether the module was needed. Turn it off with
flashlight-install-module: 'false'.
#Mount detection
By default (flashlight-mount: auto), the action inspects the repository's
composer.json to decide where to mount your working directory inside the
container:
type: prestashop-module— mounted under/var/www/html/modules/<module-name>(using thenamefromcomposer.jsonafter stripping the vendor prefix).type: prestashop-theme— mounted under/var/www/html/themes/<theme-name>.- Missing
composer.json, missingtype, or an unknown type — falls back to/var/www/html/modules/<repo-basename>and logs a warning so you can spot it.
The resolved mount point is printed in the workflow logs.
#Overriding the mount location
Set flashlight-mount explicitly when the automatic detection is not what you
want:
root— mounts the workspace at/var/www/html. Use this when the repository is itself a custom PrestaShop build (a fork, a full app repo, a shop-under-development). Follows thedevelop-prestashopreference example shipped with Flashlight.modules/themes— force the corresponding subdirectory even whencomposer.jsonsays otherwise. Handy for repositories where thetypefield is missing or incorrect and you would rather set it once in the workflow than fix the manifest.
1- name: Run PrestaFlow tests against a custom PrestaShop2 uses: PrestaFlow/github-action@v23 with:4 token: ${{ secrets.PRESTAFLOW_TOKEN }}5 projectId: '42'6 flashlight: true7 ps-version: '9.0.0'8 flashlight-mount: root
Compatibility notes
Mounting a custom PrestaShop at /var/www/html overrides Flashlight's baked-in
codebase, but three things still come from the Flashlight image itself:
- PHP runtime — the image ships a specific PHP version tuned for the baked-in PrestaShop (PHP 7.4 for 1.7.8, PHP 8.1 for 8.x, PHP 8.3 for 9.x). A code mount that expects a different PHP boots but risks fatals or deprecations from unmatched extensions and syntax.
- nginx configuration — rewrite rules differ across PrestaShop majors
(
admin-dev/handling, module routes, etc.). A mismatch produces "clean" 404s on paths the mounted code expects to work. - MySQL dump — Flashlight restores a dump matching its baked-in version. Your mounted code will hit the shop with the wrong schema — missing columns, wrong tables, install checks failing on boot.
Rule of thumb: set ps-version to at least the same major.minor as the
code you are mounting. 9.0.0 for a shop on 9.0.x, 8.2.6 for an 8.2.x shop,
etc. Mixing majors is not supported by Flashlight and rarely works.
Older or unusual versions (PrestaShop 1.6 / 1.7, forks with heavy
overrides): Docker Hub only publishes images for 8.x and 9.x. The
PrestaShop Flashlight repository
declares support for older majors in prestashop-versions.json, but you need
to build the image yourself from source. For heavily customised PrestaShop
1.7 shops, a workflow that targets a running preprod (via
PRESTAFLOW_FO_URL in the library's .env, no Flashlight) is often simpler
than fighting the image build.
Custom database state: even with a matching major, you may want to seed
the shop with your own SQL dump (specific data, an existing configuration).
Use flashlight-init-scripts and drop a .sh that runs mysql < your-dump.sql before nginx starts.
#Init scripts (advanced)
Flashlight runs every executable file it finds in /tmp/init-scripts at boot,
alphabetically, after the MySQL dump is restored and before nginx starts. This
is the hook to seed additional data, patch configuration, install extra
dependencies, or wire in an internal module before the tests run.
Point flashlight-init-scripts at a directory in your repository (path is
absolute, or relative to the workspace):
1- name: Run PrestaFlow tests with init scripts2 uses: PrestaFlow/github-action@v23 with:4 token: ${{ secrets.PRESTAFLOW_TOKEN }}5 projectId: '42'6 flashlight: true7 ps-version: '9.0.0'8 flashlight-init-scripts: flashlight/init-scripts
Each script must be executable (chmod +x) and start with a shebang
(#!/bin/sh, #!/usr/bin/env bash, etc.) — Flashlight silently skips files
that do not satisfy both conditions. Prefix filenames with a two-digit index
(01-seed-products.sh, 02-configure-cache.sh, …) to control the order.
The action validates the path at parse time and fails fast with a clear message if it does not exist or is not a directory.
#Guide: Filtering suites
Pass a comma-separated list of sub-folders of your suites path via suites to
run only those. Nested paths such as FrontOffice/Checkout are allowed. The
action hands the list to the library as PRESTAFLOW_SUITES, the environment
twin of the CLI's --suites option.
This needs prestaflow/php-library ^1.8.0: earlier versions ignore the
filter and run every suite. A name that matches no folder fails the run, so a
typo cannot turn into a green job that ran zero tests.
1name: PrestaFlow — BackOffice + FrontOffice only 2 3on: 4 pull_request: 5 6jobs: 7 tests: 8 runs-on: ubuntu-latest 9 steps:10 - uses: actions/checkout@v411 12 - name: Setup PHP13 uses: shivammathur/setup-php@v214 with:15 php-version: '8.2'16 extensions: gd17 tools: composer:v218 19 - name: Install dependencies20 run: composer install --prefer-dist --no-progress21 22 - name: Run selected suites23 uses: PrestaFlow/github-action@v224 with:25 token: ${{ secrets.PRESTAFLOW_TOKEN }}26 projectId: '42'27 suites: BackOffice,FrontOffice
For heavier test bases, a strategy.matrix gives you one runner per suite so
the wall-clock time is bounded by the slowest suite:
1name: PrestaFlow — parallel suites 2 3on: 4 pull_request: 5 6jobs: 7 tests: 8 runs-on: ubuntu-latest 9 strategy:10 fail-fast: false11 matrix:12 suite: [BackOffice, FrontOffice, Api]13 steps:14 - uses: actions/checkout@v415 16 - name: Setup PHP17 uses: shivammathur/setup-php@v218 with:19 php-version: '8.2'20 extensions: gd21 tools: composer:v222 23 - name: Install dependencies24 run: composer install --prefer-dist --no-progress25 26 - name: Run ${{ matrix.suite }}27 uses: PrestaFlow/github-action@v228 with:29 token: ${{ secrets.PRESTAFLOW_TOKEN }}30 projectId: '42'31 suites: ${{ matrix.suite }}
#Guide: PR comment
On pull_request events the action posts a summary comment listing the
pass/fail/skipped counts, the run duration and a link to the full report on
prestaflow.io. The comment carries a hidden marker so subsequent pushes on the
same pull request update it in place rather than appending a new one. The PR
timeline stays clean.
There is one comment per project (projectId) and, with Flashlight, per
ps-version: in a matrix over PrestaShop versions, each version keeps its own
comment. Before v2.3.0, matrix legs and even different projects overwrote one
another's comment, so only the last one to finish stayed visible. Comments
posted by earlier releases without a PS version are no longer updated by
Flashlight runs.

If the API response does not include a report URL (for example on a private PrestaFlow instance), the "View full report" link is omitted entirely rather than rendered as a broken link.
For the comment to be posted, the workflow must grant write access to pull requests:
1name: PrestaFlow 2 3on: 4 pull_request: 5 6permissions: 7 contents: read 8 pull-requests: write 9 10jobs:11 tests:12 runs-on: ubuntu-latest13 steps:14 - uses: actions/checkout@v415 16 - name: Setup PHP17 uses: shivammathur/setup-php@v218 with:19 php-version: '8.2'20 extensions: gd21 tools: composer:v222 23 - name: Install dependencies24 run: composer install --prefer-dist --no-progress25 26 - name: Run PrestaFlow tests27 uses: PrestaFlow/github-action@v228 with:29 token: ${{ secrets.PRESTAFLOW_TOKEN }}30 projectId: '42'
When at least one test fails, the comment lists up to 20 failing tests with their source location (file and line, if the report exposes it) and error message so the reviewer can triage from the PR without opening the full report. When the run has more than one suite, a per-suite table comes first. Beyond twenty failures, a "+N more" trailer points to the complete report on prestaflow.io.
To opt out (for example on a private mirror where you do not want a bot
comment), set pr-comment: false.
#Guide: GitHub artifacts
By default the action uploads a workflow artifact named
prestaflow-report-<run-id>-<attempt>-<job>, followed by -ps<version> when
Flashlight is on and by the suites when suites is set (for example
prestaflow-report-123456-1-tests-ps9.0.0-BackOffice). It contains:
results.json— the raw JSON report produced by the PHP library;screenshots/— the failure screenshots generated by the browser, when any.
Artifact names must be unique within a run, so each matrix leg gets its own. Before v2.3.0 every leg used the same name and all but the first failed to upload. Legs that still share all of these values (a matrix on the PHP version, say) fall back to a random suffix rather than losing their artifact.
The artifact makes it trivial to inspect a failing run locally, or to hand the report to another job in the same workflow. Download it by pattern, since the exact name depends on the job:
1name: PrestaFlow with downstream analysis 2 3on: 4 pull_request: 5 6jobs: 7 tests: 8 runs-on: ubuntu-latest 9 steps:10 - uses: actions/checkout@v411 12 - name: Setup PHP13 uses: shivammathur/setup-php@v214 with:15 php-version: '8.2'16 extensions: gd17 tools: composer:v218 19 - name: Install dependencies20 run: composer install --prefer-dist --no-progress21 22 - name: Run PrestaFlow tests23 uses: PrestaFlow/github-action@v224 with:25 token: ${{ secrets.PRESTAFLOW_TOKEN }}26 projectId: '42'27 28 analyse:29 needs: tests30 runs-on: ubuntu-latest31 steps:32 - uses: actions/download-artifact@v433 with:34 pattern: prestaflow-report-${{ github.run_id }}-${{ github.run_attempt }}-*35 merge-multiple: true36 37 - name: Inspect results.json38 run: jq '.suites[] | {suite, stats}' prestaflow/results.json
To skip the upload entirely, set upload-artifacts: false.
#Troubleshooting
-
Docker missing — the action fails with
flashlight: true requires Docker (use ubuntu-latest runner). This happens whenflashlight: trueis combined with a runner that has no Docker daemon. Fix: useruns-on: ubuntu-latest(Docker is not available on themacos-*andwindows-*runners). -
Port 8000 already in use — Flashlight tries to bind to host port
8000first, and automatically falls back to8001then8002. If all three are already taken (typical of self-hosted runners with multiple concurrent jobs), the action fails with a clear message. Free one of these ports or run the job on a fresh runner. -
Invalid token / 401 — the upload step reports a 401 when the PrestaFlow API rejects the token. Verify that
secrets.PRESTAFLOW_TOKENis set for the repository (Settings → Secrets and variables → Actions), that its value matches the token displayed on your PrestaFlow account, and that the token has access to the targetprojectId. -
PR comment not posted (403 / permission) — GitHub blocks the comment API when the workflow token lacks the right scope. Add
permissions: pull-requests: writeat the workflow or job level, or pass a customgithub-token(a PAT or a GitHub App token) with sufficient scope through thegithub-tokeninput. -
Class "…\\Pages\\v8\\…\\Page" not found— withflashlight: trueandps-version: '9.0.0', the library still tried to loadv8-namespaced pages. Root cause: the library reads its version selector from an environment variable, and untilprestaflow/php-library@1.5.2that lookup only saw$_ENV, not the process environment the action exports. Bump your dependency to^1.5.2and re-run. -
PR comment shows "0 tests passed in 0s" — the composer script crashed before writing
prestaflow/results.json. The action can only report what the library produced. Open the workflow step preceding the action's output to find the real error (missing class, syntax error in a test file, browser crash, etc.). When there is noresults.jsonthe action skips the API upload silently and posts the zero-state comment so the PR still reflects that something went wrong. -
Flashlight not ready after 240000ms— the shop container failed to respond within four minutes. The action captures the Flashlight logs into a collapsed group in the workflow output; expand it to see whether MySQL failed to become healthy, the PS installer crashed, or a firewall rule prevented the readiness probe from reaching the container. -
flashlight-mount: root+ SQL errors / missing tables / 500 on boot — the code you mounted at/var/www/htmlexpects a different database schema than the one Flashlight restored. Check thatps-versionmatches your mounted code at least at the major.minor level. If you are mounting a heavily customised shop that ships its own SQL dump, restore it viaflashlight-init-scripts— the dump runs after Flashlight's own restore, so it overrides it. See the compatibility notes in the Flashlight guide. -
flashlight-mount: root+flashlight: true+ no image published for your PrestaShop version — Docker Hub currently only publishes Flashlight images for PrestaShop 8.x and 9.x. Support for older majors is declared in theprestashop-versions.jsonmanifest but you need to build the image yourself. For shops on 1.6 or 1.7, targeting a running preprod viaPRESTAFLOW_FO_URL(no Flashlight, no mount) is usually the pragmatic path.
#See also
The same behavior — Flashlight boot, visual-regression round-trip, results upload, PR/MR comment — is available on the three other major CI platforms:
- GitLab CI/CD Component — the GitLab port (PrestaFlow/gitlab-component).
- Bitbucket Pipe — the Bitbucket Pipelines port (PrestaFlow/bitbucket-pipe).
- CircleCI Orb — the CircleCI port (PrestaFlow/circleci-orb).