Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Reusable Playwright e2e workflow, kept separate from `continuous-integration.yml`
# because it needs a dedicated e2e_testing database/environment and browser
# install, which the CI workflow does not provide.
name: "End-to-end tests"

on:
workflow_call:
inputs:
plugin-key:
required: true
type: string
glpi-version:
required: true
type: string
php-version:
required: true
type: string
db-image:
required: true
type: string

jobs:
e2e:
name: "Playwright"
runs-on: "ubuntu-latest"
container:
image: "ghcr.io/glpi-project/githubactions-glpi-apache:php-${{ inputs.php-version }}-glpi-${{ inputs.glpi-version }}"
# `--user github-actions-runner` is mandatory to prevent rights issues on mounted volume during checkout operation
options: >-
--volume ${{ github.workspace }}:/var/www/glpi/plugins:rw
--user github-actions-runner
services:
db:
image: "ghcr.io/glpi-project/githubactions-${{ inputs.db-image }}"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
MYSQL_DATABASE: "glpi_e2e"
options: >-
--shm-size=1g
defaults:
run:
# By default, execute commands using the `www-data` user to prevent rights issues on GLPI generated files.
shell: "sudo --set-home --user=www-data --preserve-env bash --noprofile --norc -eo pipefail {0}"
working-directory: "/var/www/glpi"
env:
CACHE_DIR: "/home/www-data/.cache/e2e-tests-workflow"
steps:
- name: "Validate plugin-key"
shell: "bash"
run: |
[[ "${{ inputs.plugin-key }}" =~ ^[a-z][a-z0-9_-]*$ ]] || { echo "Invalid plugin-key"; exit 1; }

- name: "Checkout"
uses: "actions/checkout@v7"
with:
path: "${{ inputs.plugin-key }}"

Comment thread
Rom1-B marked this conversation as resolved.
- name: "Configure cache directories"
# sudo needs the `github-actions-runner` user (only one with passwordless sudo).
# working-directory is the plugin dir so `composer config` writes to its local
# composer.json, readable regardless of which user runs later composer commands.
shell: "bash"
working-directory: "/var/www/glpi/plugins/${{ inputs.plugin-key }}"
run: |
sudo mkdir --parents "${{ env.CACHE_DIR }}/composer"
sudo chown --recursive github-actions-runner "${{ env.CACHE_DIR }}"
composer config cache-dir "${{ env.CACHE_DIR }}/composer"

- name: "Restore cache"
uses: "actions/cache@v6"
with:
path: |
${{ env.CACHE_DIR }}
key: "${{ inputs.plugin-key }}-dependencies-${{ inputs.php-version }}-${{ github.job }}-${{ hashFiles(format('{0}/composer.lock', inputs.plugin-key)) }}"
restore-keys: |
${{ inputs.plugin-key }}-dependencies-${{ inputs.php-version }}-${{ github.job }}-
${{ inputs.plugin-key }}-dependencies-${{ inputs.php-version }}-
${{ inputs.plugin-key }}-dependencies-

- name: "Fix directories ACL"
# Runs after cache restore so cache-extracted files (owned by github-actions-runner) get the ACL too.
shell: "bash"
run: |
sudo setfacl --recursive --modify u:www-data:rwx "${{ env.CACHE_DIR }}"
sudo setfacl --recursive --modify u:www-data:rwx "/var/www/glpi/plugins/${{ inputs.plugin-key }}"

- name: "Mark plugin directory as safe for git"
run: |
git config --global --add safe.directory "/var/www/glpi/plugins/${{ inputs.plugin-key }}"

- name: "Install composer dependencies"
if: ${{ hashFiles(format('{0}/composer.json', inputs.plugin-key)) != '' }}
working-directory: "/var/www/glpi/plugins/${{ inputs.plugin-key }}"
run: |
composer install --ansi --no-interaction --no-progress --prefer-dist

- name: "Install e2e database"
# Port 8090 is the vhost bound to GLPI_ENVIRONMENT_TYPE=e2e_testing in
# this image; port 80 serves a different (unconfigured) environment.
run: |
bin/console database:install --ansi --no-interaction --force --reconfigure --no-telemetry \
--db-host=db --db-name=glpi_e2e --db-user=root --db-password="" \
--env=e2e_testing
bin/console config:set url_base "http://localhost:8090" --env=e2e_testing
bin/console config:set url_base_api "http://localhost:8090/apirest.php" --env=e2e_testing

- name: "Install and activate plugin"
run: |
bin/console plugin:install --ansi --no-interaction --username=glpi "${{ inputs.plugin-key }}" --env=e2e_testing
bin/console plugin:activate --ansi --no-interaction "${{ inputs.plugin-key }}" --env=e2e_testing

- name: "Run apache"
shell: "bash"
run: |
sudo service apache2 start

- name: "Install Playwright browser"
# Not cached: Playwright recommends against it (restore time ≈ download time),
# and OS deps below are reinstalled on every run regardless.
run: |
npx playwright install chromium

- name: "Install Playwright system dependencies"
# Needs passwordless sudo to install system packages as root.
shell: "bash"
run: |
npx playwright install-deps chromium

- name: "Playwright"
env:
E2E_BASE_URL: "http://localhost:8090"
run: |
npx playwright test --project="plugin:${{ inputs.plugin-key }}" --reporter=html

- name: "Upload Playwright report"
if: ${{ !cancelled() }}
uses: "actions/upload-artifact@v7"
with:
name: "playwright-report-${{ inputs.glpi-version }}-${{ inputs.php-version }}"
path: "/var/www/glpi/playwright-report"
retention-days: 7
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,48 @@ On pull requests, the workflow checks that the `CHANGELOG` file has been updated

On pull requests that modify `plugin.xml` or `<plugin-key>.xml`, the workflow also validates that all URLs declared in the file are reachable. URLs inside `<download_url>` tags that are newly introduced by the PR only produce a warning (the release archive may not be published yet), while all other invalid URLs fail the check.

## End-to-end tests workflow

This workflow runs the plugin's Playwright specs (`tests/e2e/specs`) against a dedicated `e2e_testing` GLPI environment.
It is kept separate from the `continuous-integration.yml` workflow because it needs its own database and a browser install, which the CI workflow does not provide.

```yaml
name: "End-to-end tests"

on:
push:
branches:
- "main"
tags:
- "*"
pull_request:
workflow_dispatch:

concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true

jobs:
e2e:
uses: "glpi-project/plugin-ci-workflows/.github/workflows/e2e-tests.yml@v1"
with:
# The plugin key (system name).
plugin-key: "myplugin"

# The version of GLPI on which to run the tests.
glpi-version: "12.0.x"

# The version of PHP on which to run the tests.
php-version: "8.3"

# The database docker image on which to run the tests.
db-image: "mariadb:10.6"
```

See the [Continuous integration workflow](#continuous-integration-workflow) section above for the available `glpi-version`/`php-version`/`db-image` combinations.

The plugin specs are auto-discovered by GLPI's own `playwright.config.ts` as the `plugin:<plugin-key>` project, so no plugin-side Playwright configuration is required beyond the `tests/e2e/specs` directory.

## Code coverage

Code coverage is automatically enabled when a `.glpi-coverage.json` configuration file is present at the root of the plugin directory.
Expand Down Expand Up @@ -178,6 +220,19 @@ jobs:
php-version: "${{ matrix.php-version }}"
db-image: "${{ matrix.db-image }}"

e2e:
name: "Playwright - GLPI ${{ matrix.glpi-version }} - php:${{ matrix.php-version }} - ${{ matrix.db-image }}"
needs: "generate-ci-matrix"
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.generate-ci-matrix.outputs.matrix) }}
uses: "glpi-project/plugin-ci-workflows/.github/workflows/e2e-tests.yml@v1"
with:
plugin-key: "myplugin"
glpi-version: "${{ matrix.glpi-version }}"
php-version: "${{ matrix.php-version }}"
db-image: "${{ matrix.db-image }}"

coverage-report:
if: github.event_name == 'pull_request'
needs: "ci"
Expand Down