# Share a Deno Test Report — Coverage and Results at a URL

Canonical: https://commareports.com/share-deno-test-report
Published: 2026-09-14

> deno test writes lcov and JUnit, not HTML. Convert once, publish to Comma, and hand over a link: coverage drill-down intact, comments on failures, a revision per run.

# Share a Deno test report

Deno ships a test runner, a coverage tool and a formatter in the binary, which
removes most of the setup other ecosystems spend a week on. It does not remove
the last step, which is the one that actually costs a team time: getting the
result in front of someone who is not sitting at a terminal.

## Coverage, two ways

The short one:

```bash
deno test --coverage=cov_profile
deno coverage cov_profile --html      # → cov_profile/html/
```

The lcov one, if you already have tooling that speaks it:

```bash
deno coverage cov_profile --lcov --output=cov.lcov
genhtml cov.lcov -o coverage-html
```

Either way you end with a folder: an index listing files by coverage, and a
page per file with the uncovered lines marked. That structure is the whole
point — coverage is read by clicking down into the file you suspect, which is
the one thing a percentage in a CI log cannot support.

## Results

```bash
deno test --reporter=junit --junit-path=./junit.xml
npx junit2html junit.xml results.html
```

## Publish it

Drag the coverage folder (or a zip of it) into
[Comma](https://commareports.com/):

- `index.html` becomes the **report body**.
- Per-file pages and the stylesheet upload alongside it, with relative
  references rewritten to the uploaded copies, so the drill-down resolves —
  which is the step that fails when the folder is zipped and emailed, because a
  `file://` origin breaks the relative fetches. See
  [coverage report links broken](/fix/coverage-report-links-broken).
- Scripts run inside a sandboxed iframe (`allow-scripts`, no
  `allow-same-origin`).

## From CI

```bash
deno test --coverage=cov_profile || FAILED=1
deno coverage cov_profile --html

curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html cov_profile/html/index.html \
        --arg t "Coverage — $(git rev-parse --short HEAD)" '{title: $t, html: $html}')"

exit "${FAILED:-0}"
```

Publish first, fail second. Supporting pages go up through
`POST /api/v1/reports/$REPORT_ID/assets` as base64 — see the
[API reference](/docs/api) and [publishing from CI](/docs/ci).

## One link, a revision per run

PATCHing a saved report id keeps the URL constant while the content tracks the
default branch. Each publish appends a revision, so a coverage drop is visible
as a diff between two runs instead of as a number somebody remembers being
higher. Unlike a CI artifact, it does not expire — see
[expired CI artifacts](/fix/ci-artifact-expired).

## Who can see it

Per report: private, your team, anyone signed in at your domain, or anyone with
the link. Coverage output contains source — team access is the usual setting.
See [sharing & access control](/docs/sharing).

## Limits

- **Entry HTML: 5 MB.** Assets: 25 MB per file, **250 MB and 500 files total**.
  A large module tree can exceed 500 files — publish the index plus the
  directories under active work.
- **Scripts run, sandboxed** — no same-origin access.
- **60 requests/minute per token.**

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision
history.

**[Publish a coverage report →](https://commareports.com/)**

### Related

- [Share a Bun test report](/share-bun-test-report) · [Share a Vitest report](/share-vitest-report)
- [Share an lcov report](/share-lcov-report) · [Share a coverage report](/share-coverage-report)
- [Share a JUnit report](/share-junit-report) · [Publishing from CI](/docs/ci)
