Skip to content

Record archives next to the test source instead of into a bundle - #22

Merged
mattt merged 2 commits into
mainfrom
record-next-to-source
Sep 9, 2026
Merged

Record archives next to the test source instead of into a bundle#22
mattt merged 2 commits into
mainfrom
record-next-to-source

Conversation

@mattt

@mattt mattt commented Sep 9, 2026

Copy link
Copy Markdown
Owner

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 .xctest bundle and was gone on the next build. The source-relative lookup couldn't help, because it only guessed Tests/ and Sources/ 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.filePath on Swift 6.3, _filePath before that), and treats a bundle root as a playback fallback. The new order:

  1. rootURL: on the .replay trait
  2. A directory from .playbackIsolated(replaysRootURL:)
  3. 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
  4. The bundle from .playbackIsolated(replaysFrom:)
  5. Any loaded bundle carrying Replays/<name>.har as a resource
  6. Replays/ under the working directory

Directories 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) to replaysFrom:.

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 test passes on macOS (Xcode 26.0) and Linux (Swift 6.2.4).

`.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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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 .playbackIsolated default 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 thread Sources/Replay/Traits.swift Outdated
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 thread Sources/Replay/Traits.swift Outdated
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).
@mattt
mattt merged commit b0f8fa0 into main Sep 9, 2026
8 checks passed
@mattt
mattt deleted the record-next-to-source branch September 9, 2026 12:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FileManager.default.fileExists fails with a path provided by Bundle.main.resourceURL

2 participants