Testing In-App Purchases
Relevant source files
The following files were used as context for generating this wiki page:
- README.md
- Features/SettingsFeature/Tests/SettingsFeatureTests/Views/Paywall/PaywallViewModelTests.swift
- Features/AppFeature/Tests/AppFeatureTests/Views/AppRootViewModelTests.swift
- Features/ExpensesFeature/Tests/ExpensesFeatureTests/Views/SubscriptionList/SubscriptionListViewModelTests.swift
- CLAUDE.md
The Trackurr project implements a robust In-App Purchase (IAP) system utilizing StoreKit 2 to manage premium tiers (monthly and annual). The testing strategy encompasses unit tests for view model logic, lifecycle management of transaction listeners, and verification of free-tier limitations.
Sources: README.md:38-41, README.md:155-160
Testing Architecture
The IAP system is built around the PurchaseService protocol, which is injected into various ViewModels using the Factory dependency injection framework. For testing purposes, a PurchaseServiceMock is used to simulate different entitlement statuses, product availability, and transaction results.
Core Components
- PaywallViewModel: Manages the state of the paywall UI, including product loading, selection of plans, and execution of purchase or restore actions.
- AppRootViewModel: Responsible for initializing the transaction listener at the app level to capture background transaction updates.
- EntitlementService: Evaluates whether a user can perform certain actions (like creating new subscriptions) based on their current purchase status.
Sources: Features/SettingsFeature/Tests/SettingsFeatureTests/Views/Paywall/PaywallViewModelTests.swift:425-432, Features/AppFeature/Tests/AppFeatureTests/Views/AppRootViewModelTests.swift:245-255, Features/ExpensesFeature/Tests/ExpensesFeatureTests/Views/SubscriptionList/SubscriptionListViewModelTests.swift:245-255
Purchase Sequence Flow
The following diagram illustrates the interaction between the UI layer, the ViewModel, and the Mocked Service during a purchase test.
This diagram shows the standard flow for fetching and purchasing products as validated in unit tests.
Sources: Features/SettingsFeature/Tests/SettingsFeatureTests/Views/Paywall/PaywallViewModelTests.swift:45-135
Unit Testing Logic
Unit tests for IAP focus on state transitions within the PaywallViewModel. Tests verify that the UI correctly reflects the purchasing process and handles errors gracefully.
State Management
Tests ensure that flags such as isPurchasing and isRestoring are correctly toggled during asynchronous service calls.
| Property | Initial Value | Post-Action Value (Success) |
|---|---|---|
isPurchasing | false | false (via defer/finally) |
purchaseSucceeded | false | true |
showError | false | false |
selectedPlan | .annual | No change |
Sources: Features/SettingsFeature/Tests/SettingsFeatureTests/Views/Paywall/PaywallViewModelTests.swift:17-30, Features/SettingsFeature/Tests/SettingsFeatureTests/Views/Paywall/PaywallViewModelTests.swift:140-160
Error and Restore Scenarios
Testing includes edge cases such as:
- Empty Product Lists: Verifying the view model handles scenarios where StoreKit returns no products.
- Restore with No Purchases: Ensuring a "No previous purchases found" message is displayed when a restore action yields a
.freeentitlement. - Service Errors: Simulating thrown errors from the
PurchaseServiceto confirm that error messages are populated and displayed to the user.
Sources: Features/SettingsFeature/Tests/SettingsFeatureTests/Views/Paywall/PaywallViewModelTests.swift:75-85, Features/SettingsFeature/Tests/SettingsFeatureTests/Views/Paywall/PaywallViewModelTests.swift:215-225, Features/SettingsFeature/Tests/SettingsFeatureTests/Views/Paywall/PaywallViewModelTests.swift:230-245
Integration and Environments
According to the project documentation, IAP testing is conducted across four primary environments to ensure reliability before production release.
Testing covers step-by-step flows for each plan, free tier limit verification, and common pitfalls.
Sources: README.md:155-160
Free Tier Limitations
Tests in the SubscriptionListViewModel verify that the app correctly gates features based on entitlements. The canCreateSubscription property delegates to the EntitlementService to enforce limits on the number of subscriptions a user can track without a premium plan.
Analytics Verification
IAP testing also includes verification of analytics logging for business intelligence. The PaywallViewModel is tested to ensure it logs specific events based on the PaywallSource.
- paywall_shown: Logged when products are loaded, including the source (e.g.,
settings,subscriptionLimit,dataExport). - paywall_dismissed: Logged when the user exits the paywall without purchasing.
Transaction Listener Lifecycle
The AppRootViewModel starts a transaction listener upon initialization. This is a critical component for testing as it ensures that any transactions processed outside the app (e.g., subscription renewals or App Store refunds) are captured and reflected in the user's entitlement status.
Sources: Features/AppFeature/Tests/AppFeatureTests/Views/AppRootViewModelTests.swift:245-255
Testing In-App Purchases in Trackurr ensures that the financial core of the app remains reliable. By using a combination of mock-based unit tests for UI states and multi-environment manual verification, the project maintains high standards for transaction security and user experience.