Generate static HTML reports from XCTest .xcresult bundles.
- Builds an
index.htmlsuite overview and per-test detail pages. - Renders timeline + scrubber + media previews for test activities.
- Exports attachments and supports video, image, text, and plist preview flows.
- Compares against previous report folders in the same parent directory.
- Keeps heavy web payloads compressed to reduce output size.
- macOS with Xcode command-line tools (
xcrun xcresulttool). - Swift 5.5+ (SwiftPM build).
- Optional:
ffmpegfor--compress-video. - Optional:
gzipfor extra payload compression (fallbacks are automatic).
git clone https://github.com/lapfelix/xctestreport.git
cd xctestreport
swift build -c release
cp .build/release/xctestreport /usr/local/bin/xctestreportUSAGE: xctestreport <xcresult-path> <output-dir> [--compress-video] [--video-height <video-height>]
ARGUMENTS:
<xcresult-path> Path to the .xcresult file.
<output-dir> Output directory for the HTML report.
OPTIONS:
--compress-video Compress exported video attachments with ffmpeg (HEVC VideoToolbox).
--video-height <n> Maximum compressed video dimension (longest edge). Default: 1024.
-h, --help Show help information.swift run xctestreport /path/to/Test.xcresult ~/Desktop/xcresultout --compress-video --video-height 1024
open ~/Desktop/xcresultout/index.htmlindex.html is always written at <output-dir>/index.html.
- Uses
ffmpegwhen available. - Tries hardware first (
hevc_videotoolbox), then falls back tolibx264if needed. - Preserves aspect ratio and constrains the longest edge to
--video-height. - Replaces the original exported video only when output is valid and smaller.
- If
ffmpegis missing, logs a skip and continues report generation.
- Detects binary plist attachments (
bplist00). - Generates text previews via
plutil -p. - Gzip-compresses preview text and stores it as
<original-name>.gzwhen smaller. - Browser decompresses on demand with
DecompressionStream.
- Timeline run-state and screenshot payloads are compact-encoded JSON, then gzip-compressed.
- Stored under
timeline_payloads/*.binand loaded lazily bytimeline-view.js. - If compression fails, falls back to inline JSON in the page.
Typical output directory:
index.htmlsummary.jsontests_full.jsontests_grouped.jsontests/test_<identifier>.html(one per test case)web/report.css,web/index-page.js,web/timeline-view.js,web/plist-preview.jsattachments/(exported media + previews)timeline_payloads/(compressed timeline payload blobs)test_details/*.json
- Templates:
Sources/xctestreport/Resources/Web/templates/ - CSS:
Sources/xctestreport/Resources/Web/report.css - JS:
Sources/xctestreport/Resources/Web/index-page.js - JS:
Sources/xctestreport/Resources/Web/timeline-view.js - JS:
Sources/xctestreport/Resources/Web/plist-preview.js
- Very large
.xcresultbundles can still take time due to attachment export and test detail extraction. - Decompressed plist preview in-browser requires
DecompressionStreamsupport.