Vitest and PhpUnit Code Coverage Reports for Laravel to SonarQube
For some reason I always seem to struggle getting code coverage reports picked up by SonarQube - the documentation isn’t bad but it seems to take me a while to find the right incantation .
I wanted both my PhpUnit tests and Javascript unit tests for my laravel project to generate coverage reports and import this to SonarQube.
My vite config
import { sentryVitePlugin } from "@sentry/vite-plugin";
import { defineConfig } from "vite";
import laravel from "laravel-vite-plugin";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [
laravel({
input: "resources/js/app.jsx",
refresh: true,
}),
react(),
sentryVitePlugin({
org: "myorg",
project: "myproject",
}),
],
build: {
sourcemap: true,
},
test: {
environment: "jsdom",
setupFiles: ["./resources/js/tests/setup.js"],
globals: true,
resetMocks: true,
coverage: {
enabled: true,
include: "resources/js",
reporter: ["html", "lcov"],
reportsDirectory: "public/vitest-coverage/",
},
},
server: {
origin: "http://localhost:5173",
cors: {
origin: "http://localhost",
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
preflightContinue: false,
optionsSuccessStatus: 204,
},
open: false,
},
resolve: {
alias: {
"@": "/resources/js",
},
},
});
in package.json I have
"scripts": {
"dev": "vite",
"build": "vite build",
"test": "vitest --ui",
"coverage": "vitest run --coverage"
},
This provides both an html report viewable in the vite server via localhost and an lcov report on the filesystem
My phpunit.xml file
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory>app</directory>
</include>
</source>
<php>
<env name="APP_ENV" value="testing"/>
<env name="BCRYPT_ROUNDS" value="4"/>
<env name="CACHE_DRIVER" value="array"/>
<env name="DB_DATABASE" value="testing"/>
<env name="MAIL_MAILER" value="array"/>
<env name="PULSE_ENABLED" value="false"/>
<env name="QUEUE_CONNECTION" value="sync"/>
<env name="SESSION_DRIVER" value="array"/>
<env name="TELESCOPE_ENABLED" value="false"/>
</php>
</phpunit>
Then I use this script to run all the tests and import to Sonar - I run Laravel in Docker via Sail and run Sonarqube in Docker
#!/bin/bash
./vendor/bin/sail test --coverage-clover=coverage.xml --coverage-html=public/coverage-report
./vendor/bin/sail npm run coverage
sonar-scanner \
-Dsonar.projectKey=cms_laravel \
-Dsonar.sources=app,resources/js/Components,resources/js/Layouts,resources/js/Pages,resources/js/app.jsx,resources/js/bootstrap.js \
-Dsonar.tests=tests,resources/js/test,resources/js/tests \
-Dsonar.host.url=http://localhost:9000 \
-Dsonar.php.coverage.reportPaths=coverage.xml \
-Dsonar.javascript.lcov.reportPaths=public/vitest-coverage/lcov.info \
-Dsonar.token=$(cat sonar-token)
Now it all works beautifully and it is really helping me keep my code quality where I want it.