# Share a Bun Test Report — A Link Instead of a CI Log

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

> bun test has no HTML reporter. Turn its JUnit or lcov output into a report and publish it to Comma: one URL per suite, comments on failures, a revision per run.

# Share a Bun test report

Bun's test runner is fast enough that the run stops being the bottleneck. What
is left as the bottleneck is everything after the run: the failure is in a CI
log, the log needs a login, and the person who can explain the failure is the
one without the login.

`bun test` has no HTML reporter — deliberately, it is a terminal tool — so the
path to a link is a one-step conversion.

## Two artifacts worth publishing

**Results.** Bun emits JUnit XML, the format every other tool in this space
speaks:

```bash
bun test --reporter=junit --reporter-outfile=./junit.xml
npx junit2html junit.xml results.html
```

**Coverage.** Bun's coverage writes lcov, which `genhtml` turns into the
familiar drill-down tree:

```bash
bun test --coverage --coverage-reporter=lcov --coverage-dir=coverage
genhtml coverage/lcov.info -o coverage-html
```

The coverage tree is the one that gains most from being a URL: its whole value
is clicking from a directory to a file to the uncovered lines, and that is
exactly what a screenshot of a percentage removes.

## Publish it

Drag `results.html` — or the whole `coverage-html/` folder — into
[Comma](https://commareports.com/). For a folder, `index.html` becomes the
report body and the per-file pages upload alongside it, with relative
references rewritten to the uploaded copies, so the drill-down keeps working.

From CI:

```bash
bun test --reporter=junit --reporter-outfile=./junit.xml || TEST_FAILED=1
npx junit2html junit.xml results.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 results.html \
        --arg t "Tests — $GITHUB_REF_NAME" '{title: $t, html: $html}')"

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

Capturing the exit code and re-raising it after the publish is the pattern that
matters: publish first, fail second, or the red run — the only one anybody
needs — never gets a link. See [publishing from CI](/docs/ci) and the
[API reference](/docs/api).

## The failing test is a conversation

A failed assertion in a log gets a screenshot pasted into a channel, and the
thread that follows has no connection to the run it is about. Published, the
run has a URL, and the thread is anchored on the assertion — including the
"this is flaky, third time this week" that is worth recording as a pattern
rather than as a shrug. See [commenting on HTML](/comment-on-html).

PATCHing one report id keeps a permanent URL and appends a revision per run, so
"when did this start failing?" is answerable by opening the link rather than by
hunting through expired artifacts. Compare
[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. See [sharing & access control](/docs/sharing).

## Limits

- **Entry HTML: 5 MB.** Assets: 25 MB per file, **250 MB and 500 files total**.
- **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 test report →](https://commareports.com/)**

### Related

- [Share a Vitest report](/share-vitest-report) · [Share a Jest report](/share-jest-report)
- [Share a Deno test report](/share-deno-test-report) · [Share a JUnit report](/share-junit-report)
- [Share a coverage report](/share-coverage-report) · [Share an lcov report](/share-lcov-report)
