How to get video and screenshots of an iOS UI test failure
Check your test plan’s capture settings before the run. Export the video and screenshots available in the result bundle. Run your tests with xcodebuild test -resultBundlePath. Export the failure’s available attachments with xcrun xcresulttool export attachments --only-failures. Record each check on a simulator with mobster test --video. Treat recording on a USB iPhone with the same command as unverified. The report shows the frame used for each failure’s verdict. It outlines the asserted elements and links the video.
Set capture in your test plan
In Xcode 15, automatic XCTest screen recordings are on by default, in favor of screenshots. Two settings in a test plan’s configuration control them:
- Automatic Screen Capture controls screenshot capture and whether screenshots from passing tests are deleted.
- Preferred Capture Format picks video or screenshots.
You can also turn recordings off in the scheme’s Test action options.
For a screenshot at a moment you choose, attach one in the test. An attachment’s lifetime defaults to .deleteOnSuccess, so it survives only when the test fails. Set .keepAlways to keep it on a pass too:
let shot = XCTAttachment(screenshot: XCUIScreen.main.screenshot())shot.name = "Checkout total"shot.lifetime = .keepAlwaysadd(shot)Export the failure from the result bundle
Run the tests with a result bundle, then export what’s attached to failures:
xcodebuild test -scheme YourApp \ -destination 'platform=iOS Simulator,name=iPhone 17 Pro' \ -resultBundlePath build/ UITests.xcresultxcrun xcresulttool export attachments \ --path build/ UITests.xcresult \ --output-path build/ failures --only-failuresxcodebuildexits with an error when the-resultBundlePathfolder already exists. Delete the old bundle first.- For an iPhone, use
-destination 'platform=iOS,name=Test iPhone'. export attachmentsis available starting with Xcode 16. It writes each file and amanifest.jsonthat lists, per test, theexportedFileName,isAssociatedWithFailure,deviceNameandtimestampof each attachment.- Upload
build/as your CI job’s artifact.failures
On a simulator you can also record by hand while you reproduce a failure:
xcrun simctl io booted recordVideo --codec=h264 run.movxcrun simctl io booted screenshot failure.pngrecordVideo writes until you press ctrl+c, then finishes the file. Its default codec is HEVC.
Record every check with Mobster
A Mobster check is a YAML file of steps and expectations. mobster test runs every check in .mobster/. Add --video to record each run’s screen:
mobster test --videoThe suite folder stands on its own, so every link works when you upload it as an artifact:
| Path | What it holds |
|---|---|
index.html | Each check that didn’t pass, open to its expectations, what Mobster found instead, the verdict frame, and links to the run’s report, log and video |
runs/ | Each run’s own report, frames included |
videos/ | One MP4 per run |
junit.xml | A failure element per failed check, for any JUnit reader |
Every run also keeps its frames in .mobster/: the launch, one frame per step, the verdict frame, and the verdict frame with an accessibility overlay. The overlay outlines each asserted element in green when it passes and red when it fails. The numbers follow the check’s order.
How Mobster records:
- On a simulator, with
xcrun simctl io <udid> recordVideo --codec=h264. - On an iPhone on a USB cable, from WebDriverAgent’s video stream, encoded on your Mac to an H.264 MP4 590 pixels wide. Run it with
mobster test --device "Test iPhone" --video. The one recorded iPhone run leaked file handles, and we haven’t tested it again since.
Put the failure on the pull request
mobster test pr runs the checks that cover the screens a branch changed. It writes pr-comment.md with each failure’s frame, and up to 6 captioned GIFs in pr/gifs/, failed checks first. On your own Mac runner, mobster ci run runs mobster test pr --video. The workflow that mobster ci init writes uploads .mobster/ as the job’s artifact, with the frames, GIFs and videos. The comment links each one. --no-video turns the recordings off.
Keep your XCTest screenshots beside the checks
In the next release, you use mobster test --xctest to build your project with xcodebuild build-for-testing, run your XCTest targets on a simulator and read the .xcresult with xcresulttool. Your tests’ attachments land in xctest/, and each failed test in index.html links its screenshots. Mobster runs XCTest targets on simulators only.
What it costs
Mobster for Mac is free on simulators and iPhones. A launch-only check calls no model. A check with steps runs on your Claude or OpenAI API key until it passes once, then replays its recorded steps with no model call.
Questions
Does XCUITest save a screen recording when a test fails?
Xcode 15 enables automatic XCTest screen recordings by default. Check your test plan's capture settings before you rely on a recording. Preferred Capture Format selects video or screenshots.
How do I get the video out of an .xcresult on CI?
Run xcrun xcresulttool export attachments with --path set to the result bundle, --output-path set to a folder and --only-failures. It writes the files and a manifest.json that names each one's test and device.
Does Mobster record video on a real iPhone?
With mobster test --video, you read the helper app's video stream from an iPhone connected by USB and encode an H.264 MP4 on your Mac. Treat iPhone video as unverified, with verified results only on simulators.
Sources
- Apple: Xcode 15 release notes, automatic screen recordings in XCTest
- Apple: improving code assessment by organizing tests into test plans
- Apple: XCTAttachment lifetime
- Apple: Xcode 16.3 release notes, xcresulttool commands
- Mobster docs: run every check with mobster test
- Mobster docs: checks and the run folder
- Mobster docs: running checks in CI


