Skip to main content
Bun’s test runner includes built-in code coverage support. Generate coverage reports to see which lines of your code are tested.

Basic usage

Generate a coverage report:
$ bun test --coverage
This runs all tests and displays a coverage summary:
---------------|---------|---------|-------------------
File           | % Funcs | % Lines | Uncovered Line #s
---------------|---------|---------|-------------------
All files      |   85.71 |   88.89 |
 math.ts        |  100.00 |  100.00 |
 utils.ts       |   75.00 |   83.33 | 12-15, 23
---------------|---------|---------|-------------------

Coverage reporters

Bun supports multiple coverage output formats.

Text reporter (default)

Displays coverage in a table format:
$ bun test --coverage --coverage-reporter text

LCOV reporter

Generates an LCOV file that can be used with coverage visualization tools:
$ bun test --coverage --coverage-reporter lcov
This creates coverage/lcov.info.

Multiple reporters

Use multiple reporters at once:
$ bun test --coverage --coverage-reporter text --coverage-reporter lcov

Coverage directory

By default, coverage files are written to ./coverage. Change this:
$ bun test --coverage --coverage-dir my-coverage

Configuration

Configure coverage in bunfig.toml:
[test]
coverageReporter = ["text", "lcov"]
coverageDir = "./coverage"
coverageSkipTestFiles = true

Excluding test files

Exclude test files from coverage reports:
[test]
coverageSkipTestFiles = true

Ignore patterns

Exclude files from coverage using glob patterns:
[test]
coveragePathIgnorePatterns = [
  "node_modules",
  "*.config.ts",
  "test/fixtures",
  "**/*.mock.ts"
]

Coverage thresholds

Fail tests if coverage is below a threshold:
[test.coverageThreshold]
line = 80
function = 80
statement = 80
branch = 80
Tests will fail if any metric is below the threshold:
$ bun test --coverage
Error: Coverage for lines (75%) does not meet threshold (80%)

Viewing LCOV reports

With lcov tools

Generate an HTML report:
$ bun test --coverage --coverage-reporter lcov
$ genhtml coverage/lcov.info -o coverage/html
$ open coverage/html/index.html

With VS Code

Install the Coverage Gutters extension:
  1. Generate LCOV report: bun test --coverage --coverage-reporter lcov
  2. Open a file
  3. Click “Watch” in the status bar
  4. Coverage highlights appear in the gutter

With online tools

Upload lcov.info to coverage services:

Understanding coverage metrics

Line coverage

Percentage of lines executed:
function add(a: number, b: number) {
  return a + b; // Covered if function is called
}

Function coverage

Percentage of functions called:
function used() {
  return 1; // Covered
}

function unused() {
  return 2; // Not covered
}

used();

Branch coverage

Percentage of branches taken:
function check(x: number) {
  if (x > 0) {
    return "positive"; // Branch 1
  } else {
    return "negative"; // Branch 2
  }
}

check(5); // Only branch 1 covered

Statement coverage

Percentage of statements executed:
const x = 1; // Statement 1 - covered
const y = 2; // Statement 2 - covered
const z = 3; // Statement 3 - not covered if return happens before

Improving coverage

Identify uncovered code

Look at the “Uncovered Line #s” column:
utils.ts       |   75.00 |   83.33 | 12-15, 23
Lines 12-15 and 23 are not covered.

Add tests for uncovered branches

import { test, expect } from "bun:test";

function divide(a: number, b: number) {
  if (b === 0) {
    throw new Error("Division by zero");
  }
  return a / b;
}

test("divide - normal case", () => {
  expect(divide(10, 2)).toBe(5);
});

// Add test for error branch
test("divide - by zero", () => {
  expect(() => divide(10, 0)).toThrow("Division by zero");
});

Use coverage thresholds

Enforce minimum coverage in CI:
[test.coverageThreshold]
line = 80
function = 80

CI Integration

GitHub Actions

name: Test with Coverage

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: oven-sh/setup-bun@v1
      
      - run: bun install
      - run: bun test --coverage --coverage-reporter lcov
      
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          files: ./coverage/lcov.info

GitLab CI

test:
  script:
    - bun install
    - bun test --coverage --coverage-reporter lcov
  coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/lcov.info

Best practices

Don’t obsess over 100% coverage

100% coverage doesn’t guarantee bug-free code. Focus on testing critical paths and edge cases.

Exclude generated code

Exclude auto-generated files from coverage:
[test]
coveragePathIgnorePatterns = ["generated/", "*.g.ts"]

Test behavior, not coverage

Write tests for expected behavior, not just to increase coverage numbers.

Review coverage regularly

Make coverage part of code review:
# Before committing
$ bun test --coverage

Troubleshooting

No coverage output

Ensure you’re using --coverage:
$ bun test --coverage

Incorrect coverage data

Clear the coverage cache:
$ rm -rf coverage/
$ bun test --coverage

Coverage not excluding files

Check your coveragePathIgnorePatterns in bunfig.toml:
[test]
coveragePathIgnorePatterns = ["node_modules/**", "test/**"]

Build docs developers (and LLMs) love