nunomaduro/pao
pao is a tiny CLI helper for Laravel/PHP projects by Nuno Maduro. It makes running common project tasks easier by providing a simple command runner you can ship with your app or use in development, keeping team workflows consistent and repeatable.
Installation
composer require --dev nunomaduro/pao
Add to composer.json under require-dev if not using global install.
Configuration Publish the config file:
php artisan vendor:publish --provider="NunoMaduro\Pao\PaoServiceProvider" --tag="pao-config"
Edit config/pao.php to define your preferred output format (e.g., json, tap, junit).
First Use Case
Run tests with PAO in your phpunit.xml:
<phpunit>
<extensions>
<extension class="NunoMaduro\Pao\Extensions\PaoExtension"/>
</extensions>
</phpunit>
Execute tests:
./vendor/bin/phpunit --testdox-html --pao=json
Output will now be formatted as JSON (or your chosen format) in tests/_output/.
CI/CD Pipelines Use PAO to generate structured output for:
./vendor/bin/phpunit --pao=junit
prove or TAP::Harness.
./vendor/bin/phpunit --pao=tap
./vendor/bin/phpunit --pao=json | jq '.tests'
Local Development
--pao=json to inspect failed tests interactively:
./vendor/bin/phpunit --pao=json | grep -A 5 '"status":"failed"'
glow for colored JSON:
./vendor/bin/phpunit --pao=json | glow
Parallel Testing
Configure PAO in parallel test suites (e.g., phpunit-parallel) by ensuring each worker writes to a unique output directory:
./vendor/bin/phpunit --pao=json --testdox-html --workers=4 --output-dir=tests/_output/worker_
NunoMaduro\Pao\Output\OutputInterface to create new formats (e.g., Markdown or HTML).PaoServiceProvider::boot() to modify output before writing.Output Directory Permissions
Ensure tests/_output/ is writable:
mkdir -p tests/_output && chmod -R 777 tests/_output
Fix: Configure a custom path in config/pao.php:
'output_dir' => storage_path('logs/pao'),
Conflicts with Other Extensions
PAO may clash with phpunit-snapshot or phpunit-coverage. Solution:
phpunit.xml (PAO last).--exclude-group=pao to skip PAO for specific tests.JSON Parsing Issues
[] for skipped tests. Handle in consumers:
$output = json_decode(file_get_contents('tests/_output/results.json'), true);
if (empty($output['tests'])) { /* Handle edge case */ }
--verbose to PAO commands to see raw test data:
./vendor/bin/phpunit --pao=json --verbose
config/pao.php:
'debug' => env('APP_DEBUG', false),
jsonlint.com to validate PAO JSON output../vendor/bin/phpunit --pao=junit --no-coverage # Skip coverage if not needed
memory_limit in php.ini if processing huge JSON outputs:
memory_limit = 512M
config/pao.php to set paths dynamically:
'output_dir' => function () {
return sys_get_temp_dir() . '/pao_' . date('Ymd');
},
'enabled' => !app()->environment('production'),
How can I help you explore Laravel packages today?