Repository navigation
feat: Test Mode — test store products, purchase/restore overrides, dark mode UI - #425
Conversation
Add CodingKeys for snake_case decoding since Web2App decoder doesn't auto-convert from snake case. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Maps V2Product API response data into a StoreProductType for use as a test store product backed by the Superwall API. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add TestModeManager for detecting test mode users via config - Add TestStoreUser model parsed from config testStoreUsers - Add TestModeColdLaunchAlert for showing test mode status on launch - Add TestModePurchaseDrawer for simulating purchases (purchase/abandon/fail) - Add TestModeTransactionHandler to intercept purchase and restore flows - Override StoreKitManager.getProducts to use cached test products - Override TransactionManager.purchase to show test mode drawer - Override TransactionManager.tryToRestore to show entitlement picker - Override DeviceHelper.isSandbox to return true in test mode - Rename V2Product to SuperwallProduct across codebase - Fetch products from /v1/products endpoint on config load when test mode Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…tsById Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add bundleId to config endpoint application query - Include bundle_id_config in config JSON response - Decode bundleIdConfig in Swift Config model - Check bundle ID mismatch in evaluateTestMode — activates test mode when app bundle ID doesn't match config Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Additional Comments (2)
Prompt To Fix With AIThis is a comment left during a code review.
Path: Sources/SuperwallKit/Config/Models/Config.swift
Line: 118:142
Comment:
**Config.encode changed semantics**
`Config.encode(to:)` now always encodes `web2appConfig`, `iosAppId`, `bundleIdConfig`, and `testModeUserIds` (if present), whereas previously those fields were not encoded at all. If this `Codable` type is used for caching/round-tripping configs (e.g. persisted `LatestConfig`), this changes the on-disk JSON shape and can break decode expectations in older versions or any code assuming a server-shaped payload. If the intent is “cache the server response as-is”, consider keeping encoding symmetric with what the server sends, or isolating persistence to a dedicated type instead of changing `Config`’s encoding behavior.
How can I resolve this? If you propose a fix, please make it concise.
(See Prompt To Fix With AIThis is a comment left during a code review.
Path: Sources/SuperwallKit/Config/ConfigManager.swift
Line: 438:446
Comment:
**MainActor isolation mismatch**
`presentTestModeModal` is `@MainActor`, but it’s awaited directly from `processConfig` (which is not `@MainActor`). This will fail under strict concurrency checking / actor isolation rules. Wrap the call with `await MainActor.run { ... }` / `Task { @MainActor in ... }`, or make the caller main-actor isolated.
(See `presentTestModeModal` declaration later in this file.)
How can I resolve this? If you propose a fix, please make it concise. |
Adds a new `debugModeBehavior` property to `SuperwallOptions` that gives developers explicit control over when test mode activates: - `.automatic` (default): activates on dashboard match or bundle ID mismatch, but never during UI tests - `.whenEnabledForUser`: only activates on dashboard user match - `.never`: test mode is never activated - `.always`: test mode is always activated Also forces `shouldBypassAppTransactionCheck = true` in UI test environments so StoreKit checks don't block test runners. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added superwall logo to test payment sheet
… detection - Rename DebugModeBehavior -> TestModeBehavior, debugModeBehavior -> testModeBehavior - Rename SWKDebugModeBehavior -> SWKTestModeBehavior (ObjC) - Rename debugOption -> testModeOption - Rename isUITestEnvironment -> isTestEnvironment - Skip test mode in test environments unless SUPERWALL_UNIT_TESTS launch arg is set - Update tests to work correctly with the new environment detection Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use where clause instead of if inside for loop - Remove superfluous swiftlint disable commands - Remove extra blank line before closing brace Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add testModeBehavior option to SuperwallOptions
Summary
Core Test Mode
/v1/productsendpoint, caches asStoreProductisSandbox = "true"when test mode active so all events route to sandboxTestModeBehavior Option
TestModeBehaviorenum (.automatic,.whenEnabledForUser,.never,.always) toSuperwallOptionsfor explicit control over when test mode activatesisTestEnvironmentdetects test runners viaNSClassFromString("XCTestCase")but bypasses whenSUPERWALL_UNIT_TESTSlaunch arg is present for internal unit testsDark Mode UI
TestModePurchaseDrawer.label,.secondaryLabel,.separator, etc.) for proper light/dark mode supportMisc
TestModeManagerand allTestModeBehaviorcasesChecklist
CHANGELOG.mdfor any breaking changes, enhancements, or bug fixes.swiftlintin the main directory and fixed any issues.🤖 Generated with Claude Code