feat(testing): Support reusable prepared test artifacts#475
feat(testing): Support reusable prepared test artifacts#475cameroncooke wants to merge 16 commits into
Conversation
commit: |
Keep source-only xcodebuild arguments out of the generated test-without-building phase and sort final test failures independently of emission order.
Share per-test environment setup and cleanup across snapshot suites, cache suite-level simulator builds, and normalize volatile output so fixtures remain stable. Update non-environmental fixtures and add coverage for cleanup and normalization behavior.
Prevent session defaults and selectors from leaking into prepared test runs, remove a useless simulator state initializer, and align volatile snapshot fixtures across CLI and MCP.
Keep only-testing and skip-testing arguments in the prepared test phase while retaining session-default conflict filtering.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit cda637e. Configure here.
| "screenHash": "<SCREEN_HASH>", | ||
| "seq": 1, | ||
| "count": 28, | ||
| "count": 99999, |
There was a problem hiding this comment.
tap--success fixture count changed to implausible 99999 unrelated to PR scope
The count field was changed from 28 to 99999 in a UI-automation tap fixture, which is unrelated to the prepared-test-artifacts feature and does not reflect a plausible real output.
Evidence
- PR scope is
buildForTesting/testProductsPathbuild and test tools; this fixture isui-automation/tap--success.json. countchanged from 28 to 99999 while thetargetsarray still lists only 19 entries, so 99999 does not correspond to observed data.- The identical value appears in both the CLI and MCP fixtures, indicating a hand-patched constant rather than a captured snapshot value.
- If
countis volatile it should be normalized in code likescreenHash→<SCREEN_HASH>, not hard-coded to an arbitrary literal.
Also found at 2 additional locations
src/snapshot-tests/__fixtures__/cli/json/ui-automation/tap--success-verbose.json:611-617src/snapshot-tests/__fixtures__/cli/json/ui-automation/tap--success.json:48
Identified by Warden xcodebuildmcp-snapshot-fixture-review · G2H-E5J
| "error": null, | ||
| "data": { | ||
| "simulators": [ | ||
| { |
There was a problem hiding this comment.
Simulator-list fixture expanded with environment-specific entries unrelated to prepared-test feature
This fixture is regrown with many machine-specific simulators (watchOS Series 11, iPhone 17 family, etc.) that don't relate to the PR's prepared-test-artifacts change; simulator names and the device count are not normalized and reflect the installed Xcode on one machine, so this looks like a regeneration to match a local environment rather than an intentional behavior change.
Evidence
json-normalize.tsonly normalizesstate(line 83),runtimeversion (lines 95-97), and UUIDs; simulatornameand the number ofsimulatorsentries are emitted verbatim.- The added entries (Apple Watch Series 11, iPhone 17 Pro, iPad Pro (M5), etc.) are literal device names tied to a specific installed simulator set, making them volatile across machines.
- The PR scope is reusable prepared test artifacts (
buildForTesting/testProductsPath), which has no bearing on the output of the simulator-list tool.
Identified by Warden xcodebuildmcp-snapshot-fixture-review · UXY-GFK
| "Fetching https://github.com/apple/swift-argument-parser.git from cache", | ||
| "Fetched https://github.com/apple/swift-argument-parser.git from cache (<DURATION>)", | ||
| "Computing version for https://github.com/apple/swift-argument-parser.git", | ||
| "Computed https://github.com/apple/swift-argument-parser.git at 1.5.1 (<DURATION>)", | ||
| "Computed https://github.com/apple/swift-argument-parser.git at 1.5.1 (<DURATION>)", | ||
| "Creating working copy for https://github.com/apple/swift-argument-parser.git", | ||
| "Working copy of https://github.com/apple/swift-argument-parser.git resolved at 1.5.1", |
There was a problem hiding this comment.
CLI JSON run--success stderr diverges from MCP JSON fixture for the same scenario
The CLI JSON fixture (cli/json/swift-package/run--success.json) records seven SPM dependency-resolution stderr lines (Fetching/Fetched/Computing/Computed/Creating/Working copy) that the MCP JSON fixture (mcp/json/swift-package/run--success.json) does not contain. Both fixtures capture the same deterministic xcodebuildmcp.output.build-run-result scenario, so their data.output.stderr arrays should match. The divergence indicates the CLI fixture was regenerated against a different dependency-cache state (cold vs. warm) rather than kept aligned, breaking the MCP/CLI/JSON fixture alignment guardrail.
Evidence
cli/json/swift-package/run--success.jsonstderr begins withFetching .../swift-argument-parser.git from cachethroughWorking copy ... resolved at 1.5.1, thenBuilding for debugging....mcp/json/swift-package/run--success.jsonstderr for the identical scenario starts directly atBuilding for debugging...with none of those seven lines (grep forFetching https://github.com/apple/swift-argument-parsermatches only the CLI file).- Text fixtures (
cli/textandmcp/textrun--success.txt) surface no stderr detail, so the mismatch is isolated to the JSON envelopes. - The extra lines reflect volatile dependency-cache state (cold fetch/resolve) that is inconsistently captured between transports rather than normalized identically.
Also found at 1 additional location
src/snapshot-tests/__fixtures__/cli/json/swift-package/run--success.json:31-32
Identified by Warden xcodebuildmcp-snapshot-fixture-review · 7LW-6HX

Why
Agents and CI workflows need to prepare tests once and execute them later without falling back to raw
xcodebuild. The existing build tools always finished with a normal build action, so they could not expose the reusable products produced bybuild-for-testing.What Changed
buildForTestingand optionaltestProductsPathinputs..xctestproductsbundles and discovered.xctestrunfiles as structured build artifacts..xctestproductsbundles or advanced.xctestruninputs without rebuilding, while returning the new.xcresultproduced by the run.Fixes #450