Skip to content
Open
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
da64571
IBX-11740: Added playwright-browser-tests.yml
pawlakadrian May 27, 2026
7e466d1
IBX-11740: refactor playwright-browser-tests.yml
pawlakadrian May 27, 2026
6ffbfe7
IBX-11740: refactor playwright-browser-tests.yml
pawlakadrian May 27, 2026
218bc93
IBX-11740: Fixed write permissions
pawlakadrian May 27, 2026
cf0f861
IBX-11740: Fixed workflows
pawlakadrian May 27, 2026
7a8103e
IBX-11740: Fixed workflows
pawlakadrian May 28, 2026
8b966d3
IBX-11740: Fixed workflows
pawlakadrian May 28, 2026
46e8126
IBX-11740: Fixed workflows
pawlakadrian May 28, 2026
868c4c3
IBX-11740: Fixed workflows
pawlakadrian May 28, 2026
f441eee
IBX-11740: Fixed workflows
pawlakadrian May 28, 2026
2c48d32
IBX-11740: debug
pawlakadrian May 28, 2026
ec6f98d
IBX-11740: debug
pawlakadrian May 28, 2026
0996825
IBX-11740: debug
pawlakadrian May 28, 2026
0b19049
IBX-11740: debug
pawlakadrian May 28, 2026
4f7b7af
IBX-11740: debug
pawlakadrian May 28, 2026
65bbc15
IBX-11740: debug
pawlakadrian May 28, 2026
1b8f8c7
IBX-11740: debug
pawlakadrian May 29, 2026
9fa2907
IBX-11740: refactor playwright-browser-tests.yml
pawlakadrian Jun 23, 2026
a141493
IBX-11740: Fixed CI
pawlakadrian Jun 24, 2026
7f07adb
IBX-11740: Fixed CI
pawlakadrian Jun 24, 2026
1317e8d
IBX-11740: Fixed CI
pawlakadrian Jul 13, 2026
ad4806d
IBX-11740: Added missing export for cohesivo_version
pawlakadrian Jul 13, 2026
20805b5
Changed slack integration from v1.23 to v3.03
pawlakadrian Jul 24, 2026
fdd0779
Removed 2 paths for reports, added timestamp and removed behat phases
pawlakadrian Jul 24, 2026
85fb065
After review
pawlakadrian Sep 10, 2026
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
370 changes: 370 additions & 0 deletions .github/workflows/playwright-browser-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,370 @@
name: Browser tests (Playwright)

on:
workflow_call:
inputs:
project-edition:
description: "Project edition to set up: oss, headless, experience, commerce"
required: true
type: string
test-package:
description: "Run tests of a single package (e.g. admin-ui). Empty = all packages with tests (edition mode)."
required: false
type: string
default: ''
test-suite:
description: "Extra Playwright CLI args (e.g. --grep Trash)"
required: false
type: string
default: ''
project-version:
description: "Project version (e.g. 6.0.x-dev). If empty, inferred from branch alias."
required: false
type: string
default: ''
setup:
description: "Docker Compose files to use"
required: false
type: string
default: "doc/docker/base-dev.yml"
php-image:
description: "PHP Docker image to use"
required: false
type: string
default: "ghcr.io/ibexa/docker/php:8.3-node22"
node-version:
description: "Node.js version for running Playwright"
required: false
type: string
default: "22"
ci-scripts-branch:
description: "Branch from ibexa/ci-scripts to use"
required: false
type: string
default: "main"
cohesivo-version:
description: "Composer version constraint for ibexa/cohesivo-playwright. Empty = match the project version (branch alias). Playwright is 5.0+ only — there is no 4.6 branch of the library, so 4.6 projects must not call this workflow."
required: false
type: string
default: ""
app-url:
description: "URL under which the app is reachable from the runner host. Empty = derived from setup."
required: false
type: string
default: ""
artifact-suffix:
description: "Discriminator when one run calls this workflow several times for the same edition (e.g. 'pgsql18-varnish')"
required: false
type: string
default: ''
job-count:
description: "Number of jobs that will run the tests in parallel (Playwright --shard)"
required: false
type: number
default: 1
send-success-notification:
description: "Send a Slack notification when tests pass"
required: false
type: boolean
default: true
timeout:
description: "Job timeout in minutes"
required: false
type: number
default: 60
secrets:
SLACK_WEBHOOK_URL:
required: false
SATIS_NETWORK_KEY:
required: false
SATIS_NETWORK_TOKEN:
required: false
AUTOMATION_CLIENT_ID:
required: false
AUTOMATION_CLIENT_SECRET:
required: false
EZROBOT_33:
required: false
ADMIN_LOGIN:
required: false
ADMIN_PASSWORD:
required: false

env:
# Symfony env the app boots in — the established platform test env (provided by ibexa/behat),
# same as the Behat pipeline and expected by the shared project-setup script. It configures
# the app, not Playwright (the tests just hit it over HTTP). There is no dedicated "playwright"
# env; dropping this would fall back to "dev", so it stays as-is.
APP_ENV: behat
Comment thread
pawlakadrian marked this conversation as resolved.
APP_DEBUG: 1
APP_SECRET: '2d4218d7b6c69a9f88da7b8986e64717b3c40948a7ba2b1ca309dc292472286d'
PHP_INI_ENV_memory_limit: 1G
COMPOSER_CACHE_DIR: ~/.composer/cache

jobs:
setup-jobs:
runs-on: ubuntu-latest
timeout-minutes: 1
outputs:
matrix: ${{ steps.generate-matrix.outputs.matrix }}
job-count: ${{ steps.generate-matrix.outputs.job-count }}
steps:
- name: Set job count for builds
run: echo "job_count=${{ inputs.job-count }}" >> $GITHUB_ENV
- name: Limit job-count to max 3 for PRs
if: github.event_name == 'pull_request'
run: |
if [[ "$job_count" -gt 3 ]] ; then
job_count=3
fi
echo "job_count=$job_count" >> $GITHUB_ENV
env:
job_count: ${{ env.job_count }}
- name: Generate matrix
id: generate-matrix
run: |
matrix=$(jq -cn --argjson n "$job_count" '{offset: [range(0; $n)]}')
echo "matrix=$matrix" >> $GITHUB_OUTPUT
echo "job-count=$job_count" >> $GITHUB_OUTPUT
- if: always() && github.event_name != 'pull_request'
name: Create Slack message variables
run: |
echo "RESULT_EMOJI=:x:" >> $GITHUB_ENV
- if: always() && github.event_name != 'pull_request'
name: Create Slack message
run: >
echo "SLACK_PAYLOAD=
{\"blocks\": [{\"type\": \"section\",\"text\": {\"type\": \"mrkdwn\",\"text\": \"
$RESULT_EMOJI *$GITHUB_REPOSITORY*:*$GITHUB_REF_NAME* ($GITHUB_ACTOR) |
<$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID|Details>
\"}}]}" >> $GITHUB_ENV
- if: always() && github.event_name != 'pull_request' && job.status != 'success' && job.status != 'skipped'
name: Send notification about workflow result
uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload: ${{ env.SLACK_PAYLOAD }}

playwright-tests:
needs: setup-jobs
runs-on: ubuntu-latest
timeout-minutes: ${{ inputs.timeout }}
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.setup-jobs.outputs.matrix) }}

steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0

- name: Derive app URL from setup
run: |
if [ -n "$APP_URL" ]; then
echo "APP_URL=$APP_URL" >> $GITHUB_ENV
elif echo "$SETUP" | grep -q varnish; then
echo "APP_URL=http://localhost:8081" >> $GITHUB_ENV
else
echo "APP_URL=http://localhost:8080" >> $GITHUB_ENV
fi
env:
APP_URL: ${{ inputs.app-url }}
SETUP: ${{ inputs.setup }}

- name: Set up project version
id: project-version
run: |
if [[ "$version" == "" ]] ; then
echo "Input project version not set, taking the value from composer.json"
version=$(cat composer.json | jq -r '.extra | ."branch-alias" | .[]')
fi
echo "version=$version" >> $GITHUB_OUTPUT
env:
version: ${{ inputs.project-version }}

- name: Setup PHP Action
uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240 # 2.37.2
with:
php-version: 8.3
coverage: none

- name: Cache dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ${{ env.COMPOSER_CACHE_DIR }}
key: ${{ inputs.project-edition }}-${{ steps.project-version.outputs.version }}-${{ inputs.php-image }}-${{ github.sha }}
restore-keys: |
${{ inputs.project-edition }}-${{ steps.project-version.outputs.version }}-${{ inputs.php-image }}

- name: Generate token
id: generate_token
if: env.AUTOMATION_CLIENT_ID != ''
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
app-id: ${{ secrets.AUTOMATION_CLIENT_ID }}
private-key: ${{ secrets.AUTOMATION_CLIENT_SECRET }}
owner: ibexa
env:
AUTOMATION_CLIENT_ID: ${{ secrets.AUTOMATION_CLIENT_ID }}

- if: env.SATIS_NETWORK_KEY != ''
name: Add composer keys for private packagist
run: |
composer config http-basic.updates.ibexa.co $SATIS_NETWORK_KEY $SATIS_NETWORK_TOKEN
env:
SATIS_NETWORK_KEY: ${{ secrets.SATIS_NETWORK_KEY }}
SATIS_NETWORK_TOKEN: ${{ secrets.SATIS_NETWORK_TOKEN }}

- name: Add composer key for GitHub App
if: ${{ steps.generate_token.outputs.token != '' }}
run: |
composer config github-oauth.github.com $GITHUB_TOKEN
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}

- if: startsWith(steps.project-version.outputs.version, 'v') == false
name: Set up whole project using the tested dependency (dev version)
run: |
curl -L "https://raw.githubusercontent.com/ibexa/ci-scripts/${{ inputs.ci-scripts-branch }}/bin/${{ steps.project-version.outputs.version }}/prepare_project_edition.sh" > prepare_project_edition.sh

Check warning on line 227 in .github/workflows/playwright-browser-tests.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Not enforcing HTTPS here might allow for redirections to insecure websites. Make sure it is safe here.

See more on https://sonarcloud.io/project/issues?id=ibexa_gh-workflows&issues=AaCKzpQz2z2m1OuTm4W1&open=AaCKzpQz2z2m1OuTm4W1&pullRequest=100
chmod +x prepare_project_edition.sh
./prepare_project_edition.sh ${{ inputs.project-edition }} ${{ steps.project-version.outputs.version }} ${{ inputs.setup }} ${{ inputs.php-image }}

- if: startsWith(steps.project-version.outputs.version, 'v')
name: Set up whole project using a stable release
run: |
curl -L "https://raw.githubusercontent.com/ibexa/ci-scripts/${{ inputs.ci-scripts-branch }}/bin/stable/prepare_project_edition.sh" > prepare_project_edition.sh

Check warning on line 234 in .github/workflows/playwright-browser-tests.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Not enforcing HTTPS here might allow for redirections to insecure websites. Make sure it is safe here.

See more on https://sonarcloud.io/project/issues?id=ibexa_gh-workflows&issues=AaCKzpQz2z2m1OuTm4W2&open=AaCKzpQz2z2m1OuTm4W2&pullRequest=100
chmod +x prepare_project_edition.sh
./prepare_project_edition.sh ${{ inputs.project-edition }} ${{ steps.project-version.outputs.version }} ${{ inputs.setup }} ${{ inputs.php-image }}

- name: Add ibexa_integrated_help config
if: inputs.project-edition != 'oss'
run: |
cd ${HOME}/build/project
docker compose --env-file=.env exec -T --user www-data app sh -c "printf 'ibexa_integrated_help:\n enabled: false\n' > config/packages/ibexa_integrated_help.yaml"

# Data seeding is done per-test through IbexaApiClient (REST) in the packages'
# beforeAll hooks — no Behat setup phase here, so this workflow has no Behat dependency.

- name: Install ibexa/cohesivo-playwright
run: |
cd ${HOME}/build/project
# empty cohesivo-version → match the project version (branch alias), so a 5.0/6.0
# branch installs the matching library version. (No 4.6 branch of the library exists.)
if [ -z "$COHESIVO_VERSION" ]; then
COHESIVO_VERSION="$PROJECT_VERSION"
fi
echo "Installing ibexa/cohesivo-playwright:$COHESIVO_VERSION"
# TODO: drop the vcs repository once ibexa/cohesivo-playwright is published on updates.ibexa.co

Check warning on line 256 in .github/workflows/playwright-browser-tests.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this "TODO" comment.

See more on https://sonarcloud.io/project/issues?id=ibexa_gh-workflows&issues=AaCKzpQz2z2m1OuTm4W3&open=AaCKzpQz2z2m1OuTm4W3&pullRequest=100
docker compose --env-file=.env exec -T --user www-data -e GITHUB_TOKEN -e COHESIVO_VERSION app sh -c '
composer config repositories.cohesivo-playwright vcs https://github.com/ibexa/cohesivo-playwright &&
if [ -n "$GITHUB_TOKEN" ]; then composer config github-oauth.github.com "$GITHUB_TOKEN"; fi &&
composer require --dev "ibexa/cohesivo-playwright:$COHESIVO_VERSION" --no-scripts --no-plugins'
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}
COHESIVO_VERSION: ${{ inputs.cohesivo-version }}
PROJECT_VERSION: ${{ steps.project-version.outputs.version }}

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}

- name: Configure npm to use HTTPS for GitHub packages
if: ${{ steps.generate_token.outputs.token != '' }}
run: |
git config --global url."https://x-access-token:${GITHUB_TOKEN}@github.com/".insteadOf "git@github.com:"
git config --global url."https://x-access-token:${GITHUB_TOKEN}@github.com/".insteadOf "ssh://git@github.com/"
git config --global url."https://x-access-token:${GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/"
env:
GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}

- name: Fix write permissions on project directory
run: sudo chmod -R a+rwX ${HOME}/build/project

- name: Install cohesivo-playwright dependencies and build
run: |
cd ${HOME}/build/project/vendor/ibexa/cohesivo-playwright
npm ci

Check warning on line 286 in .github/workflows/playwright-browser-tests.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Omitting "--ignore-scripts" allows lifecycle scripts to run during package installation.

See more on https://sonarcloud.io/project/issues?id=ibexa_gh-workflows&issues=AaCKzpQz2z2m1OuTm4W4&open=AaCKzpQz2z2m1OuTm4W4&pullRequest=100
npm run build

- name: Install per-package Playwright test dependencies
run: |
for dir in ${HOME}/build/project/vendor/ibexa/*/tests/playwright-tests; do
if [ -f "$dir/package.json" ]; then
cd "$dir"
echo "→ npm ci in $dir"
npm ci

Check warning on line 295 in .github/workflows/playwright-browser-tests.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Omitting "--ignore-scripts" allows lifecycle scripts to run during package installation.

See more on https://sonarcloud.io/project/issues?id=ibexa_gh-workflows&issues=AaCKzpQz2z2m1OuTm4W5&open=AaCKzpQz2z2m1OuTm4W5&pullRequest=100
fi
done

- name: Install Playwright browsers
run: |
cd ${HOME}/build/project/vendor/ibexa/cohesivo-playwright
npx playwright install --with-deps chromium

Check warning on line 302 in .github/workflows/playwright-browser-tests.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define exact package version to avoid installing unverified releases.

See more on https://sonarcloud.io/project/issues?id=ibexa_gh-workflows&issues=AaCKzpQz2z2m1OuTm4W7&open=AaCKzpQz2z2m1OuTm4W7&pullRequest=100

Check warning on line 302 in .github/workflows/playwright-browser-tests.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

"npx" can install packages on-demand and run their lifecycle scripts.

See more on https://sonarcloud.io/project/issues?id=ibexa_gh-workflows&issues=AaCKzpQz2z2m1OuTm4W6&open=AaCKzpQz2z2m1OuTm4W6&pullRequest=100

- name: Run Playwright tests
# inputs are passed via env (not interpolated into the script) to avoid shell injection
run: |
cd ${HOME}/build/project/vendor/ibexa/cohesivo-playwright
EXTRA_ARGS="$TEST_SUITE"
# --pass-with-no-tests only under sharding: an empty shard is expected, an empty
# unsharded run means the edition grep matched nothing and should fail loudly.
if [ "$JOB_COUNT" -gt 1 ]; then
EXTRA_ARGS="$EXTRA_ARGS --shard=$(( SHARD_OFFSET + 1 ))/$JOB_COUNT --pass-with-no-tests"
Comment thread
pawlakadrian marked this conversation as resolved.
fi
if [ -n "$TEST_PACKAGE" ]; then
npm run test:package -- "$TEST_PACKAGE" $EXTRA_ARGS
else
npm run test:all -- $EXTRA_ARGS
fi
env:
TEST_SUITE: ${{ inputs.test-suite }}
TEST_PACKAGE: ${{ inputs.test-package }}
JOB_COUNT: ${{ needs.setup-jobs.outputs.job-count }}
SHARD_OFFSET: ${{ matrix.offset }}
APP_URL: ${{ env.APP_URL }}
APP_EDITION: ${{ inputs.project-edition }}
ADMIN_LOGIN: ${{ secrets.ADMIN_LOGIN || 'admin' }}
ADMIN_PASSWORD: ${{ secrets.ADMIN_PASSWORD || 'publish' }}
CI: true

- name: Upload Playwright report
if: always()
uses: actions/upload-artifact@v4
with:
name: playwright-report-${{ inputs.project-edition }}-${{ inputs.artifact-suffix || inputs.test-package || 'all' }}-shard${{ matrix.offset }}-${{ github.run_id }}-${{ github.run_attempt }}
# `**` matches any depth, so one pair of globs covers both the package suites
# (<pkg>/tests/playwright-tests/) and cohesivo's own tests (cohesivo-playwright/)
path: |
/home/runner/build/project/vendor/ibexa/**/playwright-report/
/home/runner/build/project/vendor/ibexa/**/test-results/
retention-days: 14

- if: always() && github.event_name != 'pull_request'
name: Create Slack message variables
run: |
echo "RESULT_EMOJI=:x:" >> $GITHUB_ENV
JOB_NUMBER=$(expr ${{ matrix.offset }} + 1)
echo "JOB_NUMBER=$JOB_NUMBER" >> $GITHUB_ENV

- if: always() && job.status == 'success' && github.event_name != 'pull_request'
name: Create Slack message success variables
run: |
echo "RESULT_EMOJI=:white_check_mark:" >> $GITHUB_ENV

- if: always() && github.event_name != 'pull_request'
name: Create Slack message
run: >
echo "SLACK_PAYLOAD=
{\"blocks\": [{\"type\": \"section\",\"text\": {\"type\": \"mrkdwn\",\"text\": \"
$RESULT_EMOJI *$GITHUB_REPOSITORY*:*$GITHUB_REF_NAME* ($GITHUB_ACTOR) | Playwright |
<$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID|Details> |
$JOB_NUMBER/${{ needs.setup-jobs.outputs.job-count }}
\"}}]}" >> $GITHUB_ENV

- if: always() && github.event_name != 'pull_request' && (job.status != 'success' || inputs.send-success-notification)
name: Send notification about workflow result
uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3
with:
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
webhook-type: incoming-webhook
payload: ${{ env.SLACK_PAYLOAD }}