πŸ”βŒ˜K

Start typing to search docs.

TestFlight Sandbox (Legacy)

1.0.0Legacy

Reference for TestFlight sandbox setup during pre-Supabase era.

Legacy Reference

This integration guide predates the Supabase multi-tenant rollout. Treat it as historical context and confirm requirements before using it in new flows.

TestFlight Sandbox Setup Guide

Legacy
Captures the historic iOS in-app purchase workflow. The current platform focuses on Supabase-hosted web apps; use this only if reviving the old mobile pipeline.

This guide covers setting up TestFlight sandbox testing for iOS in-app purchases using RevenueCat integration.

Overview

TestFlight sandbox testing allows you to test subscription flows with real App Store mechanics but without actual charges. This is essential for validating:

  • In-app purchase flows
  • Subscription management
  • Receipt validation
  • RevenueCat integration
  • App Store review compliance

Prerequisites

  • Apple Developer Account
  • iOS app configured in App Store Connect
  • RevenueCat account and project setup
  • Xcode with valid signing certificates

App Store Connect Setup

1. Configure In-App Purchases

  1. Navigate to App Store Connect

  2. Create In-App Purchases

    Features β†’ In-App Purchases β†’ Create
    

    Create the following subscription products:

    Product ID: premium_monthly
    Reference Name: Premium Monthly Subscription
    Type: Auto-Renewable Subscription
    Subscription Group: Premium Subscriptions
    Duration: 1 Month
    Price: $9.99
    
    Product ID: premium_annual
    Reference Name: Premium Annual Subscription  
    Type: Auto-Renewable Subscription
    Subscription Group: Premium Subscriptions
    Duration: 1 Year
    Price: $99.99
    
  3. Configure Subscription Groups

    • Create subscription group: "Premium Subscriptions"
    • Set upgrade/downgrade behavior
    • Configure family sharing settings

2. Create Sandbox Test Users

  1. Navigate to Sandbox Testers

    Users and Access β†’ Sandbox β†’ Testers
    
  2. Create Test Users

    Email: testuser1@example.com
    Password: TestPass123!
    First Name: Test
    Last Name: User
    Date of Birth: 01/01/1990
    Country/Region: United States
    

    Create multiple test users for different scenarios:

    • testuser1@example.com - Basic testing
    • testuser2@example.com - Subscription management
    • testuser3@example.com - Payment failures
    • testuser4@example.com - Family sharing

RevenueCat Configuration

1. Project Setup

  1. Create RevenueCat Project

  2. Configure iOS App

    Project Settings β†’ Apps β†’ Add App
    Platform: iOS
    Bundle ID: com.appfactory.yourapp
    App Store Connect App ID: [Your App ID]
    
  3. Add Products

    Products β†’ Add Product
    Product ID: premium_monthly
    Type: Subscription
    Store: App Store
    

2. API Keys

  1. Generate API Keys

    Project Settings β†’ API Keys
    Create new key: "Mobile Testing"
    
  2. Configure Environment Variables

    # Add to your .env file
    REVENUECAT_API_KEY=your_api_key_here
    REVENUECAT_SANDBOX=true
    

iOS App Configuration

1. RevenueCat SDK Integration

Add RevenueCat to your iOS project:

// Package.swift or Podfile
dependencies: [
    .package(url: "https://github.com/RevenueCat/purchases-ios.git", from: "4.0.0")
]

2. Initialize RevenueCat

// AppDelegate.swift
import RevenueCat

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    // Configure RevenueCat
    Purchases.logLevel = .debug
    Purchases.configure(withAPIKey: "your_revenuecat_api_key")
    
    return true
}

3. Implement Purchase Flow

// SubscriptionViewController.swift
import RevenueCat

class SubscriptionViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        loadOfferings()
    }
    
    func loadOfferings() {
        Purchases.shared.getOfferings { [weak self] offerings, error in
            if let error = error {
                print("Error loading offerings: \\(error)")
                return
            }
            
            guard let offerings = offerings,
                  let currentOffering = offerings.current else {
                print("No current offering available")
                return
            }
            
            // Display available packages
            self?.displayPackages(currentOffering.availablePackages)
        }
    }
    
    func purchasePackage(_ package: Package) {
        Purchases.shared.purchase(package: package) { [weak self] transaction, customerInfo, error, userCancelled in
            
            if userCancelled {
                print("User cancelled purchase")
                return
            }
            
            if let error = error {
                print("Purchase error: \\(error)")
                self?.handlePurchaseError(error)
                return
            }
            
            if let customerInfo = customerInfo {
                print("Purchase successful!")
                self?.handleSuccessfulPurchase(customerInfo)
            }
        }
    }
    
    func restorePurchases() {
        Purchases.shared.restorePurchases { [weak self] customerInfo, error in
            if let error = error {
                print("Restore error: \\(error)")
                return
            }
            
            if let customerInfo = customerInfo {
                print("Purchases restored")
                self?.updateSubscriptionStatus(customerInfo)
            }
        }
    }
}

TestFlight Distribution

1. Build Configuration

Create a specific build configuration for TestFlight testing:

// Config.swift
#if TESTFLIGHT
    static let isTestFlight = true
    static let revenueCatAPIKey = "your_testflight_api_key"
#else
    static let isTestFlight = false
    static let revenueCatAPIKey = "your_production_api_key"
#endif

2. Upload to TestFlight

  1. Archive Your App

    Xcode β†’ Product β†’ Archive
    
  2. Upload to App Store Connect

    Organizer β†’ Distribute App β†’ App Store Connect
    
  3. Configure TestFlight

    App Store Connect β†’ TestFlight β†’ Internal Testing
    Add testers and groups
    

Testing Scenarios

1. Basic Purchase Flow

// Test scenario configuration
const testFlightScenarios = [
  {
    name: 'Basic Monthly Purchase',
    steps: [
      'Launch app from TestFlight',
      'Navigate to subscription screen',
      'Select monthly plan',
      'Complete purchase with sandbox user',
      'Verify subscription status',
      'Check RevenueCat dashboard'
    ],
    expectedResults: {
      subscriptionActive: true,
      revenueCatEntitlement: 'premium',
      appStoreReceipt: 'valid'
    }
  }
];

2. Subscription Management

Test subscription lifecycle:

// Test subscription states
enum SubscriptionTestState {
    case trial
    case active
    case expired
    case cancelled
    case billingRetry
    case gracePeriod
}

func testSubscriptionState(_ state: SubscriptionTestState) {
    // Implementation for testing different states
    switch state {
    case .trial:
        // Test trial period behavior
        break
    case .active:
        // Test active subscription features
        break
    case .expired:
        // Test expired subscription handling
        break
    // ... other cases
    }
}

3. Error Handling

Test various error scenarios:

func testErrorScenarios() {
    // Test network errors
    // Test payment failures
    // Test receipt validation errors
    // Test RevenueCat API errors
}

Automated Testing Integration

1. XCTest Integration

// SubscriptionTests.swift
import XCTest
import RevenueCat
@testable import YourApp

class SubscriptionTests: XCTestCase {
    
    override func setUp() {
        super.setUp()
        // Configure test environment
        Purchases.configure(withAPIKey: "test_api_key")
    }
    
    func testPurchaseFlow() {
        let expectation = XCTestExpectation(description: "Purchase completes")
        
        // Mock purchase flow
        MockRevenueCat.shared.simulatePurchase(productId: "premium_monthly") { result in
            XCTAssertTrue(result.success)
            expectation.fulfill()
        }
        
        wait(for: [expectation], timeout: 10.0)
    }
}

2. Detox Integration

// e2e/subscription.test.js
describe('Subscription Flow', () => {
  beforeEach(async () => {
    await device.reloadReactNativeApp();
  });

  it('should complete subscription purchase', async () => {
    await element(by.id('subscription-button')).tap();
    await element(by.id('monthly-plan')).tap();
    await element(by.id('purchase-button')).tap();
    
    // Handle App Store purchase dialog
    await element(by.text('Buy')).tap();
    
    // Verify success
    await expect(element(by.id('subscription-active'))).toBeVisible();
  });
});

Monitoring and Analytics

1. RevenueCat Dashboard

Monitor key metrics:

  • Active subscriptions
  • Conversion rates
  • Churn analysis
  • Revenue tracking

2. Custom Analytics

// Analytics.swift
class SubscriptionAnalytics {
    
    static func trackPurchaseAttempt(productId: String) {
        // Track purchase attempts
    }
    
    static func trackPurchaseSuccess(productId: String, revenue: Decimal) {
        // Track successful purchases
    }
    
    static func trackPurchaseFailure(productId: String, error: Error) {
        // Track purchase failures
    }
}

Troubleshooting

Common Issues

  1. Sandbox User Issues

    • Sign out of production App Store account
    • Use fresh sandbox accounts for testing
    • Clear app data between tests
  2. Receipt Validation Failures

    • Verify RevenueCat configuration
    • Check bundle ID matches
    • Ensure products are approved in App Store Connect
  3. Purchase Flow Issues

    • Test with different sandbox users
    • Verify product IDs match exactly
    • Check subscription group configuration

Debug Tools

  1. RevenueCat Debug Logs

    Purchases.logLevel = .verbose
    
  2. App Store Receipt Validation

    func validateReceipt() {
        if let receiptURL = Bundle.main.appStoreReceiptURL,
           let receiptData = try? Data(contentsOf: receiptURL) {
            // Validate receipt with RevenueCat
        }
    }
    

Best Practices

  1. Test Early and Often

    • Start testing during development
    • Test on multiple devices and iOS versions
    • Use different sandbox accounts
  2. Comprehensive Scenario Coverage

    • Test all subscription tiers
    • Test upgrade/downgrade flows
    • Test restoration scenarios
    • Test error conditions
  3. Monitor Performance

    • Track purchase completion rates
    • Monitor API response times
    • Watch for receipt validation issues
  4. Documentation

    • Document test procedures
    • Maintain test user credentials
    • Keep RevenueCat configuration updated

Resources