sweetchuck/junit-merger
Merge multiple JUnit XML report files into a single combined report. Useful for aggregating test results from parallel jobs, multiple test suites, or split CI runs into one JUnit-compatible XML output.
junit-merger package is a point solution for consolidating JUnit XML test reports (e.g., from parallel test runs, microservices, or CI pipelines). It fits well in Laravel/PHP ecosystems where:
tests-passed or tests-failed events (if test reports are generated asynchronously).storage() or public() paths).phpunit or third-party test runners (e.g., PestPHP, which also generates JUnit XML).| Risk Area | Assessment | Mitigation Strategy |
|---|---|---|
| XML Schema Validity | Merging malformed JUnit XML may break output or cause parsing errors. | Validate input files with SimpleXMLElement or DOMDocument before merging. |
| Parallel Test Data | Race conditions if merging real-time streams (e.g., from live test suites). | Use file locks (flock()) or queue delayed merging (e.g., Laravel Queues). |
| Test Metadata Loss | Merging may duplicate or omit test IDs/time stamps if not handled carefully. | Configure the merger to preserve unique identifiers (e.g., testcase attributes). |
| Performance | Large XML files (>100MB) may cause memory issues. | Stream processing with XMLReader or chunked merging. |
| Dependency Stability | Low-star package with no dependents; risk of abandonment. | Fork or wrap in a Laravel-specific package (e.g., spatie/junit-merger-laravel). |
storage/logs/tests/, remote storage, or dynamic paths).package, timestamp)?php artisan test:merge) for CLI-driven workflows.events:dispatch (e.g., TestRunCompleted).MergeJUnitReportsJob) for async processing.afterTests or use its --junit flag + post-processing.phpunit --testdox-html or --log-junit + custom script.after_script to merge and publish results.composer require sweetchuck/junit-merger.tests/unit.xml + tests/feature.xml → tests/merged.xml).phpunit --colors=never merged.xml.// app/Console/Commands/MergeTestReports.php
use Sweetchuck\JunitMerger\JunitMerger;
public function handle() {
$merger = new JunitMerger();
$merged = $merger->merge([
storage_path('logs/tests/unit.xml'),
storage_path('logs/tests/feature.xml'),
]);
file_put_contents(storage_path('logs/tests/merged.xml'), $merged);
}
php artisan schedule:run or trigger manually.phpunit.xml post-test hook or CI pipeline:
<phpunit>
<listeners>
<listener class="App\Listeners\MergeTestReportsListener" />
</listeners>
</phpunit>
# .github/workflows/tests.yml
- name: Merge JUnit reports
run: php artisan test:merge
- uses: actions/upload-artifact@v3
with:
name: test-results
path: storage/logs/tests/merged.xml
--junit flag (Pest 1.2+).xmllint --schema junit.xsd merged.xml).phpunit.xml or Pest config).tests/{suite}.xml).phpunit --colors=never merged.xml).sweetchuck/junit-merger-cli for enhancements).JunitMerger (e.g., add Laravel-specific logging).README section for Laravel usage (e.g., Artisan command examples).Log::info('Merging files: ' . implode(', ', $files))).SimpleXMLElement before merging.try-catch or validate with libxml_use_internal_errors().testcase attributes (e.g., name="TestClass::method" + time) to deduplicate.How can I help you explore Laravel packages today?