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

# 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

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

Drag report.html into the app, or POST it:

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:

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

./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.
  • Revisions, so an intermittent failure has a record.
  • Access per report — private, team, domain-gated or named reviewers. See the sharing model.

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 →

Related