skills/bun-test-code-coverage/SKILL.md
Learn how to use Bun's built-in code coverage reporting to track test coverage and find untested areas in your codebase
npx skillsauth add jarle/bun-skills Bun Code coverageInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Learn how to use Bun's built-in code coverage reporting to track test coverage and find untested areas in your codebase
Bun's test runner now supports built-in code coverage reporting. This makes it easy to see how much of the codebase is covered by tests, and find areas that are not currently well-tested.
bun:test supports seeing which lines of code are covered by tests. To use this feature, pass --coverage to the CLI. It will print out a coverage report to the console:
bun test --coverage
-------------|---------|---------|-------------------
File | % Funcs | % Lines | Uncovered Line #s
-------------|---------|---------|-------------------
All files | 38.89 | 42.11 |
index-0.ts | 33.33 | 36.84 | 10-15,19-24
index-1.ts | 33.33 | 36.84 | 10-15,19-24
index-10.ts | 33.33 | 36.84 | 10-15,19-24
index-2.ts | 33.33 | 36.84 | 10-15,19-24
index-3.ts | 33.33 | 36.84 | 10-15,19-24
index-4.ts | 33.33 | 36.84 | 10-15,19-24
index-5.ts | 33.33 | 36.84 | 10-15,19-24
index-6.ts | 33.33 | 36.84 | 10-15,19-24
index-7.ts | 33.33 | 36.84 | 10-15,19-24
index-8.ts | 33.33 | 36.84 | 10-15,19-24
index-9.ts | 33.33 | 36.84 | 10-15,19-24
index.ts | 100.00 | 100.00 |
-------------|---------|---------|-------------------
To always enable coverage reporting by default, add the following line to your bunfig.toml:
[test]
# Always enable coverage
coverage = true
By default coverage reports will include test files and exclude sourcemaps. This is usually what you want, but it can be configured otherwise in bunfig.toml.
[test]
coverageSkipTestFiles = true # default false
It is possible to specify a coverage threshold in bunfig.toml. If your test suite does not meet or exceed this threshold, bun test will exit with a non-zero exit code to indicate the failure.
[test]
# To require 90% line-level and function-level coverage
coverageThreshold = 0.9
[test]
# To set different thresholds for lines and functions
coverageThreshold = { lines = 0.9, functions = 0.9, statements = 0.9 }
Setting any of these thresholds enables fail_on_low_coverage, causing the test run to fail if coverage is below the threshold.
By default, coverage reports will be printed to the console.
For persistent code coverage reports in CI environments and for other tools, you can pass a --coverage-reporter=lcov CLI option or coverageReporter option in bunfig.toml.
[test]
coverageReporter = ["text", "lcov"] # default ["text"]
coverageDir = "path/to/somewhere" # default "coverage"
| Reporter | Description |
| -------- | ---------------------------------------------------- |
| text | Prints a text summary of the coverage to the console |
| lcov | Save coverage in lcov format |
To generate an lcov report, you can use the lcov reporter. This will generate an lcov.info file in the coverage directory.
[test]
coverageReporter = "lcov"
# Or via CLI
bun test --coverage --coverage-reporter=lcov
The LCOV format is widely supported by various tools and services:
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
By default, test files themselves are included in coverage reports. You can exclude them with:
[test]
coverageSkipTestFiles = true # default false
This will exclude files matching test patterns (e.g., *.test.ts, *.spec.js) from the coverage report.
You can exclude specific files or file patterns from coverage reports using coveragePathIgnorePatterns:
[test]
# Single pattern
coveragePathIgnorePatterns = "**/*.spec.ts"
# Multiple patterns
coveragePathIgnorePatterns = [
"**/*.spec.ts",
"**/*.test.ts",
"src/utils/**",
"*.config.js"
]
This option accepts glob patterns and works similarly to Jest's collectCoverageFrom ignore patterns. Files matching any of these patterns will be excluded from coverage calculation and reporting in both text and LCOV outputs.
[test]
coveragePathIgnorePatterns = [
# Exclude utility files
"src/utils/**",
# Exclude configuration files
"*.config.js",
"webpack.config.ts",
"vite.config.ts",
# Exclude specific test patterns
"**/*.spec.ts",
"**/*.e2e.ts",
# Exclude build artifacts
"dist/**",
"build/**",
# Exclude generated files
"src/generated/**",
"**/*.generated.ts",
# Exclude vendor/third-party code
"vendor/**",
"third-party/**"
]
Internally, Bun transpiles all files by default, so Bun automatically generates an internal source map that maps lines of your original source code onto Bun's internal representation. If for any reason you want to disable this, set test.coverageIgnoreSourcemaps to true; this will rarely be desirable outside of advanced use cases.
[test]
coverageIgnoreSourcemaps = true # default false
<Warning>
When using this option, you probably want to stick a `// @bun` comment at the top of the source file to opt out of the
transpilation process.
</Warning>
By default, coverage reports:
node_modules directories.css, .txt) unless a custom JS loader is specifiedcoverageSkipTestFiles = true)coveragePathIgnorePatterns[test]
coverageDir = "coverage-reports" # default "coverage"
[test]
coverageReporter = ["text", "lcov"]
# Run coverage only on specific test files
bun test --coverage src/components/*.test.ts
# Run coverage with name pattern
bun test --coverage --test-name-pattern="API"
name: Coverage Report
on: [push, pull_request]
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: bun install
- name: Run tests with coverage
run: bun test --coverage --coverage-reporter=lcov
- name: Upload to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage/lcov.info
fail_ci_if_error: true
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
-------------|---------|---------|-------------------
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
-------------|---------|---------|-------------------
// Good: Test actual functionality
test("calculateTax should handle different tax rates", () => {
expect(calculateTax(100, 0.08)).toBe(8);
expect(calculateTax(100, 0.1)).toBe(10);
expect(calculateTax(0, 0.08)).toBe(0);
});
// Avoid: Just hitting lines for coverage
test("calculateTax exists", () => {
calculateTax(100, 0.08); // No assertions!
});
test("user input validation", () => {
// Test normal case
expect(validateEmail("[email protected]")).toBe(true);
// Test edge cases that improve coverage meaningfully
expect(validateEmail("")).toBe(false);
expect(validateEmail("invalid")).toBe(false);
expect(validateEmail(null)).toBe(false);
});
# Run coverage to identify untested code
bun test --coverage
# Look at specific files that need attention
bun test --coverage src/critical-module.ts
Coverage is just one metric. Also consider:
If files aren't appearing in coverage reports, they might not be imported by your tests. Coverage only tracks files that are actually loaded.
// Make sure to import the modules you want to test
import { myFunction } from "../src/my-module";
test("my function works", () => {
expect(myFunction()).toBeDefined();
});
If you see coverage reports that don't match your expectations:
coveragePathIgnorePatternsFor large projects, coverage collection can slow down tests:
[test]
# Exclude large directories you don't need coverage for
coveragePathIgnorePatterns = [
"node_modules/**",
"vendor/**",
"generated/**"
]
Consider running coverage only on CI or specific branches rather than every test run during development.
development
Using TypeScript with Bun, including type definitions and compiler options
development
Learn how to write tests using Bun's Jest-compatible API with support for async tests, timeouts, and various test modifiers
testing
Learn how to use snapshot testing in Bun to save and compare output between test runs
testing
Learn about Bun test's runtime integration, environment variables, timeouts, and error handling