# Line coverage vs branch coverage > Line coverage asks whether each line ran; branch coverage asks whether each decision went both ways. A measured example, and why tools count differently. Web page: https://supercov.com/compare/line-vs-branch-coverage · Published 2026-10-12 All Supercov pages for agents: https://supercov.com/llms.txt · Full text: https://supercov.com/llms-full.txt ## What is the difference? Line coverage asks whether each line ran. Branch coverage asks whether each decision went each way. A line can run while one of its branches never does, so 100% line coverage can hide untested paths. Track both. If you enforce one threshold, enforce branches. ## A line that ran, a branch that did not ```js function label(user, fallback = 'Guest') { return user ? user.name : fallback; } ``` One test calls `label({ name: 'Ada' })`. The `return` line ran, so line coverage is 100%. The function never returned `fallback`, and line coverage cannot say so. Branch coverage reports one branch missing on that line. We measured this with Jest 30.5.2 and its default Babel provider, on a file with this function and one more: 5/5 lines, 6/7 branches. The missing branch is `fallback`. ## Statement and function coverage - **Statement coverage** counts statements instead of lines. The two differ when one line holds several statements or one statement spans several lines. - **Function coverage** asks whether each function was called at all. Istanbul-based tools report all four. Many others report lines and branches. ## Tools do not count branches the same way The same three tests on the same JavaScript file: | Tool | Lines | Branches | | --- | --- | --- | | Jest, Babel provider | 5/5 | 6/7 | | Jest, V8 provider | 14/17 | 4/5 | | `node --test`, built-in coverage | 14/17 | 5/6 | All three agree on which branch is missing. They disagree on how many branches and lines exist. Other languages differ again: - coverage.py counts a branch only when a line can jump to more than one next line. The Python version of `label`, on one line, reported 6/6 lines and 2/2 branches with `fallback` never returned. - `go test -cover` reports statements and has no branch metric. - JaCoCo counts branches in bytecode, where each condition of an `&&` is its own jump. Compare a branch percentage with the same tool's earlier number, not with another tool's. ## What branch coverage still misses ```js if (signedIn && !expired) { ``` Two tests can take this `if` both ways without ever trying a signed-in session that has expired. Branch coverage is 100%. [MC/DC](https://supercov.com/compare/mcdc-vs-branch-coverage.md) is the metric that catches it. Neither metric says whether a test checked the result. A test can run every branch and assert nothing. ## Measure them on your tests ```sh npx supercov -- npm test npx supercov runs latest gaps ``` Supercov runs your existing test command and reports line, branch and MC/DC coverage per test, for JavaScript, TypeScript, Python, Go, Java, Kotlin, Rust and Ruby. On the JavaScript file above it reported 7/9 lines, 4/6 branches and 1/3 MC/DC conditions. [Assertion coverage](https://supercov.com/docs/assertions.md) then shows which executed statements your tests check. Example evidence: [fixture source, commands and recorded results (JSON)](https://supercov.com/downloads/tool-comparisons-2026-10-12.json). Measured October 12, 2026 with Supercov 4.3.0. These small examples are not a performance benchmark or a general conformance test.