Test Reporters

bun test supports different output formats through reporters, both built-in and custom.


Built-in Reporters#

Default Console Reporter#

By default, bun test outputs results to the console in a human-readable format:

terminal
test/package-json-lint.test.ts:
✓ test/package.json [0.88ms]
✓ test/js/third_party/grpc-js/package.json [0.18ms]
✓ test/js/third_party/svelte/package.json [0.21ms]
✓ test/js/third_party/express/package.json [1.05ms]

 4 pass
 0 fail
 4 expect() calls
Ran 4 tests across 1 file. [8.00ms]

When a terminal doesn't support colors, the output avoids non-ASCII characters:

terminal
test/package-json-lint.test.ts:
(pass) test/package.json [0.48ms]
(pass) test/js/third_party/grpc-js/package.json [0.10ms]
(pass) test/js/third_party/svelte/package.json [0.04ms]
(pass) test/js/third_party/express/package.json [0.04ms]

 4 pass
 0 fail
 4 expect() calls
Ran 4 tests across 1 file. [9.00ms]

Dots Reporter#

The dots reporter shows . for passing tests and prints full error details for failures, useful for large test suites.

terminal
bun test --dots
bun test --reporter=dots

JUnit XML Reporter#

For CI/CD environments, Bun can generate JUnit XML reports. JUnit XML is a widely-adopted test result format that many CI/CD systems can parse, including GitLab and Jenkins.

Using the JUnit Reporter#

To generate a JUnit XML report, use the --reporter=junit flag along with --reporter-outfile to specify the output file:

terminal
bun test --reporter=junit --reporter-outfile=./junit.xml

Console output is unchanged; Bun writes the JUnit XML report to the specified path at the end of the test run, and creates the folder if it doesn't exist.

The report omits characters that XML 1.0 doesn't allow, such as most control characters and U+FFFE.

Every test file that ran has a <testsuite>, even if it has no tests. Its timestamp is the time the file started, in the format of Date.prototype.toISOString().

An uncaught exception or unhandled rejection while a test is running fails that test, and its <failure>, <flakyFailure> or <rerunFailure> has uncaught="true". Examples are an error thrown by a timer and a rejected promise that the test didn't await. The attribute is absent when the test function itself throws, returns a promise that rejects, or calls done(error).

An error outside of any test is reported as a failed <testcase> named (unhandled error) in that file's <testsuite>. Examples are a test file or a preload script that throws while it loads, has a syntax error, or imports a module that doesn't exist.

With --parallel, a file whose worker crashed has a failed <testcase> named (worker crashed). The files that the crash kept from finishing or from starting have one named (aborted). After SIGINT or SIGTERM, a file that was running has one named (interrupted), and a file that hadn't started has one named (aborted).

Configuring via bunfig.toml#

You can also configure the JUnit reporter in bunfig.toml:

bunfig.toml
[test.reporter]
junit = "path/to/junit.xml"  # Output path for JUnit XML report

Describe Blocks in JUnit Reports#

By default, each describe block becomes a <testsuite> nested inside its file's <testsuite>. Some tools only read the <testcase> elements directly inside a file's <testsuite>. For those tools, use --reporter-junit-suites=flat:

terminal
bun test --reporter=junit --reporter-outfile=./junit.xml --reporter-junit-suites=flat
bunfig.toml
[test.reporter]
junit = "path/to/junit.xml"
junitSuites = "flat"  # "nested" (default) or "flat"

The report then has one <testsuite> per file. Each test's name is prefixed with its describe block names, and classname is the file:

junit.xml
<testsuite name="math.test.ts" file="math.test.ts" tests="1" ...>
  <testcase name="add &gt; negative numbers &gt; returns the sum" classname="math.test.ts" file="math.test.ts" line="5" ... />
</testsuite>

Retried tests#

A test with retry is one <testcase>, with its final result. The attempts before the last one are in the elements that Maven Surefire uses, which CI tools read to find flaky tests:

junit.xml
<testcase name="passes on the third attempt" ...>
  <flakyFailure type="Error" message="attempt 1">...</flakyFailure>
  <flakyFailure type="Error" message="attempt 2">...</flakyFailure>
</testcase>
<testcase name="never passes" ...>
  <failure type="Error" message="attempt 3">...</failure>
  <rerunFailure type="Error" message="attempt 1">...</rerunFailure>
  <rerunFailure type="Error" message="attempt 2">...</rerunFailure>
</testcase>

Environment Variables in JUnit Reports#

The JUnit reporter includes environment information as <properties> in the XML output, so you can tell which environment and commit a test run was for.

It includes the following environment variables when available:

Environment VariableProperty NameDescription
GITHUB_RUN_ID, GITHUB_SERVER_URL, GITHUB_REPOSITORY, CI_JOB_URLciCI build information
GITHUB_SHA, CI_COMMIT_SHA, GIT_SHAcommitGit commit identifiers
System hostnamehostnameMachine hostname

Current Limitations#

The JUnit reporter does not include:

  • stdout and stderr output from individual tests
  • Precise timestamp fields per test case

GitHub Actions reporter#

bun test detects when it's running inside GitHub Actions and emits GitHub Actions annotations to the console directly. No configuration is needed beyond installing Bun and running bun test.

For an example GitHub Actions workflow, see CI/CD integration.


Custom Reporters#

You can implement custom test reporters with Bun's testing-specific extensions to the WebKit Inspector Protocol, which report detailed information about test execution in real time.

Inspector Protocol for Testing#

Bun extends the standard WebKit Inspector Protocol with two custom domains:

  1. TestReporter: Reports test discovery, execution start, and completion events
  2. LifecycleReporter: Reports errors and exceptions during test execution

Key Events#

Custom reporters can listen for these events:

  • TestReporter.found: Emitted when a test is discovered
  • TestReporter.start: Emitted when a test starts running
  • TestReporter.end: Emitted when a test completes
  • Console.messageAdded: Emitted when console output occurs during a test
  • LifecycleReporter.error: Emitted when an error or exception occurs