Skip to content

Repository files navigation

GitHub Workflow Status Codecov

title

What is it?

Xcode-like HTML report for Unit and UI Tests

▶ Open a live report — rendered from this repository's own sample test run, republished on every merge to main. Past releases are at /v/.

screenshot

Features

  • Supports parallel testing
  • Supports attachments:
    • .png
    • .jpeg
    • .heic
    • .txt
    • .log
    • .mp4
    • .gif
  • Navigate through the report with the keyboard's arrow keys
  • Filter out successful, failed, skipped, or mixed-result tests
  • Displays information about the target device
  • Displays activity logs
  • Junit report(-j flag)
  • Json report(--json flag)
  • Shrink bundle size by removing unattached files
  • Automatically convert heic images to browser-friendly format
  • Render as a single html file with inline attachments or as a bundle
  • Downsize image attachments

Installation

Homebrew (recommended)

Install via Homebrew

Install latest stable version

brew install xctesthtmlreport

Install latest from main branch

brew install xctesthtmlreport --HEAD

Mint

Install via Mint

Install latest stable version

mint install XCTestHTMLReport/XCTestHTMLReport

Install latest from main branch

mint install XCTestHTMLReport/XCTestHTMLReport@main

Usage

Run your UI tests using xcodebuild without forgetting to specify the resultBundlePath

$ xcodebuild test -workspace XCTestHTMLReport.xcworkspace -scheme SampleApp -destination 'platform=iOS Simulator,name=iPhone 14,OS=16.0' -resultBundlePath TestResults

Then use the previously downloaded xchtmlreport tool to create the HTML report. Additionally, -i flag is also available to inline all resources, this is convenient for exporting the html file standalone. HTML file will be much heavier but much more portable.

$ xchtmlreport TestResults.xcresult

Report successfully created at ./index.html

Multiple Result Bundle Path

$ xchtmlreport TestResults1 TestResults2

Report successfully created at ./index.html

This will create only one HTML Report in the path you passed with the -r option

Generate Junit Reports

You can generate junit reports with the -j flag

$ xchtmlreport -j TestResults1

Report successfully created at ./index.html

JUnit report successfully created at report.junit

Generate JSON Reports

You can generate json reports with the --json flag

$ xchtmlreport --json TestResults1

Report successfully created at ./index.html

JSON report successfully created at ./report.json

Starting in 4.0, report.json is our own documented, versioned schema — docs/json-schema.md is the contract. The schema is identical whichever result reader produced it: same keys, same nesting, same schemaVersion. A few values legitimately differ between readers — the four differences listed under "Choosing the result reader" below, plus testCase.arguments, which only the modern reader can populate — and the contract documents each one. Earlier versions dumped xcresulttool's legacy object graph verbatim; that graph is Apple's internal shape and disappears together with the legacy commands, so 4.0 replaces it once, deliberately. The change is visible at a glance — before:

[{"_type":{"_name":"ActionsInvocationRecord"},"actions":{"_type":{"_name":"Array"},"_values":[...

after:

{
  "runs" : [ ... ],
  "schemaVersion" : "1.0.0"
}

Consumers should read schemaVersion first and follow the version policy in the contract document.

Choosing the result reader

xcresulttool's legacy API — the way every version before 4.0 read result bundles — is deprecated and will be removed from Xcode. xchtmlreport now has two readers and picks one per run:

$ xchtmlreport --result-reader auto TestResults.xcresult    # the default
  • auto prefers legacy while the toolchain still offers the legacy commands, and falls back to modern once they are gone (or when the probe cannot tell).
  • modern forces the new-format reader on any toolchain.
  • legacy forces the legacy reader; if the toolchain no longer provides the legacy commands this is an error, never a silent substitution.

The XCHR_RESULT_READER environment variable sets the default when the flag is absent — useful for forcing a whole CI job onto one reader.

Reports from the two readers are held byte-identical by a differential test suite, up to a short declared list of differences the new format cannot avoid:

  • Attachment display names. The new format does not expose the user-supplied XCTAttachment name, so the modern reader labels attachments by their type (Screenshot, Video, File).
  • Failure title prefixes. Legacy renders Assertion Failure at File.swift:12: message; modern renders File.swift:12: message — the new format pre-joins the string and drops the issue type.
  • Wrapper groups. Legacy nests two extra levels (All tests / Selected tests, then <target>.xctest) that the new format does not have; the modern reader renders the natural flat tree.
  • Group durations. The new format reports no duration for test suites and bundles, so the modern reader shows (0.00s) where legacy shows a real value.

--json output additionally carries testCase.arguments (Swift Testing @Test(arguments:) values), which only the modern reader can populate — the legacy format has no counterpart, so it is always [] there. See the schema contract for how consumers should compare reports across readers.

Exit codes

Code Meaning
0 No faults detected
1 The report could not be written
3 Report was generated but is degraded — some of the result bundle could not be fully processed
64 Invalid arguments

Starting in 3.0, xchtmlreport exits non-zero when part of a result bundle cannot be turned into a report. Earlier versions exited 0 and printed a success message even when parts of the report were missing, so pipelines had no way to detect an incomplete report.

Exit 0 means no faults were detected, which is not yet the same as a guaranteed complete report: some XCResultKit decode failures are not surfaced as faults today and are still only visible as messages on stderr. See #378 and the follow-on work it tracks.

Exit 1 covers failures to write the output — for example -o pointing at a directory that does not exist.

The report is still written when faults occur. To restore the pre-3.0 behaviour and always exit 0 on faults, pass --lenient. --lenient does not affect exit 1 or 64.

Fastlane Support

https://github.com/TitouanVanBelle/fastlane-plugin-xchtmlreport

Contribution

Please create an issue whenever you find an issue or think a feature could be a good addition to XCTestHTMLReport. Always make sure to follow the Contributing Guidelines. Feel free to take a shot at these issues.

Special Thanks

Thank you to the original author of this tool, TitouanVanBelle! 🥳🎉

License

XCTestHTMLReport is available under the MIT license.

About

Xcode-like HTML report for Unit and UI Tests

Topics

Resources

Code of conduct

Contributing

Stars

771 stars

Watchers

16 watching

Forks

Releases

Used by

Contributors

Languages