> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/oven-sh/bun/llms.txt
> Use this file to discover all available pages before exploring further.

# Code Coverage

> Generate coverage reports with bun test --coverage to find untested code, enforce thresholds, and integrate with CI/CD pipelines.

Bun has built-in code coverage reporting. Pass `--coverage` to see which lines and functions are exercised by your tests.

## Enabling coverage

```bash theme={null}
bun test --coverage
```

Bun prints a coverage summary to the console after the test run:

```
-------------|---------|---------|-------------------
File         | % Funcs | % Lines | Uncovered Line #s
-------------|---------|---------|-------------------
All files    |   85.71 |   90.48 |
 src/         |   85.71 |   90.48 |
  utils.ts   |  100.00 |  100.00 |
  api.ts     |   75.00 |   85.71 | 15-18,25
  main.ts    |   80.00 |   88.89 | 42,50-52
-------------|---------|---------|-------------------
```

* **% Funcs** — percentage of functions called during tests
* **% Lines** — percentage of executable lines that were run
* **Uncovered Line #s** — specific lines that were not executed

### Always-on coverage

Enable coverage by default in `bunfig.toml`:

```toml bunfig.toml theme={null}
[test]
coverage = true
```

## Coverage thresholds

Fail the test run if coverage falls below a specified level. This is useful in CI to enforce minimum quality gates.

### Simple threshold

Apply the same threshold to lines, functions, and statements:

```toml bunfig.toml theme={null}
[test]
coverageThreshold = 0.9   # 90% across all metrics
```

### Per-metric thresholds

Set different thresholds for each coverage metric:

```toml bunfig.toml theme={null}
[test]
coverageThreshold = { lines = 0.85, functions = 0.90, statements = 0.80 }
```

When any threshold is configured, `bun test` exits with a non-zero code if coverage is below the threshold.

## Coverage reporters

By default, coverage is printed as a text table. Use `coverageReporter` to add additional output formats:

```toml bunfig.toml theme={null}
[test]
coverageReporter = ["text", "lcov"]
coverageDir = "./coverage"   # default: "coverage"
```

| Reporter | Description                                          |
| -------- | ---------------------------------------------------- |
| `text`   | Prints a summary table to the console (default)      |
| `lcov`   | Writes an `lcov.info` file to the coverage directory |

Via CLI:

```bash theme={null}
bun test --coverage --coverage-reporter=lcov
```

### LCOV integration

The LCOV format is supported by a wide range of tools:

<CardGroup cols={2}>
  <Card title="VS Code" icon="code">
    Extensions like Coverage Gutters can display coverage inline in the editor using the `lcov.info` file.
  </Card>

  <Card title="Codecov / Coveralls" icon="chart-bar">
    Upload `coverage/lcov.info` as a coverage artifact to track coverage trends over time.
  </Card>

  <Card title="GitHub Actions" icon="github">
    Use the `codecov/codecov-action` to upload and comment on PRs automatically.
  </Card>

  <Card title="GitLab CI" icon="gitlab">
    Configure `coverage_report` artifacts to display coverage in merge requests.
  </Card>
</CardGroup>

## Excluding files from coverage

### Skip test files

By default, test files themselves are included in the coverage report. Exclude them with:

```toml bunfig.toml theme={null}
[test]
coverageSkipTestFiles = true
```

### Path ignore patterns

Exclude specific files or directories using glob patterns:

```toml bunfig.toml theme={null}
[test]
coveragePathIgnorePatterns = [
  "**/*.spec.ts",
  "**/*.test.ts",
  "src/generated/**",
  "dist/**",
  "vendor/**",
  "*.config.ts"
]
```

Files matching any pattern are excluded from both the text summary and any generated report files.

## CI/CD integration

### GitHub Actions

```yaml .github/workflows/test.yml theme={null}
name: Test with Coverage
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      - run: bun test --coverage --coverage-reporter=lcov
      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v3
        with:
          file: ./coverage/lcov.info
          fail_ci_if_error: true
```

### GitLab CI

```yaml .gitlab-ci.yml theme={null}
test:coverage:
  stage: test
  script:
    - bun install
    - bun test --coverage --coverage-reporter=lcov
  coverage: '/Lines\s*:\s*(\d+.\d+)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/lcov.info
```

## Running coverage on a subset of tests

Run coverage for specific files or patterns:

```bash theme={null}
# Coverage for a specific test file
bun test --coverage src/api.test.ts

# Coverage for tests matching a name pattern
bun test --coverage --test-name-pattern="API"
```

## Sourcemaps

Bun transpiles all files internally and automatically applies sourcemaps so that coverage reports reference your original source lines. To disable this (rarely needed):

```toml bunfig.toml theme={null}
[test]
coverageIgnoreSourcemaps = true
```

<Warning>
  When disabling sourcemaps, add `// @bun` at the top of source files to opt out of transpilation, otherwise line numbers will be confusing.
</Warning>

## Coverage defaults

By default, coverage reports:

* **Exclude** `node_modules` directories
* **Exclude** files loaded through non-JS/TS loaders (e.g., `.css`, `.txt`)
* **Include** test files (disable with `coverageSkipTestFiles = true`)

## Best practices

<AccordionGroup>
  <Accordion title="Focus on quality, not just percentage">
    High coverage does not guarantee good tests. Write assertions that verify behavior, not just lines that execute without throwing.

    ```typescript theme={null}
    // Good: validates actual behavior
    test("calculates tax correctly", () => {
      expect(calculateTax(100, 0.08)).toBe(8);
      expect(calculateTax(0, 0.08)).toBe(0);
    });

    // Avoid: executes lines without asserting anything
    test("calculateTax runs", () => {
      calculateTax(100, 0.08); // no expect!
    });
    ```
  </Accordion>

  <Accordion title="Test edge cases to increase meaningful coverage">
    ```typescript theme={null}
    test("validates email format", () => {
      expect(validateEmail("user@example.com")).toBe(true);
      expect(validateEmail("")).toBe(false);          // empty string
      expect(validateEmail("nodomain")).toBe(false);   // missing @
      expect(validateEmail(null)).toBe(false);         // null input
    });
    ```
  </Accordion>

  <Accordion title="Use coverage to find gaps, not as the goal">
    Run `bun test --coverage` periodically to identify untested branches. Use the uncovered line numbers to guide where to add tests next.
  </Accordion>

  <Accordion title="Only run coverage in CI for large projects">
    Coverage instrumentation adds overhead. For fast feedback during development, run tests without `--coverage` and let CI enforce thresholds.
  </Accordion>
</AccordionGroup>
