bun test --coverage: code coverage table and lcov report
- tool
- Bun
- command
- bun test
- flag
- --coverage, --coverage-reporter=text|lcov, --coverage-dir=DIR
- default
- off
bun test --coverage runs the tests and then prints a table with the share of functions and lines each source file executed, plus the line numbers that never ran. It needs no extra package (no Istanbul or c8). Add --coverage-reporter=lcov to write coverage/lcov.info for CI services and editors.
Example
math.ts has two functions; the test only calls one of them:
cat > math.ts <<'EOF'
export function add(a: number, b: number) {
return a + b;
}
export function divide(a: number, b: number) {
if (b === 0) throw new Error("division by zero");
return a / b;
}
EOF
cat > math.test.ts <<'EOF'
import { expect, test } from "bun:test";
import { add } from "./math";
test("add", () => expect(add(1, 2)).toBe(3));
EOF
npx --yes bun@1 test --coverage 2>&1 | grep -E "\|"
echo "--- lcov"
npx --yes bun@1 test --coverage --coverage-reporter=lcov >/dev/null 2>&1
ls coverageOutput
-----------|---------|---------|------------------- File | % Funcs | % Lines | Uncovered Line #s -----------|---------|---------|------------------- All files | 50.00 | 40.00 | math.ts | 50.00 | 40.00 | 4-6 -----------|---------|---------|------------------- --- lcov lcov.info
% Funcs counts functions that were called at least once and % Lines the executed lines; Uncovered Line #s points at the body of divide, which no test reached. The test file itself is excluded by default.
Options
| Option | Effect |
|---|---|
| --coverage | Collect coverage and print the text table |
| --coverage-reporter=text | The table in the terminal (default) |
| --coverage-reporter=lcov | Write coverage/lcov.info; repeat the flag to get both |
| --coverage-dir=DIR | Directory for the lcov file (default coverage) |
| coverage = true in bunfig.toml [test] | Turn coverage on for every bun test |
| coverageThreshold in bunfig.toml | Fail the run when coverage is below the value |
| coverageSkipTestFiles | Exclude test files from the report (default true) |
bunfig.toml
[test]
coverage = true
coverageReporter = ["text", "lcov"]
coverageThreshold = { lines = 0.8, functions = 0.8 }With the threshold set, bun test exits with a non-zero code when either value is below 80 percent, which fails a CI job.
Reading the numbers
- Coverage is computed only for files that were loaded. Add a test that imports a new module, otherwise it is invisible in the table.
- The
All filesrow is an average over the listed files, not over the project. - Line coverage does not mean every branch was tested:
if (b === 0)counts as covered once the line ran, whatever the condition was. - Running a subset of tests (
bun test math) lowers the numbers, because fewer files and lines run.
More test runner options, such as filters and watch mode, are in bun test.
FAQ
How do I upload bun test coverage to Codecov or Coveralls?
Run bun test --coverage --coverage-reporter=lcov. Bun writes coverage/lcov.info, the format those services and most CI coverage tools read.
Can bun test fail when coverage is too low?
Yes. Set coverageThreshold under [test] in bunfig.toml, either one number (0.9 for 90 percent) or separate values for lines and functions. bun test exits non-zero when coverage is below it.
Why are some files missing from the coverage table?
Bun reports only files that the tests loaded. A module no test imports does not appear at all, so 100 percent in the table does not mean every file in the project is tested.