From 5dd0e28d618a6ba71ebf0c72c3676b447109226f Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 9 Jun 2026 16:28:40 +0200 Subject: [PATCH 1/3] ci(playwright): run E2E in parallel and drop redundant browser install The Playwright job ran single-threaded on CI despite the public-repo runner having 4 vCPUs, and reinstalled browsers on every run even though the pinned mcr.microsoft.com/playwright image already ships them. - playwright.config.ts: use 3 workers on CI (was 1). Tests mock all network traffic per page (assets/tests/**/test-helper.js), so they are isolated and safe to run in parallel. - docker-compose.yml: add `ipc: host` to the playwright service so parallel Chromium does not crash on Docker's default 64 MB /dev/shm. - .github/workflows/playwright.yaml: drop `playwright install --with-deps`; the image's bundled browsers already match @playwright/test, so it only re-ran apt for libraries already present. Retries, the build/cache steps and Playwright versions are unchanged. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/playwright.yaml | 5 ++++- CHANGELOG.md | 5 +++++ docker-compose.yml | 4 ++++ playwright.config.ts | 7 +++++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/.github/workflows/playwright.yaml b/.github/workflows/playwright.yaml index 6cc614d80..06e5f9bf0 100644 --- a/.github/workflows/playwright.yaml +++ b/.github/workflows/playwright.yaml @@ -58,8 +58,11 @@ jobs: - name: Run playwright env: CI: "true" + # The mcr.microsoft.com/playwright image already bundles the browsers for + # its version, kept in lockstep with @playwright/test in package.json, so + # `playwright install --with-deps` only re-runs apt for libraries that are + # already present. Run the tests directly. run: | - docker compose run --rm playwright npx playwright install --with-deps docker compose run --rm playwright npx playwright test - uses: actions/upload-artifact@v7 diff --git a/CHANGELOG.md b/CHANGELOG.md index a415a2a3b..28eb95971 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +- Sped up the Playwright CI job: it now runs in parallel (3 workers, sized to the 4-vCPU public + GitHub runner) instead of a single worker, added `ipc: host` to the `playwright` Compose + service so parallel Chromium does not exhaust Docker's default 64 MB `/dev/shm`, and dropped + the redundant `playwright install --with-deps` step (the pinned Playwright image already ships + the matching browsers). - Removed a dead statement in `MediaRepository::getPaginator()` that referenced the undefined variables `$page` and `$itemsPerPage`; the computed value was never used. - Fixed inverted user-type guard in `UserService::activateExternalUser()`: the "user is not of diff --git a/docker-compose.yml b/docker-compose.yml index c9f2f16a3..cb0d6c344 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -162,6 +162,10 @@ services: # https://playwright.dev/docs/docker # Version should match the one in `package.json`. image: mcr.microsoft.com/playwright:v1.57.0 + # Chromium needs more than Docker's default 64 MB /dev/shm once tests run in + # parallel; sharing the host IPC namespace avoids renderer crashes + # ("Target closed"). See the Playwright Docker docs. + ipc: host networks: - app depends_on: diff --git a/playwright.config.ts b/playwright.config.ts index 103de5202..4835d74e7 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -20,8 +20,11 @@ export default defineConfig({ forbidOnly: !!process.env.CI, /* Retry on CI only */ retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, + /* CI runs on a 4-vCPU GitHub-hosted runner (public repo); use 3 workers and + * leave one core for the browser/system. Tests mock every network call per + * page (see assets/tests/**\/test-helper.js), so they are isolated and safe + * to run in parallel. Locally, Playwright's default (50% of cores) applies. */ + workers: process.env.CI ? 3 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ // Open never added to avoid the CI pipeline to get stuck in a html-reporter-mode. reporter: [['html', { open: 'never' }]], From f2985e7cce3c66a4f47bc8aecb1bdb5a80b325b3 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 9 Jun 2026 16:35:23 +0200 Subject: [PATCH 2/3] ci(playwright): propagate CI into the container so workers:3 applies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The first attempt set workers:3 but CI still ran 2 (Playwright's default for a 4-core box) — `docker compose run` doesn't forward host env, so process.env.CI was undefined inside the container and the CI branch of both `workers` and `retries` never triggered (a pre-existing gap: the baseline was already running the default, not 1 worker). Pass `-e CI=true` explicitly, matching how the local verification invokes it. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/playwright.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/playwright.yaml b/.github/workflows/playwright.yaml index 06e5f9bf0..9bb2d5176 100644 --- a/.github/workflows/playwright.yaml +++ b/.github/workflows/playwright.yaml @@ -56,14 +56,18 @@ jobs: docker compose run --rm node npm run build - name: Run playwright - env: - CI: "true" + # `-e CI=true` propagates CI *into* the container — `docker compose run` + # does not forward host env by default, so without it playwright.config.ts + # sees no CI and falls back to its defaults (50% of cores ≈ 2 workers, + # retries 0). The explicit flag is what actually enables workers: 3 and + # retries: 2 on the runner. + # # The mcr.microsoft.com/playwright image already bundles the browsers for # its version, kept in lockstep with @playwright/test in package.json, so # `playwright install --with-deps` only re-runs apt for libraries that are # already present. Run the tests directly. run: | - docker compose run --rm playwright npx playwright test + docker compose run --rm -e CI=true playwright npx playwright test - uses: actions/upload-artifact@v7 if: always() From 14b0d9718d6b679aa9fc08efc50ed5f64b39e5b9 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 9 Jun 2026 16:43:23 +0200 Subject: [PATCH 3/3] ci(playwright): pre-pull images in parallel instead of on-demand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each image was pulled on demand inside the first step that used it, serially across steps — measured ~90s total on the runner (mariadb+phpfpm during Composer install, node during Build assets, nginx+playwright during Run playwright). Pull them all up front in one `docker compose pull`, which pulls services concurrently, overlapping the smaller images under the large playwright pull. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/playwright.yaml | 9 +++++++++ CHANGELOG.md | 9 +++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/playwright.yaml b/.github/workflows/playwright.yaml index 9bb2d5176..431d673d2 100644 --- a/.github/workflows/playwright.yaml +++ b/.github/workflows/playwright.yaml @@ -42,6 +42,15 @@ jobs: - name: Setup network run: docker network create frontend + - name: Pull container images + # Pull all images this job uses up front, in parallel (compose pulls + # services concurrently). Otherwise each image is pulled on demand inside + # the first step that uses it — serially across steps (~90s total: + # mariadb+phpfpm in Composer install, node in Build assets, + # nginx+playwright in Run playwright). Pulling concurrently overlaps the + # smaller images under the large playwright pull. + run: docker compose pull --quiet phpfpm node playwright nginx mariadb + - name: Composer install run: | docker compose run --rm phpfpm composer install diff --git a/CHANGELOG.md b/CHANGELOG.md index 28eb95971..21b955d76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,10 +5,11 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - Sped up the Playwright CI job: it now runs in parallel (3 workers, sized to the 4-vCPU public - GitHub runner) instead of a single worker, added `ipc: host` to the `playwright` Compose - service so parallel Chromium does not exhaust Docker's default 64 MB `/dev/shm`, and dropped - the redundant `playwright install --with-deps` step (the pinned Playwright image already ships - the matching browsers). + GitHub runner) instead of the default 2, added `ipc: host` to the `playwright` Compose + service so parallel Chromium does not exhaust Docker's default 64 MB `/dev/shm`, pulls the + container images once up front in parallel instead of on demand serially across steps + (~90s of pulls overlapped), and dropped the redundant `playwright install --with-deps` step + (the pinned Playwright image already ships the matching browsers). - Removed a dead statement in `MediaRepository::getPaginator()` that referenced the undefined variables `$page` and `$itemsPerPage`; the computed value was never used. - Fixed inverted user-type guard in `UserService::activateExternalUser()`: the "user is not of