From 4c20917008a64e4f34c74d34a25cf9712c11267c Mon Sep 17 00:00:00 2001 From: NachoSoto Date: Wed, 20 Sep 2023 14:30:09 -0700 Subject: [PATCH] Improved logic and added tests --- RevenueCatUI/Data/TestData.swift | 61 ++++++++++++++++--- .../Purchasing/PurchaseHandler+TestData.swift | 6 +- RevenueCatUI/Purchasing/PurchaseHandler.swift | 7 ++- RevenueCatUI/Views/FooterView.swift | 5 +- .../Purchasing/PurchaseHandlerTests.swift | 13 +++- 5 files changed, 76 insertions(+), 16 deletions(-) diff --git a/RevenueCatUI/Data/TestData.swift b/RevenueCatUI/Data/TestData.swift index 73220396b6..292e0fff14 100644 --- a/RevenueCatUI/Data/TestData.swift +++ b/RevenueCatUI/Data/TestData.swift @@ -440,7 +440,8 @@ internal enum TestData { #endif static let customerInfo: CustomerInfo = { - let json = """ + return .decode( + """ { "schema_version": "4", "request_date": "2022-03-08T17:42:58Z", @@ -463,13 +464,46 @@ internal enum TestData { } } """ + ) + }() - let decoder = JSONDecoder() - decoder.keyDecodingStrategy = .convertFromSnakeCase - decoder.dateDecodingStrategy = .iso8601 - - // swiftlint:disable:next force_try - return try! decoder.decode(CustomerInfo.self, from: Data(json.utf8)) + static let customerInfoWithSubscriptions: CustomerInfo = { + return .decode( + """ + { + "schema_version": "4", + "request_date": "2022-03-08T17:42:58Z", + "request_date_ms": 1646761378845, + "subscriber": { + "first_seen": "2022-03-08T17:42:58Z", + "last_seen": "2022-03-08T17:42:58Z", + "management_url": "https://apps.apple.com/account/subscriptions", + "non_subscriptions": { + }, + "original_app_user_id": "$RCAnonymousID:5b6fdbac3a0c4f879e43d269ecdf9ba1", + "original_application_version": "1.0", + "original_purchase_date": "2022-04-12T00:03:24Z", + "other_purchases": { + }, + "subscriptions": { + "com.revenuecat.product": { + "billing_issues_detected_at": null, + "expires_date": "2062-04-12T00:03:35Z", + "grace_period_expires_date": null, + "is_sandbox": true, + "original_purchase_date": "2022-04-12T00:03:28Z", + "period_type": "intro", + "purchase_date": "2022-04-12T00:03:28Z", + "store": "app_store", + "unsubscribe_detected_at": null + }, + }, + "entitlements": { + } + } + } + """ + ) }() static let localization1: PaywallData.LocalizedConfiguration = .init( @@ -540,4 +574,17 @@ extension PackageType { } +private extension CustomerInfo { + + static func decode(_ json: String) -> Self { + let decoder = JSONDecoder() + decoder.keyDecodingStrategy = .convertFromSnakeCase + decoder.dateDecodingStrategy = .iso8601 + + // swiftlint:disable:next force_try + return try! decoder.decode(Self.self, from: Data(json.utf8)) + } + +} + #endif diff --git a/RevenueCatUI/Purchasing/PurchaseHandler+TestData.swift b/RevenueCatUI/Purchasing/PurchaseHandler+TestData.swift index 3dc0bc3d02..5d9f2f21d7 100644 --- a/RevenueCatUI/Purchasing/PurchaseHandler+TestData.swift +++ b/RevenueCatUI/Purchasing/PurchaseHandler+TestData.swift @@ -19,16 +19,16 @@ import RevenueCat @available(iOS 15.0, macOS 12.0, tvOS 15.0, *) extension PurchaseHandler { - static func mock() -> Self { + static func mock(customerInfo: CustomerInfo = TestData.customerInfo) -> Self { return self.init( purchases: MockPurchases { _ in return ( transaction: nil, - customerInfo: TestData.customerInfo, + customerInfo: customerInfo, userCancelled: false ) } restorePurchases: { - return TestData.customerInfo + return customerInfo } trackEvent: { event in Logger.debug("Tracking event: \(event)") } diff --git a/RevenueCatUI/Purchasing/PurchaseHandler.swift b/RevenueCatUI/Purchasing/PurchaseHandler.swift index 3cb01a3b0c..1bd2e30e49 100644 --- a/RevenueCatUI/Purchasing/PurchaseHandler.swift +++ b/RevenueCatUI/Purchasing/PurchaseHandler.swift @@ -91,8 +91,10 @@ extension PurchaseHandler { return result } + /// - Returns: `success` is `true` only when the resulting `CustomerInfo` + /// had any transactions @MainActor - func restorePurchases() async throws -> CustomerInfo { + func restorePurchases() async throws -> (info: CustomerInfo, success: Bool) { self.actionInProgress = true defer { self.actionInProgress = false } @@ -103,7 +105,8 @@ extension PurchaseHandler { self.restoredCustomerInfo = customerInfo } - return customerInfo + return (customerInfo, + success: !customerInfo.activeSubscriptions.isEmpty) } func trackPaywallImpression(_ eventData: PaywallEvent.Data) { diff --git a/RevenueCatUI/Views/FooterView.swift b/RevenueCatUI/Views/FooterView.swift index ae68f22467..2886e0a8e2 100644 --- a/RevenueCatUI/Views/FooterView.swift +++ b/RevenueCatUI/Views/FooterView.swift @@ -167,9 +167,8 @@ private struct RestorePurchasesButton: View { var body: some View { AsyncButton { - let customerInfo = try await self.purchaseHandler.restorePurchases() - - if !customerInfo.entitlements.active.isEmpty { + let success = try await self.purchaseHandler.restorePurchases().success + if success { self.displayRestoredAlert = true } } label: { diff --git a/Tests/RevenueCatUITests/Purchasing/PurchaseHandlerTests.swift b/Tests/RevenueCatUITests/Purchasing/PurchaseHandlerTests.swift index 0c3b3af819..8f571e6b8b 100644 --- a/Tests/RevenueCatUITests/Purchasing/PurchaseHandlerTests.swift +++ b/Tests/RevenueCatUITests/Purchasing/PurchaseHandlerTests.swift @@ -55,13 +55,24 @@ class PurchaseHandlerTests: TestCase { func testRestorePurchases() async throws { let handler: PurchaseHandler = .mock() - _ = try await handler.restorePurchases() + let result = try await handler.restorePurchases() + + expect(result.info) === TestData.customerInfo + expect(result.success) == false expect(handler.restored) == true expect(handler.restoredCustomerInfo) === TestData.customerInfo expect(handler.purchasedCustomerInfo).to(beNil()) expect(handler.actionInProgress) == false } + func testRestorePurchasesWithNoTransactions() async throws { + let handler: PurchaseHandler = .mock(customerInfo: TestData.customerInfoWithSubscriptions) + + let result = try await handler.restorePurchases() + expect(result.info) === TestData.customerInfoWithSubscriptions + expect(result.success) == true + } + } #endif