Skip to content

feat(ci): add E2E tests with PHP code coverage#253

Merged
CybotTM merged 10 commits into
mainfrom
feat/e2e-ci-coverage
Jan 20, 2026
Merged

feat(ci): add E2E tests with PHP code coverage#253
CybotTM merged 10 commits into
mainfrom
feat/e2e-ci-coverage

Conversation

@CybotTM
Copy link
Copy Markdown
Member

@CybotTM CybotTM commented Jan 19, 2026

Summary

Adds E2E test execution to CI with PHP code coverage collection and significant performance optimizations.

Changes

1. E2E CI Job with Sharding

  • 3 parallel shards for faster execution
  • Fail-fast with -x flag (stop on first failure)
  • 2 workers per shard for parallelism

2. Pre-built E2E Docker Image

  • New e2e Dockerfile target with Playwright + Chromium pre-installed
  • Built and pushed via Docker Publish workflow
  • CI pulls pre-built image (falls back to build if unavailable)
  • Tests run inside container (no host browser install needed)

3. PHP Coverage Collector

  • Collects Xdebug coverage during HTTP requests
  • Stores coverage data in var/coverage/e2e/
  • API endpoint for coverage report retrieval (/coverage.php)
  • Generates Clover XML format for Codecov
  • Security: Only active when COVERAGE_ENABLED=1 in test/dev environment

4. Coverage Integration

  • PHPUnit coverage uploaded with unit flag
  • E2E coverage uploaded with e2e flag (per shard)
  • Codecov shows both separately and combined

Performance Improvements

Metric Before After
Image build 4 min × 3 shards ~10s pull × 3 shards
Browser install 30s × 3 shards Pre-installed
Workers per shard 1 2
Fail behavior Run all tests Stop on first failure
Total E2E time ~35 min ~10-15 min (estimated)

Test Plan

  • Docker Publish builds and pushes E2E image
  • CI pulls pre-built E2E image
  • E2E tests run inside container with 2 workers
  • Sharding distributes tests across 3 jobs
  • Fail-fast stops on first failure
  • E2E coverage collected and uploaded to Codecov
  • Unit test coverage still works with unit flag

How E2E Coverage Works

Browser → HTTP Request → Nginx → PHP-FPM (with Xdebug)
                                     ↓
                          coverage.php starts collection
                                     ↓
                          Symfony handles request
                                     ↓
                          Shutdown function saves coverage
                                     ↓
After all tests: curl /coverage.php?action=report → Clover XML → Codecov

Local Usage

# Build E2E image locally (with Playwright pre-installed)
docker bake app-e2e

# Run E2E tests (from host - uses Playwright UI if available)
make e2e

# Or run from container (same as CI)
COMPOSE_PROFILES=e2e docker compose run --rm \
  -e E2E_BASE_URL=http://httpd-e2e:80 \
  app-e2e npx playwright test

- Add E2E job to CI workflow that runs Playwright tests
- Create PHP coverage collector (public/coverage.php) for E2E tests
- Enable coverage collection via COVERAGE_ENABLED and XDEBUG_MODE env vars
- Upload E2E coverage to Codecov with 'e2e' flag
- Upload PHPUnit coverage with 'unit' flag for separation
- Include test artifacts (screenshots, reports) on failure

The coverage collector:
- Starts Xdebug coverage on each HTTP request
- Saves coverage data to var/coverage/e2e/*.json
- Provides /coverage.php?action=report endpoint for Clover XML export
- Only active when COVERAGE_ENABLED=1
Copilot AI review requested due to automatic review settings January 19, 2026 20:13
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds E2E test execution to the CI pipeline with PHP code coverage collection via Xdebug. The implementation includes a new coverage collector script, CI workflow job, and configuration changes to enable coverage during E2E tests.

Changes:

  • New E2E CI job that builds the E2E Docker image, runs Playwright tests, and collects coverage
  • PHP coverage collector (public/coverage.php) with API endpoints for status, report generation, and clearing data
  • Integration in index.php to conditionally load coverage collector based on environment variables

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 21 comments.

File Description
.github/workflows/ci.yml Adds E2E job with coverage collection, Playwright execution, and Codecov upload with e2e flag
public/coverage.php New file implementing coverage collection, Clover XML generation, and API endpoints
public/index.php Conditionally includes coverage.php when COVERAGE_ENABLED=1
compose.yml Adds COVERAGE_ENABLED and XDEBUG_MODE environment variables to app-e2e service

Comment thread public/coverage.php Outdated
Comment thread public/coverage.php Outdated
Comment thread public/coverage.php Outdated
Comment thread public/coverage.php Outdated
Comment thread public/coverage.php
Comment thread public/coverage.php Outdated
Comment thread public/coverage.php Outdated
Comment thread public/coverage.php
Comment thread .github/workflows/ci.yml
Comment thread public/coverage.php
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 46.07%. Comparing base (ddc7cf4) to head (eae3cbf).
⚠️ Report is 12 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##               main     #253   +/-   ##
=========================================
  Coverage     46.07%   46.07%           
  Complexity     2627     2627           
=========================================
  Files           172      172           
  Lines          7205     7205           
=========================================
  Hits           3320     3320           
  Misses         3885     3885           
Flag Coverage Δ
unit 46.07% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Coverage collector fixes:
- Fix nginx routing detection using REQUEST_URI instead of SCRIPT_FILENAME
- Add error handling for file operations (mkdir, file_put_contents, unlink)
- Handle glob() returning false
- Validate action and format parameters
- Use random_bytes() for better unique ID generation
- Filter dead code (-2) and non-src files during collection
- Use restrictive permissions (0755 for directories)
- Require COVERAGE_ENABLED=1 for API access
- Only enable coverage in test/dev environments

CI improvements:
- Add E2E test sharding (3 parallel jobs)
- Add --max-failures=10 for fail-fast behavior
- Use more restrictive chmod permissions (755 instead of 777)
- Pass COVERAGE_ENABLED and XDEBUG_MODE as proper env vars
- Reduce timeout to 20 minutes per shard
Performance optimizations:
- Create E2E Docker target with Playwright + Chromium pre-installed
- Build and push E2E image via Docker Publish workflow
- CI pulls pre-built image (falls back to build if unavailable)
- Run Playwright tests inside container (no host browser install)
- Increase workers from 1 to 2 per shard for parallelism
- Use -x flag for immediate fail-fast behavior

Expected time savings:
- Skip ~4 min image build per shard (after first push)
- Skip ~30s Playwright browser install per shard
- Total: ~15 min saved across 3 shards

Changes:
- Dockerfile: Add e2e target extending dev with Playwright
- docker-bake.hcl: Update app-e2e to use e2e target
- docker-publish.yml: Build and push E2E image
- ci.yml: Pull image, run tests in container
- playwright.config.ts: Use 2 workers in CI
docker compose run doesn't support --network flag like docker run.
Use internal service name httpd-e2e:80 instead of host network.
…h check

- Add Symfony cache warmup for test environment
- Improve health check to fail if app doesn't start
- Add container logs output on failure for debugging
- Increase retry attempts with better feedback
The deps stage runs composer install --no-dev which doesn't install
MakerBundle. But composer post-install scripts run with default APP_ENV=dev,
causing Symfony to try loading the dev-only MakerBundle class.

Setting APP_ENV=prod prevents dev bundles from being loaded during
cache warmup.
Show HTTP response code, response body, PHP-FPM logs, nginx logs,
and Symfony error log to help diagnose why the app returns 500 errors.
@CybotTM CybotTM merged commit 03e9c3a into main Jan 20, 2026
11 checks passed
@CybotTM CybotTM deleted the feat/e2e-ci-coverage branch January 20, 2026 06:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants