Free tool

Coverage files, as a report people can read.

Drop the lcov.info, coverage.xml or clover.xml your test run wrote. Get line, branch and function coverage, the least-covered files and their uncovered lines — then copy a Markdown summary for the pull request or send the report as a link.

lcov.info
1.1 KB4 files · lcov
Coverage report.html

63.1% lines · 64.2% branches · 66.6% functions · 14 uncovered lines

Publishes this report on Comma: one URL that opens on any phone, comments pinned to the file that needs tests, and the next run kept as a revision you can diff to see whether coverage moved. Free, no card.

How the file is read

  • LCOV: each SF: starts a file, DA:line,hits are lines, BRDA:line,block,branch,taken are branches (- means never reached) and FN/FNDA are functions. The LF/LH summary lines are ignored and recounted.
  • Cobertura: every <class filename="…"> is grouped by file; condition-coverage="50% (1/2)" gives the branches, and a <method> counts as covered when any of its lines was hit.
  • Clover: <line type="stmt"> and type="cond" are lines, truecount/falsecount are the two sides of each branch, and type="method" are functions.
  • Paths lose the directory every file shares, so /home/runner/work/shop/shop/src/cart/cart.ts reads cart/cart.ts under a cart directory row.

Getting the file

ToolWrites a coverage file with
Jestjest --coverage → coverage/lcov.info, coverage/clover.xml
Vitestvitest run --coverage --coverage.reporter=lcov
c8 / nycc8 --reporter=lcov npm test → coverage/lcov.info
pytest-covpytest --cov --cov-report=xml → coverage.xml (Cobertura)
coverage.pycoverage lcov (or coverage xml)
gcov / C++lcov --capture -d . -o coverage.info (or gcovr --xml)
Rustcargo llvm-cov --lcov --output-path lcov.info
Gogcov2lcov -infile=coverage.out -outfile=lcov.info
Flutterflutter test --coverage → coverage/lcov.info
.NETdotnet test --collect:"XPlat Code Coverage" → coverage.cobertura.xml
PHPUnitphpunit --coverage-clover clover.xml

When the coverage number should be a link

A coverage percentage in a CI log starts arguments; the list of files behind it ends them. Published to Comma, the report opens for anyone without a seat in your CI or a coverage SaaS, reviewers comment on the file that needs tests, and an agent can publish it from the pipeline on every run. For the full line-by-line source view, publish the genhtml or lcov-report folder instead — see how to share an lcov report. More on the format in what LCOV is and what code coverage measures.

Questions

How do I view an lcov.info file?
Drop it onto this page or paste its contents. It becomes a coverage report in your browser: line, branch and function percentages, a roll-up per directory, and every file sorted least-covered first with its uncovered line numbers. Nothing is uploaded, and there is no genhtml or Perl to install.
Which coverage formats does it read?
LCOV tracefiles (lcov.info, coverage.info), Cobertura XML (coverage.xml, cobertura.xml, Cobertura.xml) and Clover XML (clover.xml). Between them that covers Jest, Vitest, c8 and nyc/Istanbul, coverage.py and pytest-cov, gcov via lcov or gcovr, cargo-llvm-cov and grcov, Flutter, .NET coverlet, PHPUnit and JaCoCo through its Cobertura converter.
How are the percentages calculated?
From the line-level records, not from the summary numbers in the file. Lines: DA records (LCOV) or <line> elements (Cobertura, Clover) with a hit count above zero. Branches: BRDA records, Cobertura's condition-coverage, or Clover's truecount/falsecount. Functions: FN/FNDA records, Cobertura <method> elements with any hit line, or Clover method lines. Percentages are rounded down, so 99.96% shows as 99.9%, not 100%.
Why does my number differ from Codecov or Istanbul's summary?
Tools disagree on what counts. Istanbul reports statements, which this viewer doesn't see in LCOV. Codecov counts a line with a partly taken branch as a partial, not a hit. Some tools merge overlapping runs differently. Here a line is covered when any record in the file hit it, and a file that appears twice — several TN: blocks or split classes — is merged, so a line hit in either run counts.
Can I merge coverage from several test runs?
For LCOV, paste the tracefiles one after another; repeated SF: records for the same file are summed, the way lcov --add-tracefile does. Cobertura and Clover files are read one at a time.
Can I post the summary on a pull request?
Yes. “Copy Markdown” gives a GitHub-flavored table — line, branch and function coverage plus the fifteen least-covered files with their uncovered lines — that pastes into a PR comment or appends to $GITHUB_STEP_SUMMARY.
Is my coverage data uploaded?
No. The file is parsed and the report is built in your browser. It only leaves your machine if you click “Get a shareable link” and publish the report to Comma.

Related: JUnit XML viewer · SARIF viewer · share a coverage report · coverage report links broken · all free tools