Record archives next to the test source instead of into a bundle - #22
Merged
Conversation
`.playbackIsolated(replaysFrom:)` set the archive root for recording as well as playback, so in an Xcode project every recording landed inside the freshly built `.xctest` bundle and was gone on the next build. The source-relative lookup could not help, because it only guessed `Tests/` and `Sources/` under the working directory. Resolve the test's source file from the path Swift Testing records at compile time, and treat a bundle root as a playback fallback: recording always writes to the `Replays/` directory next to the test source when that file is present, and playback reads from there when the archive exists. A directory passed as `replaysRootURL:` or `rootURL:` still wins for both. Fixes #11
There was a problem hiding this comment.
🟡 Changes recommended
The updated behavior is solid and well-tested, but a couple of new doc comments in Traits.swift currently over-specify Replays/ and over-promise “always” recording next to sources despite configurable directories and fallback behavior.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR adjusts Replay’s test-archive resolution so recordings are written next to the test source file (instead of into an ephemeral .xctest bundle), while keeping bundle-based playback as a fallback—addressing the Xcode workflow described in Issue #11.
Changes:
- Introduces a new archive resolution order that prioritizes source-adjacent
Replays/for recording and preferred playback. - Refactors
.playbackIsolateddefault root handling to distinguish explicit directories vs bundle roots. - Adds focused tests for the new precedence rules and updates README guidance for Xcode projects.
File summaries
| File | Description |
|---|---|
| Tests/ReplayTests/Replays/source_relative.har | Adds a fixture archive used to validate source-relative playback resolution. |
| Tests/ReplayTests/ArchiveResolutionTests.swift | Adds coverage for the updated resolution precedence (source tree vs explicit root vs bundle fallback). |
| Sources/Replay/Traits.swift | Implements the new resolution order and introduces ArchiveRoot to model directory vs bundle roots. |
| README.md | Updates Xcode setup instructions to prefer .playbackIsolated(replaysFrom:) and explains source-tree recording behavior. |
Review details
- Files reviewed: 4/4 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+267
to
+272
| /// 3. The `Replays/` directory next to the test's source file. | ||
| /// Recording always writes here when the source file is present, | ||
| /// and playback reads from here when the archive exists. | ||
| /// 4. A bundle set with `.playbackIsolated(replaysFrom:)`. | ||
| /// 5. Any loaded bundle that contains `Replays/<name>.har` as a resource. | ||
| /// 6. `Replays/` under the current working directory. |
Comment on lines
+571
to
+574
| /// The bundle is a playback fallback: | ||
| /// an archive next to the test's source file takes precedence when it exists, | ||
| /// and recording always writes next to the source file | ||
| /// (bundles are rebuilt on every build, so an archive recorded into one is lost). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #11.
.playbackIsolated(replaysFrom:)set the archive root for recording as well as playback, so in an Xcode project every recording landed inside the freshly built.xctestbundle and was gone on the next build. The source-relative lookup couldn't help, because it only guessedTests/andSources/under the working directory, which never matches an Xcode project layout.This resolves the test's source file from the path Swift Testing records at compile time (
SourceLocation.filePathon Swift 6.3,_filePathbefore that), and treats a bundle root as a playback fallback. The new order:rootURL:on the.replaytrait.playbackIsolated(replaysRootURL:)Replays/next to the test's source file: recording always writes here when the file is present, and playback reads from here when the archive exists.playbackIsolated(replaysFrom:)Replays/<name>.haras a resourceReplays/under the working directoryDirectories passed explicitly keep winning for both recording and playback, so package setups that share one fixtures directory across test files are unchanged. The README's Xcode example moves from
replaysRootURL:(which would still record into the bundle) toreplaysFrom:.Tests cover each branch of the new order through the internal
resolveArchiveURL(name:test:recordMode:), which takes the record mode as a parameter so the tests don't touch the environment.swift testpasses on macOS (Xcode 26.0) and Linux (Swift 6.2.4).