◉CLAUDE LABJP
●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…●2.1.301 — Adds the vim % motion, LaTeX math rendering in the VS Code panel, and a retry-watchdog limit for usage-limit waits (10/15)●2.1.299 — Conversations over 200K tokens left idle about 54 minutes get compacted; MCP allow rules now match only the server they name●SONNET 4.5 — Retires on the Claude API on 11/30, 45 days left. Migrate to Sonnet 5.5●WINDOWS — Reports say hooks break silently only on Japanese-locale Windows; check the character encoding first●FAST MODE — Opus 5.5 fast mode is out of research preview and no longer needs the beta header (10/15)●NEW — I Put a Ten-Line Promise File at the To…
Articles/Claude Code
⟐ Claude Code/2026-06-03Advanced

Triaging iOS Test Failures Fast: Parsing .xcresult with Claude Code

Xcode 16 deprecated xcresulttool's legacy JSON, changing how you pull test failures out of a .xcresult bundle. Here's how to shape the new test-results format with jq and hand it to Claude Code to pinpoint the cause and a fix, drawn from running six apps in parallel.

claude-code132ios14xcresultxcodebuildxctestci-cd8test-automationswift

✦ Premium Article

When an iOS test fails in CI, the minutes I lose are rarely spent on why it failed. They go to finding where the reason is written down. Open the test navigator in Xcode and the failure is right there, but CI gives you a flood of log lines and a single .xcresult bundle that you can't read without waiting for Xcode to open it.

I've built wallpaper and relaxation apps for iOS and Android as a solo developer since 2014, and since May 2026 I've been migrating six of them to StoreKit 2 in parallel. Every migration knocks out a batch of purchase tests at once, and I once burned half a day opening .xcresult bundles one by one in Xcode just to see what broke. That extraction step — getting the contents of a failure out of the bundle — is exactly the part Claude Code can collapse into a single command.

The catch is that Xcode 16 deprecated the legacy JSON output of xcresulttool, so the xcresulttool get --format json that countless scripts and blog posts assumed no longer works cleanly. Below, I start from the newer test-results subcommands, pull out only the failed tests, hand them to Claude Code, and get back a cause hypothesis and a candidate fix.

What lives inside a .xcresult

A .xcresult is not a log file. It's a SQLite-backed bundle that packages test results, code coverage, attachments such as screenshots, and build diagnostics. Finder shows it as one file, but it's a directory you aren't meant to read directly. The supported way in is xcrun xcresulttool.

Here's the first trap. Through Xcode 15, the common approach fetched a root object and then walked IDs down to the test results.

# The old way, through Xcode 15 (now warns as deprecated in Xcode 16)
xcrun xcresulttool get --path Result.xcresult --format json

This still runs in Xcode 16 for now, but without --legacy it warns that it's deprecated, and the output shape isn't guaranteed going forward. Worse, that root JSON is deeply nested: reaching the test list means pulling the id out of actions → actionResult → testsRef and calling get again. The scripts break easily, and it's far too heavy to feed to Claude Code as-is.

Old vs new, side by side

Xcode 16 added a test-results subcommand dedicated to test output, and that's the star here. No multi-step reference walking — you get a flat-ish JSON of the summary and the individual results directly.

# Before: fetch the root, then walk ids (two or three get calls)
ROOT=$(xcrun xcresulttool get --legacy --path Result.xcresult --format json)
TESTS_REF=$(echo "$ROOT" | jq -r '.actions._values[0].actionResult.testsRef.id._value')
xcrun xcresulttool get --legacy --path Result.xcresult --id "$TESTS_REF" --format json
# → still more nesting before you reach a single test's assertion text
# After: pull test results directly (Xcode 16+)
# Summary: overall pass/fail, counts, duration
xcrun xcresulttool get test-results summary --path Result.xcresult
# Individual tests, including failure messages and file/line references
xcrun xcresulttool get test-results tests --path Result.xcresult

The test-results tests output is a tree — test plan → bundle → suite → individual test — and each node carries a result (Passed, Failed, and so on). A failed node includes the assertion failure message and a source reference. The part where the old approach called get repeatedly now collapses into essentially one command.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦Get the exact jq pipeline that flattens Xcode 16's new test-results output down to just the failed tests, so Claude Code reads a few hundred tokens instead of your entire test tree
✦Reuse a single slash command that turns failed test names, assertion messages, and file/line references into a cause hypothesis plus a candidate fix diff
✦See a Stop-hook and headless-CI setup that auto-triages whatever .xcresult is left behind, separating flakes from real bugs, based on migrating six wallpaper apps to StoreKit 2
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Claude Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⟐ Claude Code2026-04-08
iOS Test Automation with Claude Code — Where XCTest, Swift Testing, and XCUITest Each Belong
How I rebuilt an iOS test suite with Claude Code: where XCTest, Swift Testing, and XCUITest each belong, the pipefail trap that turns failed tests green in CI, and a hook that hands only test failures back to Claude.
⟐ Claude Code2026-08-28
A small script that catches invisible characters in plugin names before you install
Control characters and zero-width characters hiding in plugin or skill names are invisible in a terminal listing. I built six deliberately confusing names, compared what ls actually shows, and wrote a short check you can run before installing anything — plus an honest note on what that check misses.
⟐ Claude Code2026-08-26
I decide the prompt cache TTL by where I come back to, not how long I was away
Claude Code v2.1.242 added promptCacheTtl and subagentPromptCacheTtl. Whether the one-hour cache pays off depends on returning to the same directory and the same git state, not on how long the break was. Here is the order I check things in.