Code Coverage
Code coverage measures which lines, branches, and functions of the source code are exercised
during test execution. Blong uses V8's built-in coverage mechanism (via c8) to collect
coverage data from several packages across the monorepo and produce a single unified report.
How Coverage Is Collected
Blong collects coverage at two levels:
- Server-side (tap tests) — unit and integration tests that exercise the backend (handlers, orchestrators, adapters) directly through the JSON-RPC layer.
- Full-stack (Playwright tests) — browser tests that exercise both the server backend and the client-side React UI through a real browser.
Both mechanisms produce coverage data in V8's native coverage format, which is then aggregated
by c8 into a single lcov.info file and text report.
Server-Side Coverage (tap)
The server-side coverage pipeline works as follows:
Each package that contributes to coverage runs blong-dev test, which wraps tap with:
--allow-incomplete-coverage --coverage-report=none
This tells tap to collect V8 coverage (which it does by default via @tapjs/processinfo)
but skip generating its own report. The raw V8 coverage JSON files land in
.tap/coverage/ within each package's directory.
Coverage Aggregation Script
The aggregation is orchestrated by core/blong-gogo/run-coverage.sh:
#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CORE_DIR="$(dirname "$SCRIPT_DIR")"
C8="$CORE_DIR/../common/temp/node_modules/.pnpm/node_modules/.bin/c8"
cd "$(dirname "$CORE_DIR")"
# Merge coverage from all tap-based test packages
for pkg in blong-int-adapter test; do
src="core/$pkg/.tap/coverage"
if [ -d "$src" ]; then
cp "$src"/*.json core/blong-gogo/.tap/coverage/ 2>/dev/null || true
fi
done
# Playwright coverage data is staged by blong-dev playwright --coverage
# directly into core/blong-gogo/.tap/coverage/ (with pw- prefix).
pw_count=$(ls core/blong-gogo/.tap/coverage/pw-*.json 2>/dev/null | wc -l)
if [ "$pw_count" -gt 0 ]; then
echo "run-coverage.sh: Including $pw_count Playwright coverage file(s)"
fi
"$C8" report \
--all \
--temp-directory core/blong-gogo/.tap/coverage \
--include "core/blong-gogo/src/**/*.ts" \
--include "core/test/**/*.ts" \
--include "core/blong-int-adapter/**/*.ts" \
--include "core/blong-suite/**/*.ts" \
--include "core/blong-marine/**/*.ts" \
--include "core/blong-browser/src/**/*.ts" \
--include "core/blong-browser/src/**/*.tsx" \
--reporter text \
--reporter lcov \
-o coverage
How it works:
- Copy coverage data: Coverage JSON files from tap-based packages (
blong-int-adapter,test) are copied intoblong-gogo's own.tap/coverage/directory. Playwright coverage files (withpw-prefix) are also written here byblong-dev playwright --coverage. This collects all coverage data in one place. - Run
c8 report:c8reads all V8 coverage JSON files from the temp directory and generates coverage reports. The--includeflags restrict the report to source files from the relevant packages:blong-gogo,test,blong-int-adapter,blong-suite,blong-marine, andblong-browser. - Output: An
lcov.infofile and a text report are written to the repository root'scoverage/directory. Thelcov.infois consumed by GitHub Actions (viaromeovs/lcov-reporter-action) to post coverage summaries on pull requests.
Why Not --coverage-map
Passing --coverage-map with TypeScript paths causes tap to exit 1 with "No coverage generated"
because tsx compiles files in-memory and the V8 coverage data does not match the original .ts
file paths. The separate c8 step handles this correctly.
Rush Integration
The ci-coverage bulk command is defined in common/config/rush/command-line.json:
{
"commandKind": "bulk",
"name": "ci-coverage",
"summary": "Run code coverage reports",
"ignoreMissingScript": true,
...
}
Only @feasibleone/blong-gogo implements this script in its package.json:
"ci-coverage": "./run-coverage.sh"
In CI, rush ci-coverage runs after rush ci-test completes, so all test coverage data
is available before aggregation.
Full-Stack Coverage (Playwright)
Playwright tests collect coverage from both the server and browser simultaneously:
- Server-side: The
blong-dev playwright --coveragecommand setsNODE_V8_COVERAGEso the blong server process writes V8 coverage on exit. Coverage files are written to.playwright/coverage/v8/within the suite directory. - Browser-side: The
@feasibleone/blong-browser/playwrighttest object includes an automatic coverage fixture that uses Playwright'spage.coverage.startJSCoverage()API. Browser scripts served by Vite are mapped back to filesystem paths and written as V8 coverage JSON files. - Aggregation: After tests complete, both sets of coverage files are copied with a
pw-prefix intocore/blong-gogo/.tap/coverage/, where they are included in the unifiedc8 reportaggregation.
See the Playwright code coverage pattern for the full pattern reference including setup instructions, the URL-to-file mapping mechanism, and CI integration details.
Key Constraints
c8must run from the repository root so path mappings inlcov.infoare correct for subsequent GitHub Actions steps.- Use
-o <path>(not--reports-directory) for the output directory. - Coverage data must be on disk before
c8 reportruns — the tap-produced.tap/coverage/files must exist and be merged into a single temp directory.