Skip to content

test(postgrest): migrate PostgRESTTests to Swift Testing + Replay (Phase 4)#1095

Open
grdsdev wants to merge 2 commits into
mainfrom
guilherme/sdk-1251-swift-testing-migration-phase-4-postgresttests
Open

test(postgrest): migrate PostgRESTTests to Swift Testing + Replay (Phase 4)#1095
grdsdev wants to merge 2 commits into
mainfrom
guilherme/sdk-1251-swift-testing-migration-phase-4-postgresttests

Conversation

@grdsdev

@grdsdev grdsdev commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Converts all 10 files in Tests/PostgRESTTests (2,948 lines) from XCTest+Mocker to Swift Testing (#expect/#require/@Test/@Suite) and Replay for HTTP mocking, per the Phase 0 decision (SDK-1247). This is Phase 4 of the migration tracked in SDK-435.

Changes

  • All 10 test files converted to Swift Testing; zero import XCTest, zero import Mocker remain in the target.
  • Mocker's .snapshotRequest { curl ... } assertions (66 occurrences) are dropped entirely — no shim — replaced with Replay .replay(stubs: [...], matching: [.method, .path], scope: .test), mirroring the original mocks' ignoreQuery: true semantics.
  • BuildURLRequestTests keeps its assertSnapshot(as: .curl) request-shape snapshots (32 files in __Snapshots__/) unchanged in intent, but switches the #file default to #filePath — Swift Testing resolves #file to a module-relative path, which broke snapshot directory resolution under both swift test and xcodebuild (writing to <repo-root>/PostgRESTTests/__Snapshots__ instead of Tests/PostgRESTTests/__Snapshots__).
  • PostgresQueryTests.swift, an XCTestCase base class shared via inheritance by 5 other test classes, is replaced by a composed PostgrestQueryFixture struct (Swift Testing suites don't support shared state through subclassing) and renamed to PostgrestQueryFixture.swift to reflect its new contents.
  • PostgrestBuilderTests is a final class (not a struct) with @Suite(.serialized), so deinit can restore the process-global _clock test seam (Sources/Helpers/_Clock.swift) after its retry tests run — matching the old tearDown(). A struct has no equivalent teardown hook, so an early version of this migration silently dropped the clock reset; caught in review.
  • PostgRESTTests moves off the blanket .swiftLanguageMode(.v5) pin onto full Swift 6 language mode, matching production targets' swiftSettings.
  • Adds Replay (from: "0.4.0") as a new package dependency; drops Mocker/InlineSnapshotTesting from PostgRESTTests' target dependencies.

Test plan

  • swift test --filter PostgRESTTests: 97/97 tests, 9 suites, green.
  • PLATFORM=MACOS XCODEBUILD_ARGUMENT=test SCHEME=PostgREST ./scripts/xcodebuild.sh: Test Succeeded, 97/97.
  • Full swift test run: no regressions in other targets (pre-existing IntegrationTests failures require a live local Supabase instance, unrelated to this change).
  • ./scripts/spell-check.sh: clean.
  • ./scripts/format.sh scoped to changed files.

Linear

Closes SDK-1251

…ase 4)

Converts all 10 files in Tests/PostgRESTTests from XCTest+Mocker to Swift
Testing (#expect/#require/@Test/@suite) and Replay for HTTP mocking, per
the Phase 0 decision (SDK-1247). Drops Mocker's `.snapshotRequest` curl
assertions entirely, replacing them with Replay stubs matched on method+path
(mirroring the original `ignoreQuery: true` semantics). BuildURLRequestTests
keeps its `assertSnapshot(as: .curl)` request-shape snapshots unchanged, but
switches its `#file` default to `#filePath` since Swift Testing resolves
`#file` to a module-relative path (breaking snapshot directory resolution
under both `swift test` and `xcodebuild`).

PostgrestQueryTests.swift (an XCTestCase base class shared via inheritance)
is replaced by a composed `PostgrestQueryFixture` struct, since Swift Testing
suites don't support shared state through subclassing; the file is renamed
to PostgrestQueryFixture.swift to reflect its new contents.

PostgrestBuilderTests keeps `@Suite(.serialized)` and is now a class (not a
struct) so `deinit` can restore the process-global `_clock` seam after its
retry tests run, matching the old `tearDown()` — a struct has no equivalent
hook, so the initial conversion silently dropped the clock reset.

PostgRESTTests moves off the blanket `.swiftLanguageMode(.v5)` pin onto full
Swift 6 language mode, matching production targets' swiftSettings. Adds
`Replay` as a new package dependency.

Verified via both `swift test` and `xcodebuild test` (97/97 tests, 9 suites,
both hosts).

Linear: SDK-1251
@grdsdev grdsdev requested a review from a team as a code owner July 8, 2026 21:11
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

⚠️ Potential Breaking API Changes Detected

This PR appears to contain breaking API changes. Please review the changes below:

API Check Output
  💔 API breakage: class SupabaseClient has been removed
  💔 API breakage: struct SupabaseClientOptions has been removed
  💔 API breakage: enum Defaults has been removed
  💔 API breakage: enum ChannelState has been removed
  💔 API breakage: struct Delegated has been removed
  💔 API breakage: typealias Message has been removed
  💔 API breakage: protocol PhoenixTransport has been removed
  💔 API breakage: protocol PhoenixTransportDelegate has been removed
  💔 API breakage: enum PhoenixTransportReadyState has been removed
  💔 API breakage: class URLSessionTransport has been removed
  💔 API breakage: class Presence has been removed
  💔 API breakage: class Push has been removed
  💔 API breakage: struct ChannelFilter has been removed
  💔 API breakage: enum ChannelResponse has been removed
  💔 API breakage: enum RealtimeListenTypes has been removed
  💔 API breakage: struct RealtimeChannelOptions has been removed
  💔 API breakage: enum RealtimeSubscribeStates has been removed
  💔 API breakage: class RealtimeChannel has been removed
  💔 API breakage: enum SocketError has been removed
  💔 API breakage: typealias Payload has been removed
  💔 API breakage: typealias PayloadClosure has been removed
  💔 API breakage: class RealtimeClient has been removed
  💔 API breakage: struct RealtimeMessage has been removed
  💔 API breakage: var RealtimeClientV2.subscriptions has been removed
  💔 API breakage: struct RealtimeClientV2.Configuration has been removed
  💔 API breakage: typealias RealtimeClientV2.Status has been removed
  💔 API breakage: constructor RealtimeClientV2.init(config:) has been removed
  💔 API breakage: typealias RealtimeChannelV2.Subscription has been removed
  💔 API breakage: typealias RealtimeChannelV2.Status has been removed
  💔 API breakage: typealias URLQueryRepresentable has been removed
  💔 API breakage: class PostgrestBuilder has been removed
  💔 API breakage: class PostgrestClient has been removed
  💔 API breakage: class PostgrestFilterBuilder has been removed
  💔 API breakage: protocol PostgrestFilterValue has been removed
  💔 API breakage: class PostgrestQueryBuilder has been removed
  💔 API breakage: class PostgrestTransformBuilder has been removed
  💔 API breakage: struct PostgrestResponse has been removed
  💔 API breakage: enum CountOption has been removed
  💔 API breakage: enum PostgrestReturningOptions has been removed
  💔 API breakage: enum TextSearchType has been removed
  💔 API breakage: struct ExplainFormat has been removed
  💔 API breakage: struct FetchOptions has been removed
  💔 API breakage: var String.rawValue has been removed
  💔 API breakage: var Int.rawValue has been removed
  💔 API breakage: var Double.rawValue has been removed
  💔 API breakage: var Bool.rawValue has been removed
  💔 API breakage: var UUID.rawValue has been removed
  💔 API breakage: var Date.rawValue has been removed
  💔 API breakage: var Array.rawValue has been removed
  💔 API breakage: var AnyJSON.rawValue has been removed
  💔 API breakage: var Optional.rawValue has been removed
  💔 API breakage: var Dictionary.rawValue has been removed
  💔 API breakage: class FunctionsClient has been removed
  💔 API breakage: enum FunctionsError has been removed
  💔 API breakage: struct FunctionInvokeOptions has been removed
  💔 API breakage: enum FunctionRegion has been removed
  💔 API breakage: struct File has been removed
  💔 API breakage: class FormData has been removed
  💔 API breakage: class StorageApi has been removed
  💔 API breakage: class StorageBucketApi has been removed
  💔 API breakage: struct StorageError has been removed
  💔 API breakage: class StorageFileApi has been removed
  💔 API breakage: struct StorageHTTPSession has been removed
  💔 API breakage: struct StorageClientConfiguration has been removed
  💔 API breakage: class SupabaseStorageClient has been removed
  💔 API breakage: struct SearchOptions has been removed
  💔 API breakage: struct SortBy has been removed
  💔 API breakage: struct FileOptions has been removed
  💔 API breakage: struct SignedURL has been removed
  💔 API breakage: enum SignedURLResult has been removed
  💔 API breakage: struct SignedUploadURL has been removed
  💔 API breakage: struct FileUploadResponse has been removed
  💔 API breakage: struct SignedURLUploadResponse has been removed
  💔 API breakage: struct CreateSignedUploadURLOptions has been removed
  💔 API breakage: struct DestinationOptions has been removed
  💔 API breakage: struct FileObject has been removed
  💔 API breakage: struct FileObjectV2 has been removed
  💔 API breakage: struct Bucket has been removed
  💔 API breakage: struct StorageByteCount has been removed
  💔 API breakage: struct ResizeMode has been removed
  💔 API breakage: struct ImageFormat has been removed
  💔 API breakage: struct SortOrder has been removed
  💔 API breakage: enum DownloadBehavior has been removed
  💔 API breakage: struct BucketOptions has been removed
  💔 API breakage: struct TransformOptions has been removed
  💔 API breakage: var JSONEncoder.defaultStorageEncoder has been removed
  💔 API breakage: var JSONDecoder.defaultStorageDecoder has been removed
  💔 API breakage: struct AuthAdmin has been removed
  💔 API breakage: struct AuthAdminOAuth has been removed
  💔 API breakage: class AuthClient has been removed
  💔 API breakage: struct ErrorCode has been removed
  💔 API breakage: enum AuthError has been removed
  💔 API breakage: struct AuthMFA has been removed
  💔 API breakage: protocol AuthStateChangeListenerRegistration has been removed
  💔 API breakage: typealias AuthStateChangeListener has been removed
  💔 API breakage: typealias GoTrueClient has been removed
  💔 API breakage: typealias GoTrueMFA has been removed
  💔 API breakage: typealias GoTrueLocalStorage has been removed
  💔 API breakage: typealias GoTrueMetaSecurity has been removed
  💔 API breakage: typealias GoTrueError has been removed
  💔 API breakage: typealias MFAEnrollParams has been removed
  💔 API breakage: protocol AuthLocalStorage has been removed
  💔 API breakage: struct KeychainLocalStorage has been removed
  💔 API breakage: enum AuthChangeEvent has been removed
  💔 API breakage: struct UserCredentials has been removed
  💔 API breakage: struct Session has been removed
  💔 API breakage: struct User has been removed
  💔 API breakage: struct UserIdentity has been removed
  💔 API breakage: enum Provider has been removed
  💔 API breakage: struct OpenIDConnectCredentials has been removed
  💔 API breakage: struct AuthMetaSecurity has been removed
  💔 API breakage: enum MobileOTPType has been removed
  💔 API breakage: enum EmailOTPType has been removed
  💔 API breakage: enum AuthResponse has been removed
  💔 API breakage: struct UserAttributes has been removed
  💔 API breakage: struct AdminUserAttributes has been removed
  💔 API breakage: enum AuthFlowType has been removed
  💔 API breakage: typealias FactorType has been removed
  💔 API breakage: enum FactorStatus has been removed
  💔 API breakage: struct Factor has been removed
  💔 API breakage: protocol MFAEnrollParamsType has been removed
  💔 API breakage: struct MFATotpEnrollParams has been removed
  💔 API breakage: struct MFAPhoneEnrollParams has been removed
  💔 API breakage: struct AuthMFAEnrollResponse has been removed
  💔 API breakage: struct MFAChallengeParams has been removed
  💔 API breakage: struct MFAVerifyParams has been removed
  💔 API breakage: struct MFAUnenrollParams has been removed
  💔 API breakage: struct MFAChallengeAndVerifyParams has been removed
  💔 API breakage: struct AuthMFAChallengeResponse has been removed
  💔 API breakage: typealias AuthMFAVerifyResponse has been removed
  💔 API breakage: struct AuthMFAUnenrollResponse has been removed
  💔 API breakage: struct AuthMFAListFactorsResponse has been removed
  💔 API breakage: typealias AuthenticatorAssuranceLevels has been removed
  💔 API breakage: struct AMREntry has been removed
  💔 API breakage: struct AuthMFAGetAuthenticatorAssuranceLevelResponse has been removed
  💔 API breakage: enum SignOutScope has been removed
  💔 API breakage: enum ResendEmailType has been removed
  💔 API breakage: enum ResendMobileType has been removed
  💔 API breakage: struct ResendMobileResponse has been removed
  💔 API breakage: struct WeakPassword has been removed
  💔 API breakage: enum MessagingChannel has been removed
  💔 API breakage: struct SSOResponse has been removed
  💔 API breakage: struct OAuthResponse has been removed
  💔 API breakage: struct PageParams has been removed
  💔 API breakage: struct ListUsersPaginatedResponse has been removed
  💔 API breakage: struct OAuthClientGrantType has been removed
  💔 API breakage: struct OAuthClientResponseType has been removed
  💔 API breakage: struct OAuthClientType has been removed
  💔 API breakage: struct OAuthClientRegistrationType has been removed
  💔 API breakage: struct OAuthClient has been removed
  💔 API breakage: struct CreateOAuthClientParams has been removed
  💔 API breakage: struct UpdateOAuthClientParams has been removed
  💔 API breakage: struct ListOAuthClientsPaginatedResponse has been removed
  💔 API breakage: struct JWK has been removed
  💔 API breakage: struct JWKS has been removed
  💔 API breakage: struct JWTHeader has been removed
  💔 API breakage: struct JWTClaims has been removed
  💔 API breakage: enum AudienceClaim has been removed
  💔 API breakage: struct JWTClaimsResponse has been removed
  💔 API breakage: struct GetClaimsOptions has been removed
  💔 API breakage: struct MFAWebAuthnEnrollParams has been removed
  💔 API breakage: struct WebAuthnChallengeOptions has been removed
  💔 API breakage: enum WebAuthnChallengeType has been removed
  💔 API breakage: struct WebAuthnChallengeResponseData has been removed
  💔 API breakage: struct PasskeyListItem has been removed
  💔 API breakage: struct PasskeyRegistrationOptions has been removed
  💔 API breakage: struct PasskeyAuthenticationOptions has been removed
  💔 API breakage: var JSONEncoder.goTrue has been removed
  💔 API breakage: var JSONDecoder.goTrue has been removed

If this is intentional, please update your PR title or commit message to include:

  • ! after the type (e.g., feat!: remove deprecated method)
  • Or include BREAKING CHANGE: in the commit body

If this is a false positive, you can safely ignore this warning.

@coveralls

coveralls commented Jul 8, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 28980249909

Coverage remained the same at 83.221%

Details

  • Coverage remained the same as the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 9470
Covered Lines: 7881
Line Coverage: 83.22%
Coverage Strength: 37.64 hits per line

💛 - Coveralls

…ration

Path-only stub matching (matching: [.method, .path]) silently dropped all
query-string and request-body verification that the old Mocker-based tests
enforced via .snapshotRequest curl assertions. Every filter/transform/rpc/
query builder test would have passed even if the underlying query-string or
body construction regressed.

Switch to Replay's default exact-URL matcher (byte-identical query string)
for deterministic cases, .query (order-insensitive) for the two RPC tests
with non-deterministic dictionary-iteration-ordered params, and a custom
.custom body matcher (reading httpBodyStream, since URLSession moves the
body out of httpBody in flight) for insert/update/upsert body assertions.
Query strings were re-derived from actual runtime request output, not
copied from the stale pre-migration snapshot text, since Mocker's curl
pretty-printer didn't reflect real percent-encoding/param order.
grdsdev added a commit that referenced this pull request Jul 9, 2026
Converts the largest AuthTests file (87 tests, 81 Mocker Mock() calls,
53 curl-snapshot assertions) to Swift Testing + Replay, per the Phase 0
decision (SDK-1247) and the Phase 4/Phase 3 conversion patterns
(PostgRESTTests PR #1095, StorageTests PR #1096).

- Curl-snapshot request-shape assertions dropped per the Phase 0 "no
  shim" decision, replaced by Replay's matcher-based enforcement.
- Query strings preserved via exact-URL matching (.method, .url) rather
  than path-only matching, so query-string regressions are still
  caught (the gap PR #1095's follow-up commit found and fixed).
- Request bodies verified via a custom .custom matcher that decodes
  both sides as AnyJSON for structural comparison (key order/whitespace
  insensitive), following the pattern from StorageTests PR #1096's
  jsonBody(of:) helper -- important here since most of this file's
  Mocker bodies carry auth-relevant payloads (passwords, tokens, PKCE
  code verifiers, MFA/passkey credentials).
- withMainSerialExecutor wrapping moved from XCTestCase.invokeTest into
  the handful of @test bodies that actually spawn concurrent
  authStateChanges-driven Tasks.
- HTTPResponse.stub(...) helper (used cross-file by SessionManagerTests)
  preserved at the bottom of the file.

Linear: SDK-1252
grdsdev added a commit that referenced this pull request Jul 9, 2026
… bugs

- RequestsTests.swift: converts the last remaining XCTest/Mocker file.
  These tests only verify request routing (method+path); response
  bodies are minimal but decodable fixtures where AuthClient actually
  decodes a response (Session/User), reusing AuthClientTests' MockData.
- Fixes two real bugs surfaced by actually running the suite (not just
  compiling): AuthClientTests/SessionManagerTests used
  `.method, .url` exact-URL matching, which broke on percent-encoding
  differences between how the stub URL string parses vs. how the live
  request is constructed (e.g. `:`/`/` in a redirect_to query value).
  Switched to `.method, .path, .query` throughout, matching the
  Matcher type's own documented guidance to prefer composed matchers
  over whole-URL comparison.
- SessionManagerTests/AuthClientTests: withMainSerialExecutor mutates
  a process-global flag; Swift Testing runs same-suite tests
  concurrently by default, so mark both suites .serialized to avoid
  cross-test interference, mirroring the _clock precedent in
  PostgrestBuilderTests (PR #1095).
- setSessionWithAFutureExpirationDate/updateUser: fixed stubs that
  decoded the wrong response type (Session vs User) — caught by
  running tests, not visible from a clean compile.

swift build --target AuthTests: 0 errors.
swift test --filter AuthTests: 206/206 passed.

Linear: SDK-1252
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants