GitHub Actions


#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.2 or newer. Earlier versions read the runtime configuration only from $_ENV, which is not populated from the process environment on most CI setups; 1.5.2 introduced the Env helper that also reads getenv(), so the environment variables exported by the action (PRESTAFLOW_FO_URL, PRESTAFLOW_PS_VERSION, PRESTAFLOW_SUITES) are picked up transparently.
  • suites input — needs prestaflow/php-library ^1.8.0. Earlier versions never read PRESTAFLOW_SUITES and run every suite.
  • PHP 8.2 or newer on the runner.
  • Docker, only when flashlight: true — the runner must be ubuntu-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.

Copied!
1name: PrestaFlow
2 
3on:
4 push:
5 branches: [main]
6 pull_request:
7 branches: [main]
8 
9jobs:
10 tests:
11 runs-on: ubuntu-latest
12 steps:
13 - uses: actions/checkout@v4
14 
15 - name: Setup PHP
16 uses: shivammathur/setup-php@v2
17 with:
18 php-version: '8.2'
19 extensions: gd
20 tools: composer:v2
21 
22 - name: Install dependencies
23 run: composer install --prefer-dist --no-progress
24 
25 - name: Run PrestaFlow tests
26 uses: PrestaFlow/github-action@v2
27 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: true input.
  • Suite filtering — pick which suites to run via the suites CSV 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.json and 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, status are 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:

Copied!
1name: PrestaFlow
2 
3on:
4 pull_request:
5 
6jobs:
7 tests:
8 runs-on: ubuntu-latest
9 steps:
10 - uses: actions/checkout@v4
11 
12 - name: Setup PHP
13 uses: shivammathur/setup-php@v2
14 with:
15 php-version: '8.2'
16 extensions: gd
17 tools: composer:v2
18 
19 - name: Install dependencies
20 run: composer install --prefer-dist --no-progress
21 
22 - name: Run PrestaFlow tests
23 id: prestaflow
24 uses: PrestaFlow/github-action@v2
25 with:
26 token: ${{ secrets.PRESTAFLOW_TOKEN }}
27 projectId: '42'
28 
29 - name: Fail fast on regressions
30 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.

Copied!
1name: PrestaFlow with Flashlight
2 
3on:
4 pull_request:
5 
6jobs:
7 tests:
8 runs-on: ubuntu-latest
9 steps:
10 - uses: actions/checkout@v4
11 
12 - name: Setup PHP
13 uses: shivammathur/setup-php@v2
14 with:
15 php-version: '8.2'
16 extensions: gd
17 tools: composer:v2
18 
19 - name: Install dependencies
20 run: composer install --prefer-dist --no-progress
21 
22 - name: Run PrestaFlow tests against Flashlight
23 uses: PrestaFlow/github-action@v2
24 with:
25 token: ${{ secrets.PRESTAFLOW_TOKEN }}
26 projectId: '42'
27 flashlight: true
28 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 — the prestashop/prestashop-flashlight:<ps-version> image, bound to a free host port (starting at 8000, falling back to 8001/8002 if occupied). Waits for the MySQL sidecar's health check before starting.
  • mysql — a mariadb:lts sidecar 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):

  1. every PRESTAFLOW_* variable set on the step with env:;
  2. the values imposed by the container: PRESTAFLOW_FO_URL (e.g. http://localhost:8000/), PRESTAFLOW_BO_URL (<fo>admin-dev/) and PRESTAFLOW_PS_VERSION (the ps-version input, so the library loads the matching page namespace);
  3. your own dotenv file, copied as is: .env.local if it exists, otherwise .env;
  4. the Flashlight back-office credentials, PRESTAFLOW_BO_EMAIL=admin@prestashop.com and PRESTAFLOW_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.

Copied!
1- uses: PrestaFlow/github-action@v2
2 env:
3 PRESTAFLOW_LOCALE: fr
4 with:
5 token: ${{ secrets.PRESTAFLOW_TOKEN }}
6 flashlight: true
7 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 the name from composer.json after stripping the vendor prefix).
  • type: prestashop-theme — mounted under /var/www/html/themes/<theme-name>.
  • Missing composer.json, missing type, 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 the develop-prestashop reference example shipped with Flashlight.
  • modules / themes — force the corresponding subdirectory even when composer.json says otherwise. Handy for repositories where the type field is missing or incorrect and you would rather set it once in the workflow than fix the manifest.
Copied!
1- name: Run PrestaFlow tests against a custom PrestaShop
2 uses: PrestaFlow/github-action@v2
3 with:
4 token: ${{ secrets.PRESTAFLOW_TOKEN }}
5 projectId: '42'
6 flashlight: true
7 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):

Copied!
1- name: Run PrestaFlow tests with init scripts
2 uses: PrestaFlow/github-action@v2
3 with:
4 token: ${{ secrets.PRESTAFLOW_TOKEN }}
5 projectId: '42'
6 flashlight: true
7 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.

Copied!
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@v4
11 
12 - name: Setup PHP
13 uses: shivammathur/setup-php@v2
14 with:
15 php-version: '8.2'
16 extensions: gd
17 tools: composer:v2
18 
19 - name: Install dependencies
20 run: composer install --prefer-dist --no-progress
21 
22 - name: Run selected suites
23 uses: PrestaFlow/github-action@v2
24 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:

Copied!
1name: PrestaFlow — parallel suites
2 
3on:
4 pull_request:
5 
6jobs:
7 tests:
8 runs-on: ubuntu-latest
9 strategy:
10 fail-fast: false
11 matrix:
12 suite: [BackOffice, FrontOffice, Api]
13 steps:
14 - uses: actions/checkout@v4
15 
16 - name: Setup PHP
17 uses: shivammathur/setup-php@v2
18 with:
19 php-version: '8.2'
20 extensions: gd
21 tools: composer:v2
22 
23 - name: Install dependencies
24 run: composer install --prefer-dist --no-progress
25 
26 - name: Run ${{ matrix.suite }}
27 uses: PrestaFlow/github-action@v2
28 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.

Example of a PrestaFlow test report comment on a pull request, showing 4 passed, 3 failed, 0 skipped tests in 3m 08s against PrestaShop 9.0.0, with the three failure descriptions and file:line locations expanded.

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:

Copied!
1name: PrestaFlow
2 
3on:
4 pull_request:
5 
6permissions:
7 contents: read
8 pull-requests: write
9 
10jobs:
11 tests:
12 runs-on: ubuntu-latest
13 steps:
14 - uses: actions/checkout@v4
15 
16 - name: Setup PHP
17 uses: shivammathur/setup-php@v2
18 with:
19 php-version: '8.2'
20 extensions: gd
21 tools: composer:v2
22 
23 - name: Install dependencies
24 run: composer install --prefer-dist --no-progress
25 
26 - name: Run PrestaFlow tests
27 uses: PrestaFlow/github-action@v2
28 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:

Copied!
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@v4
11 
12 - name: Setup PHP
13 uses: shivammathur/setup-php@v2
14 with:
15 php-version: '8.2'
16 extensions: gd
17 tools: composer:v2
18 
19 - name: Install dependencies
20 run: composer install --prefer-dist --no-progress
21 
22 - name: Run PrestaFlow tests
23 uses: PrestaFlow/github-action@v2
24 with:
25 token: ${{ secrets.PRESTAFLOW_TOKEN }}
26 projectId: '42'
27 
28 analyse:
29 needs: tests
30 runs-on: ubuntu-latest
31 steps:
32 - uses: actions/download-artifact@v4
33 with:
34 pattern: prestaflow-report-${{ github.run_id }}-${{ github.run_attempt }}-*
35 merge-multiple: true
36 
37 - name: Inspect results.json
38 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 when flashlight: true is combined with a runner that has no Docker daemon. Fix: use runs-on: ubuntu-latest (Docker is not available on the macos-* and windows-* runners).

  • Port 8000 already in use — Flashlight tries to bind to host port 8000 first, and automatically falls back to 8001 then 8002. 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_TOKEN is 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 target projectId.

  • PR comment not posted (403 / permission) — GitHub blocks the comment API when the workflow token lacks the right scope. Add permissions: pull-requests: write at the workflow or job level, or pass a custom github-token (a PAT or a GitHub App token) with sufficient scope through the github-token input.

  • Class "…\\Pages\\v8\\…\\Page" not found — with flashlight: true and ps-version: '9.0.0', the library still tried to load v8-namespaced pages. Root cause: the library reads its version selector from an environment variable, and until prestaflow/php-library@1.5.2 that lookup only saw $_ENV, not the process environment the action exports. Bump your dependency to ^1.5.2 and 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 no results.json the 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/html expects a different database schema than the one Flashlight restored. Check that ps-version matches 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 via flashlight-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 the prestashop-versions.json manifest but you need to build the image yourself. For shops on 1.6 or 1.7, targeting a running preprod via PRESTAFLOW_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: