Skip to content

test(storage): migrate StorageTests to Swift Testing (Phase 3)#1096

Open
grdsdev wants to merge 1 commit into
mainfrom
test/sdk-1250-storage-swift-testing-migration
Open

test(storage): migrate StorageTests to Swift Testing (Phase 3)#1096
grdsdev wants to merge 1 commit into
mainfrom
test/sdk-1250-storage-swift-testing-migration

Conversation

@grdsdev

@grdsdev grdsdev commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrates Tests/StorageTests (11 files) from XCTest+Mocker to Swift Testing (@Suite/@Test) + Replay for HTTP mocking, per the repo-wide Swift Testing migration plan (SDK-435) and the conventions decided in Phase 0 (SDK-1247, SDK-1091).

Changes

  • Package.swift: Added the Replay package dependency, wired into the StorageTests target. Removed Mocker/TestHelpers deps (only used for the now-dropped .snapshotRequest curl-snapshot assertions — dropped per the ticket's explicit "no shim" decision). Moved StorageTests out of the blanket .swiftLanguageMode(.v5) pin into the swift6TestTargets set, so it now compiles under full Swift 6 language mode with the same strict-concurrency settings as production targets.
  • Tests/StorageTests/: All 11 files converted. Pure-unit files (BucketOptionsTests, FileOptionsTests, TransformOptionsTests, ValueTypesTests, StorageErrorTests, MultipartFormDataTests) are mechanical conversions. DownloadBehaviorTests' setUp became init(). The Mocker-heavy files (StorageBucketAPITests, StorageFileAPITests) now use @Test(.replay(stubs: [...])) with StorageHTTPSession(fetch: { try await Replay.session.data(for: $0) }, ...) injected — mirroring FunctionsClient's existing fetch-closure DI pattern, so no new Storage-side injection scope was needed. SupabaseStorageTests keeps its existing closure-based StorageHTTPSession mocking (already framework-agnostic) but drops XCTestCase.
  • Request-body coverage: .snapshotRequest's curl-body assertions had no direct Replay equivalent for inline stubs, so move/copy/remove (the tests most exposed to a silent parameter-swap regression, e.g. sourceKey/destinationKey) now use a .custom Replay matcher that decodes and compares the JSON body. Verified this actually catches regressions by temporarily swapping sourceKey/destinationKey in StorageFileApi.move() and confirming the test fails, then reverting.
  • One-off orphaned/stale snapshot fixture (StorageBucketAPITests-testCreateBucket.1.txt, didn't match any current test) removed.

Root cause note (bug found during migration)

While migrating SupabaseStorageTests.uploadData/uploadFileURL, found that the original XCTest mocks wired their response-producing closure to StorageHTTPSession.fetch, not .upload — confirmed this is correct because production Storage code (StorageApi.swift) only ever calls configuration.session.fetch; .upload is currently dead code for all Storage HTTP calls including multipart uploads. My first conversion pass mistakenly moved the mock logic onto .upload, causing an unimplemented() failure — fixed by keeping the response logic on .fetch.

Test plan

  • swift build --build-tests: clean, no warnings beyond pre-existing intentional deprecated-API test warnings.
  • swift test --filter StorageTests: 139/139 tests pass (138 original XCTest methods + 1, from splitting a 10-case for-loop into two @Test(arguments:) parameterized tests covering the same 10 cases).
  • swift test (full suite): 0 failures outside IntegrationTests (which requires a local Supabase instance per AGENTS.md, pre-existing/expected without supabase start).
  • Zero import XCTest / import Mocker remaining in Tests/StorageTests (grep-verified).
  • ./scripts/format.sh and ./scripts/spell-check.sh clean.
  • Regression-test sanity check: intentionally swapped sourceKey/destinationKey in move(), confirmed the new body-matching test fails, then reverted.

Linear

Closes SDK-1250

Converts all 11 files in Tests/StorageTests from XCTest+Mocker to Swift
Testing (@Suite/@test) + Replay for HTTP mocking, per the SDK-435
migration plan and the Phase 0 conventions decided in SDK-1247.

- Adds the Replay package dependency and wires it into the StorageTests
  target; drops Mocker/TestHelpers (only used for the now-removed
  .snapshotRequest curl-snapshot assertions, dropped per plan with no
  shim).
- Moves StorageTests out of the blanket Swift 5 language-mode pin into
  full Swift 6 mode, matching production targets' strict-concurrency
  settings.
- StorageHTTPSession already supported fetch/upload closure injection
  (same pattern as FunctionsClient), so no new Storage-side scope was
  needed for Replay adoption.
- Adds request-body verification via Replay's `.custom` matcher for
  move/copy/remove (previously covered by .snapshotRequest), reading
  the body via httpBodyStream since URLSession no longer exposes it on
  httpBody once handed to the loading system.

Linear: SDK-1250
@grdsdev grdsdev requested a review from a team as a code owner July 8, 2026 21:16
@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: 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
  💔 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: 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: 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: class SupabaseClient has been removed
  💔 API breakage: struct SupabaseClientOptions 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

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

Copy link
Copy Markdown

Coverage Report for CI Build 28976348844

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.6 hits per line

💛 - Coveralls

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

3 participants