# Share a Catch2 Report — Keep the Expression Decomposition

Canonical: https://commareports.com/share-catch2-report
Published: 2026-09-08

> Catch2's best feature is showing you the values inside a failing assertion. Convert its XML to HTML and publish to Comma so that detail reaches the reader intact.

# Share a Catch2 report

The reason people choose Catch2 is that its failures explain themselves:

```
tests/buffer.cpp:214: FAILED:
  REQUIRE( buf.read_u32(offset) == expected )
with expansion:
  3735928559 == 3405691582
```

That `with expansion` block is expression decomposition, and it is the single
most useful thing in a C++ test framework. It is also the first casualty of
every summarised report — a pass/fail count tells you a test broke, and Catch2
already told you exactly how.

Catch2 has no HTML reporter, so getting that detail to a colleague takes one
conversion step.

## Pick a reporter

```bash
# widest tool support
./tests --reporter junit --out results.xml

# richer: keeps section nesting and full expression detail
./tests --reporter xml --out results.xml

# multiple at once (Catch2 v3)
./tests --reporter junit::out=results.xml --reporter console::out=-
```

That last form is worth knowing: v3 lets you emit machine-readable XML *and*
keep human-readable console output in the same run, so the CI log stays useful
while the artifact gets produced.

## Convert and publish

```bash
npx xunit-viewer --results=results.xml --output=report.html
# or
pip install junit2html && junit2html results.xml report.html
```

Drag `report.html` into [the app](https://commareports.com/), or POST it:

```bash
curl -fsS -X POST "https://commareports.com/api/v1/reports" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html report.html \
        --arg t "Catch2 — libcore @ $(git rev-parse --short HEAD)" \
        '{title: $t, html: $html}')"
```

Check the rendered output for the expansion block before you send the link.
Some JUnit converters drop the failure message body in favour of the type
attribute; if yours does, switch to Catch2's `xml` reporter and a converter that
reads it, because without the expansion the report is much less useful than the
console output it replaced.

## Sections and scenarios

Catch2's SECTION mechanism re-runs the test body once per leaf, so a single
TEST_CASE can produce a dozen result rows that share a name. In BDD form:

```cpp
SCENARIO("buffer handles unaligned reads") {
  GIVEN("a buffer with a two-byte header") {
    WHEN("reading a u32 at offset 1") {
      THEN("the value is byte-swapped correctly") { … }
    }
  }
}
```

A converter that preserves nesting renders that as the tree it was written as.
A converter that flattens it produces twelve rows called "buffer handles
unaligned reads", which is worse than useless in a shared report — publish a
sample and look at it before wiring this into CI.

## From CI

```bash
./tests --reporter junit --out results.xml || TESTS_FAILED=1
npx xunit-viewer --results=results.xml --output=report.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 report.html \
        --arg t "Catch2 — $TOOLCHAIN @ $GITHUB_SHA" '{title: $t, html: $html}')"

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

Publish before exiting, with `if: always()` / `when: always` / `post { always }`
so a failing build still leaves the report behind. One report id per toolchain
gives each configuration a stable URL and its own revision history.

## What review adds

- **Anchored threads** on the failing case — see
  [commenting on HTML](/comment-on-html).
- **Revisions**, so an intermittent failure has a record.
- **Access per report** — private, team, domain-gated or named reviewers. See
  the [sharing model](/docs/sharing).

## Limits

- **Entry HTML: 5 MB.**
- **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 GoogleTest report](/share-gtest-report) · [Share a CTest report](/share-ctest-report)
- [Share a JUnit report](/share-junit-report) · [Share a coverage report](/share-coverage-report)
- [Share a Criterion benchmark report](/share-criterion-benchmark-report) · [Publish from CI](/docs/ci)
