A failing UI assertion often shows what the test saw, but not what the app logged while the simulator handled the tap, request, or navigation. A scoped iOS Simulator unified-log capture gives the app messages for the same run window so a login, deep link, permission, or network failure can be matched to app-side behavior.
xcrun simctl spawn booted runs the macOS log tool inside the booted simulator. Filtering by the app's OSLog subsystem keeps the file small enough to review beside the .xcresult bundle instead of collecting every SpringBoard and system daemon message.
Start the log stream before the target UI test, let the stream stop after a fixed timeout, then compare the saved lines with the failing test in Xcode. A physical iPhone or iPad uses Xcode's device console or another device-log collector; the simulator command path is for local or CI-style simulator runs with full Xcode selected.
Related: How to run XCUITest tests locally
Related: How to run XCUITest with xcodebuild in CI
Related: How to save XCUITest result bundles
Related: How to debug a flaky XCUITest test
Steps to capture XCUITest simulator device logs:
- Open a terminal in the project root and create a directory for test evidence.
$ mkdir -p TestResults
- Start a scoped simulator log stream in a separate terminal before launching the UI test.
$ xcrun simctl spawn booted log stream \ --style compact \ --level info \ --timeout 12m \ --predicate 'subsystem == "com.example.MyApp"' \ > TestResults/LoginUITests-device.log
Replace com.example.MyApp with the app's Logger or OSLog subsystem. For older NSLog-only apps, use --process MyApp instead of the predicate after the app has launched.
- Run the failing or suspicious UI test while the log stream is active.
$ xcodebuild test \ -workspace MyApp.xcworkspace \ -scheme MyApp \ -destination 'platform=iOS Simulator,name=iPhone 16,OS=latest' \ -only-testing:MyAppUITests/LoginUITests/testValidLogin \ -resultBundlePath TestResults/LoginUITests.xcresult Test Suite 'Selected tests' started. Test Case '-[MyAppUITests.LoginUITests testValidLogin]' started. Test Case '-[MyAppUITests.LoginUITests testValidLogin]' failed (5.812 seconds). ** TEST FAILED **
Use -project MyApp.xcodeproj instead of -workspace MyApp.xcworkspace for a standalone project. Remove -only-testing:MyAppUITests/LoginUITests/testValidLogin when the whole UI test bundle should run.
- Stop the log stream after the test finishes if it has not reached its timeout.
--timeout 12m prevents a forgotten stream from running indefinitely. Increase it only when the selected test normally runs longer.
- Check that the saved log contains messages from the app during the test window.
$ cat TestResults/LoginUITests-device.log Timestamp Type Process[PID] Message 2026-06-26 09:41:11.846 Info MyApp[1842] [Login] Login button tapped 2026-06-26 09:41:12.431 Error MyApp[1842] [Network] POST /session returned 401 2026-06-26 09:41:12.770 Info MyApp[1842] [Login] Showing invalid credentials message
If the file is empty, the predicate is too narrow, the simulator was not booted, or the stream started after the app exited. Re-run with the app's process name or a broader subsystem filter before collecting unrelated system logs.
- Open the result bundle and match the failed test row to the saved log window.
$ open TestResults/LoginUITests.xcresult
In Xcode, select the failed test, inspect the failure screenshot or activity timeline, and keep TestResults/LoginUITests-device.log with the .xcresult bundle when filing a bug or CI artifact.
Related: How to save XCUITest result bundles
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.