This repository provides:
-
π³ Custom Docker Image based on
jakzal/phpqawith: -
π Centralized Castor Tasks for quality assurance:
- Reusable Castor tasks across all your projects
- Minimal configuration required per project
- Support for Libraries, Bundles, and Applications
-
βοΈ Reusable GitHub Actions Workflows:
- Single workflow configuration for all projects
- Customizable per project type
- Consistent CI/CD across your organization
π See Integration Guide for using centralized Castor & GitHub Actions
# From the phpqa repository
./scripts/migrate-project.sh /path/to/your/project library
# Or for an application
./scripts/migrate-project.sh /path/to/your/project applicationThis creates everything you need:
- β
castor.phpwith auto-download from GitHub - β
.phpqa-config.phpconfigured for your project type - β
.github/workflows/ci.ymlready to use - β
.gitignorewith.castor-cache/
Then just run:
cd /path/to/your/project
castor qa:allCopy one of the examples:
cp examples/castor-simple.php your-project/castor.php
cd your-project
castor qa:all # Downloads PHPQA tasks automaticallyπ Full Getting Started Guide
# Pull the image for your desired PHP version
docker pull ghcr.io/spomky-labs/phpqa:<version>Replace <version> with one of the supported PHP versions below.
You can customize the image by using build arguments to include or exclude browsers:
| Argument | Default | Description |
|---|---|---|
WITH_CHROMIUM |
true |
Install Chromium and ChromeDriver for Panther |
WITH_FIREFOX |
true |
Install Firefox ESR and GeckoDriver for Panther |
# Build without any browsers (smallest image, ~500MB-1GB smaller)
docker build --build-arg WITH_CHROMIUM=false --build-arg WITH_FIREFOX=false \
-t ghcr.io/spomky-labs/phpqa:8.4-no-browsers .
# Build with Chrome only
docker build --build-arg WITH_FIREFOX=false \
-t ghcr.io/spomky-labs/phpqa:8.4-chrome-only .
# Build with Firefox only
docker build --build-arg WITH_CHROMIUM=false \
-t ghcr.io/spomky-labs/phpqa:8.4-firefox-only .
# Build with both browsers (default behavior)
docker build -t ghcr.io/spomky-labs/phpqa:8.4 .The following versions are available as tags:
| PHP Version | Tags |
|---|---|
| 8.2 | 8.2, 8.2-amd64, 8.2-arm64, 8.2-<sha>, 8.2-latest (main branch only) |
| 8.3 | 8.3, 8.3-amd64, 8.3-arm64, 8.3-<sha>, 8.3-latest (main branch only) |
| 8.4 | 8.4, 8.4-amd64, 8.4-arm64, 8.4-<sha>, 8.4-latest (main branch only) |
| 8.5 | 8.5, 8.5-amd64, 8.5-arm64, 8.5-<sha> (build may fail, experimental) |
If a release is tagged (e.g. 8.4.1), additional tags will be pushed:
8.4.1,8.4,8
Run PHPUnit from the container:
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 phpunitThis image includes:
- PHP QA tools from
jakzal/phpqa - Castor - Task runner
- PIE - PHP Installer for Extensions
- Enhanced PHPStan, PHPUnit, and Infection extensions
- Chromium + ChromeDriver for browser testing
- Firefox ESR + GeckoDriver for browser testing
PIE is the official PHP extension installer that integrates with Packagist.
# Search for available extensions
docker run --rm ghcr.io/spomky-labs/phpqa:8.4 pie search
# Install an extension from Packagist
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
pie install vendor/extension-name
# List installed extensions
docker run --rm ghcr.io/spomky-labs/phpqa:8.4 pie list
# Get information about an extension
docker run --rm ghcr.io/spomky-labs/phpqa:8.4 pie info vendor/extension-nameBrowse available extensions at packagist.org/extensions.
Additional PHPStan extensions are pre-installed for stricter analysis:
- php-static-analysis/phpstan-extension - Enhanced static analysis
- staabm/phpstan-todo-by - TODO comments with expiry dates
- struggle-for-php/sfp-phpstan-psr-log - PSR-3 Logger interface support
- phpstan/phpstan-deprecation-rules - Detect deprecated code usage
- phpstan/phpstan-strict-rules - Extra strict type checking rules
# Run PHPStan with all extensions
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
phpstan analyse src --level=max
# The extensions are automatically loaded via phpstan/extension-installerphpstan/phpstan-strict-rules provides extra strict checks like:
- Disallow empty() - Use more explicit checks instead
- Require boolean in if conditions
- Disallow variable variables
- Strict comparison operators
phpstan/phpstan-deprecation-rules helps you:
- Find all deprecated code usage in your codebase
- Prepare for major version upgrades
- Maintain compatibility with dependencies
Enhanced PHPUnit testing capabilities with additional plugins:
- ergebnis/phpunit-slow-test-detector - Identify slow tests
- digitalrevolution/phpunit-extensions - Advanced testing utilities
- symfony/browser-kit - Simulate browser requests
- symfony/css-selector - Query HTML with CSS selectors
- symfony/panther - End-to-end testing with real browsers
- zenstruck/foundry - Fixture factories for testing
# Run tests and detect slow ones
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
phpunit --configuration phpunit.xmlConfigure in phpunit.xml:
<extensions>
<bootstrap class="Ergebnis\PHPUnit\SlowTestDetector\Extension">
<parameter name="maximum-duration" value="500"/>
</bootstrap>
</extensions>use Symfony\Component\BrowserKit\HttpBrowser;
use Symfony\Component\HttpClient\HttpClient;
$browser = new HttpBrowser(HttpClient::create());
$crawler = $browser->request('GET', 'https://example.com');
$browser->clickLink('Products');use DigitalRevolution\PHPUnitExtensions\TestCase;
class MyTest extends TestCase
{
// Image comparison for visual regression testing
public function testImageMatches(): void
{
$this->assertImageEquals('expected.png', 'actual.png');
}
// Clock manipulation for time-dependent tests
public function testWithFrozenTime(): void
{
$this->freezeTime('2025-01-01 12:00:00');
// Your test code here
}
}End-to-end testing with real browsers (Chrome and Firefox) for JavaScript-heavy applications.
- Chromium + ChromeDriver (optional, enabled by default with
WITH_CHROMIUM=true) - Firefox ESR + GeckoDriver v0.36.0 (optional, enabled by default with
WITH_FIREFOX=true)
Note: If you don't need browser testing, you can build the image without browsers using --build-arg WITH_CHROMIUM=false --build-arg WITH_FIREFOX=false to reduce the image size by approximately 500MB-1GB.
The following environment variables are configured when browsers are installed:
PANTHER_NO_SANDBOX=1
# Only if WITH_CHROMIUM=true:
PANTHER_CHROME_ARGUMENTS='--disable-dev-shm-usage --no-sandbox --disable-gpu --headless --window-size=1920,1080'
PANTHER_CHROME_DRIVER_BINARY=/usr/bin/chromedriver
# Only if WITH_FIREFOX=true:
PANTHER_FIREFOX_ARGUMENTS='-headless'use Symfony\Component\Panther\Client;
// Create a Chrome client
$client = Client::createChromeClient();
// Navigate to a page
$crawler = $client->request('GET', 'https://example.com');
// Interact with JavaScript
$client->executeScript('document.querySelector("#button").click()');
// Wait for AJAX to complete
$client->waitFor('#result');
// Take a screenshot
$client->takeScreenshot('screenshot.png');use Symfony\Component\Panther\Client;
// Create a Firefox client
$client = Client::createFirefoxClient();
// Same API as Chrome
$crawler = $client->request('GET', 'https://example.com');use Symfony\Component\Panther\PantherTestCase;
class E2ETest extends PantherTestCase
{
public function testMyApp(): void
{
$client = static::createPantherClient();
$crawler = $client->request('GET', 'http://localhost:8000');
// Fill a form
$form = $crawler->selectButton('Submit')->form([
'email' => '[email protected]',
'password' => 'secret',
]);
$client->submit($form);
// Wait for redirect and check result
$client->waitForVisibility('#welcome-message');
$this->assertSelectorTextContains('#welcome-message', 'Welcome');
}
}// Use specific browser
$client = Client::createChromeClient([
'browser' => Client::CHROME,
]);
// Custom browser arguments
$client = Client::createChromeClient([], [
'capabilities' => [
'goog:chromeOptions' => [
'args' => ['--window-size=1920,1080', '--disable-notifications'],
],
],
]);
// Multiple tabs
$client->request('GET', 'https://example.com');
$crawler = $client->clickLink('Open in new tab');
$client->switchTo()->window($client->getWindowHandles()[1]);
// Handle alerts
$client->switchTo()->alert()->accept();# Run with Chrome (default)
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
phpunit --testsuite e2e
# With custom arguments
docker run --rm -v $(pwd):/project -w /project \
-e PANTHER_CHROME_ARGUMENTS='--window-size=1280,720' \
ghcr.io/spomky-labs/phpqa:8.4 phpunitMutation testing framework to ensure your tests are effective.
# Run mutation testing
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
infection --threads=4 --min-msi=80
# Run only on covered code
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
infection --threads=4 --only-coveredConfigure in infection.json5:
{
"source": {
"directories": ["src"]
},
"mutators": {
"@default": true
},
"minMsi": 80,
"minCoveredMsi": 90
}Mutation testing modifies your code (creates mutants) to verify if your tests catch the changes:
- If a test fails, the mutant is "killed" (good - your tests work)
- If tests pass, the mutant "escaped" (bad - you need better tests)
- MSI (Mutation Score Indicator) shows the percentage of killed mutants
Here's a complete QA workflow using all tools:
# 1. Install PHP extension if needed
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
pie install vendor/extension-name
# 2. Run PHPStan with strict rules
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
phpstan analyse src tests --level=max
# 3. Run unit tests with slow test detection
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
phpunit --testsuite unit
# 4. Run browser tests with Panther
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
phpunit --testsuite e2e
# 5. Run mutation testing
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
infection --threads=4 --min-msi=80
# 6. Run Castor tasks
docker run --rm -v $(pwd):/project -w /project ghcr.io/spomky-labs/phpqa:8.4 \
castor qa:allThis project is licensed under the MIT License.