Skip to content

Commit 067d77d

Browse files
committed
Tests and tweaks
- Adds entitlements to redemption result - Makes PaywallInfo optional - Uses expiredSubscription when resetting - Adds some tests
1 parent 74bd0c1 commit 067d77d

6 files changed

Lines changed: 117 additions & 4 deletions

File tree

Sources/SuperwallKit/Models/Web2App/RedemptionResult.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public enum RedemptionResult: Codable {
2121
/// The code is invalid.
2222
case invalidCode(code: String)
2323

24-
/// The subscription that code redeems has expired.
24+
/// The subscription that the code redeems has expired.
2525
case expiredSubscription(code: String, redemptionInfo: RedemptionInfo)
2626

2727
/// Convenience variable to extract the code
@@ -61,7 +61,10 @@ public enum RedemptionResult: Codable {
6161
public let purchaserInfo: PurchaserInfo
6262

6363
/// Info about the paywall the purchase was made from.
64-
public let paywallInfo: PaywallInfo
64+
public let paywallInfo: PaywallInfo?
65+
66+
/// The entitlements array
67+
public let entitlements: [Entitlement]
6568

6669
/// Enum specifiying code ownership.
6770
public enum Ownership: Codable {

Sources/SuperwallKit/Storage/Cache/Cache.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,11 +371,15 @@ extension Cache {
371371

372372
/// Cleans codes that are owned by the user.
373373
func cleanUserCodes() {
374-
if var redeemResponse = read(LatestRedeemResponse.self) {
374+
if let redeemResponse = read(LatestRedeemResponse.self) {
375375
var deviceResults: [RedemptionResult] = []
376376
for result in redeemResponse.results {
377377
switch result {
378-
case let .success(code, redemptionInfo):
378+
case let .success(_, redemptionInfo):
379+
if case .device = redemptionInfo.ownership {
380+
deviceResults.append(result)
381+
}
382+
case let .expiredSubscription(_, redemptionInfo):
379383
if case .device = redemptionInfo.ownership {
380384
deviceResults.append(result)
381385
}
@@ -384,6 +388,8 @@ extension Cache {
384388
}
385389
}
386390

391+
// TODO: What to do with user owned entitlements on reset?
392+
// TODO: Only keeping results from success & expiredSubscription
387393
let newRedeemResponse = RedeemResponse(
388394
results: deviceResults,
389395
entitlements: redeemResponse.entitlements

Tests/SuperwallKitTests/Config/ConfigManagerTests.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ final class ConfigManagerTests: XCTestCase {
2929
paywallManager: dependencyContainer.paywallManager,
3030
deviceHelper: dependencyContainer.deviceHelper,
3131
entitlementsInfo: dependencyContainer.entitlementsInfo,
32+
webEntitlementRedeemer: dependencyContainer.redeemer,
3233
factory: dependencyContainer
3334
)
3435

@@ -93,6 +94,7 @@ final class ConfigManagerTests: XCTestCase {
9394
paywallManager: dependencyContainer.paywallManager,
9495
deviceHelper: dependencyContainer.deviceHelper,
9596
entitlementsInfo: dependencyContainer.entitlementsInfo,
97+
webEntitlementRedeemer: dependencyContainer.redeemer,
9698
factory: dependencyContainer
9799
)
98100
configManager.postbackAssignment(assignment)
@@ -127,6 +129,7 @@ final class ConfigManagerTests: XCTestCase {
127129
paywallManager: dependencyContainer.paywallManager,
128130
deviceHelper: dependencyContainer.deviceHelper,
129131
entitlementsInfo: dependencyContainer.entitlementsInfo,
132+
webEntitlementRedeemer: dependencyContainer.redeemer,
130133
factory: dependencyContainer
131134
)
132135
configManager.postbackAssignment(assignment)
@@ -154,6 +157,7 @@ final class ConfigManagerTests: XCTestCase {
154157
paywallManager: dependencyContainer.paywallManager,
155158
deviceHelper: dependencyContainer.deviceHelper,
156159
entitlementsInfo: dependencyContainer.entitlementsInfo,
160+
webEntitlementRedeemer: dependencyContainer.redeemer,
157161
factory: dependencyContainer
158162
)
159163

@@ -184,6 +188,7 @@ final class ConfigManagerTests: XCTestCase {
184188
paywallManager: dependencyContainer.paywallManager,
185189
deviceHelper: dependencyContainer.deviceHelper,
186190
entitlementsInfo: dependencyContainer.entitlementsInfo,
191+
webEntitlementRedeemer: dependencyContainer.redeemer,
187192
factory: dependencyContainer
188193
)
189194
configManager.configState.send(.retrieved(.stub()
@@ -209,6 +214,7 @@ final class ConfigManagerTests: XCTestCase {
209214
paywallManager: dependencyContainer.paywallManager,
210215
deviceHelper: dependencyContainer.deviceHelper,
211216
entitlementsInfo: dependencyContainer.entitlementsInfo,
217+
webEntitlementRedeemer: dependencyContainer.redeemer,
212218
factory: dependencyContainer
213219
)
214220

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//
2+
// File.swift
3+
// SuperwallKit
4+
//
5+
// Created by Yusuf Tör on 17/03/2025.
6+
//
7+
8+
import Foundation
9+
import Testing
10+
@testable import SuperwallKit
11+
12+
final class RedeemResponseTests {
13+
let successData = """
14+
{
15+
"codes": [
16+
{
17+
"status": "SUCCESS",
18+
"code": "redemption_8c7916a7-d48b-42c1-8eae-a58e0a57d37d",
19+
"redemptionInfo": {
20+
"ownership": {
21+
"type": "device",
22+
"deviceId": "$SuperwallDevice:24141E45-EDE8-4BD7-BCE9-A788228BCB0D"
23+
},
24+
"purchaserInfo": {
25+
"appUserId": "24141E45-EDE8-4BD7-BCE9-A788228BCB0D",
26+
"email": "asdasd@sdfsdf.com",
27+
"storeIdentifiers": {
28+
"store": "STRIPE",
29+
"stripeSubscriptionId": "sub_1R3awqBitwqMmwU0FEHl0ZJ6"
30+
}
31+
},
32+
"paywallInfo": null,
33+
"entitlements": []
34+
}
35+
}
36+
],
37+
"entitlements": []
38+
}
39+
""".data(using: .utf8)!
40+
41+
let invalidCode = """
42+
{
43+
"codes": [
44+
{
45+
"status": "INVALID_CODE",
46+
"code": "redemption_8c7916a7-d48bs-42c1-8eae-a58e0a57d37d"
47+
}
48+
],
49+
"entitlements": []
50+
}
51+
""".data(using: .utf8)!
52+
53+
@Test("Decodes success JSON")
54+
func testSuccessRedeemResponseDecoding() throws {
55+
let decoder = JSONDecoder()
56+
let response = try decoder.decode(RedeemResponse.self, from: successData)
57+
58+
#expect(response.results.count == 1)
59+
#expect(response.results.first?.code == "redemption_8c7916a7-d48b-42c1-8eae-a58e0a57d37d")
60+
#expect(response.entitlements.isEmpty)
61+
}
62+
63+
@Test("All codes extracts the codes")
64+
func testAllCodesProperty() throws {
65+
let decoder = JSONDecoder()
66+
let response = try decoder.decode(RedeemResponse.self, from: successData)
67+
68+
let expectedCode = Redeemable(code: "redemption_8c7916a7-d48b-42c1-8eae-a58e0a57d37d", isFirstRedemption: false)
69+
#expect(response.allCodes == Set([expectedCode]))
70+
}
71+
72+
@Test("Code is invalid")
73+
func testInvalidCode() throws {
74+
let decoder = JSONDecoder()
75+
let response = try decoder.decode(RedeemResponse.self, from: invalidCode)
76+
switch response.results.first! {
77+
case .invalidCode(let code):
78+
#expect(code == "redemption_8c7916a7-d48bs-42c1-8eae-a58e0a57d37d")
79+
default:
80+
Issue.record("Incorrect result type")
81+
}
82+
#expect(response.entitlements.isEmpty)
83+
}
84+
}

Tests/SuperwallKitTests/Paywall/Presentation/Internal Presentation/Operators/ConfirmHoldoutAssignmentTests.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ final class ConfirmHoldoutAssignmentOperatorTests: XCTestCase {
2323
paywallManager: dependencyContainer.paywallManager,
2424
deviceHelper: dependencyContainer.deviceHelper,
2525
entitlementsInfo: dependencyContainer.entitlementsInfo,
26+
webEntitlementRedeemer: dependencyContainer.redeemer,
2627
factory: dependencyContainer
2728
)
2829

@@ -54,6 +55,7 @@ final class ConfirmHoldoutAssignmentOperatorTests: XCTestCase {
5455
paywallManager: dependencyContainer.paywallManager,
5556
deviceHelper: dependencyContainer.deviceHelper,
5657
entitlementsInfo: dependencyContainer.entitlementsInfo,
58+
webEntitlementRedeemer: dependencyContainer.redeemer,
5759
factory: dependencyContainer
5860
)
5961

@@ -84,6 +86,7 @@ final class ConfirmHoldoutAssignmentOperatorTests: XCTestCase {
8486
paywallManager: dependencyContainer.paywallManager,
8587
deviceHelper: dependencyContainer.deviceHelper,
8688
entitlementsInfo: dependencyContainer.entitlementsInfo,
89+
webEntitlementRedeemer: dependencyContainer.redeemer,
8790
factory: dependencyContainer
8891
)
8992
try? await Task.sleep(nanoseconds: 10_000_000)
@@ -115,6 +118,7 @@ final class ConfirmHoldoutAssignmentOperatorTests: XCTestCase {
115118
paywallManager: dependencyContainer.paywallManager,
116119
deviceHelper: dependencyContainer.deviceHelper,
117120
entitlementsInfo: dependencyContainer.entitlementsInfo,
121+
webEntitlementRedeemer: dependencyContainer.redeemer,
118122
factory: dependencyContainer
119123
)
120124
try? await Task.sleep(nanoseconds: 10_000_000)
@@ -146,6 +150,7 @@ final class ConfirmHoldoutAssignmentOperatorTests: XCTestCase {
146150
paywallManager: dependencyContainer.paywallManager,
147151
deviceHelper: dependencyContainer.deviceHelper,
148152
entitlementsInfo: dependencyContainer.entitlementsInfo,
153+
webEntitlementRedeemer: dependencyContainer.redeemer,
149154
factory: dependencyContainer
150155
)
151156
try? await Task.sleep(nanoseconds: 10_000_000)
@@ -177,6 +182,7 @@ final class ConfirmHoldoutAssignmentOperatorTests: XCTestCase {
177182
paywallManager: dependencyContainer.paywallManager,
178183
deviceHelper: dependencyContainer.deviceHelper,
179184
entitlementsInfo: dependencyContainer.entitlementsInfo,
185+
webEntitlementRedeemer: dependencyContainer.redeemer,
180186
factory: dependencyContainer
181187
)
182188
try? await Task.sleep(nanoseconds: 10_000_000)
@@ -208,6 +214,7 @@ final class ConfirmHoldoutAssignmentOperatorTests: XCTestCase {
208214
paywallManager: dependencyContainer.paywallManager,
209215
deviceHelper: dependencyContainer.deviceHelper,
210216
entitlementsInfo: dependencyContainer.entitlementsInfo,
217+
webEntitlementRedeemer: dependencyContainer.redeemer,
211218
factory: dependencyContainer
212219
)
213220
try? await Task.sleep(nanoseconds: 10_000_000)

Tests/SuperwallKitTests/Paywall/Presentation/Internal Presentation/Operators/ConfirmPaywallAssignmentOperatorTests.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ final class ConfirmPaywallAssignmentOperatorTests: XCTestCase {
2323
paywallManager: dependencyContainer.paywallManager,
2424
deviceHelper: dependencyContainer.deviceHelper,
2525
entitlementsInfo: dependencyContainer.entitlementsInfo,
26+
webEntitlementRedeemer: dependencyContainer.redeemer,
2627
factory: dependencyContainer
2728
)
2829
try? await Task.sleep(nanoseconds: 10_000_000)
@@ -49,6 +50,7 @@ final class ConfirmPaywallAssignmentOperatorTests: XCTestCase {
4950
paywallManager: dependencyContainer.paywallManager,
5051
deviceHelper: dependencyContainer.deviceHelper,
5152
entitlementsInfo: dependencyContainer.entitlementsInfo,
53+
webEntitlementRedeemer: dependencyContainer.redeemer,
5254
factory: dependencyContainer
5355
)
5456
try? await Task.sleep(nanoseconds: 10_000_000)
@@ -76,6 +78,7 @@ final class ConfirmPaywallAssignmentOperatorTests: XCTestCase {
7678
paywallManager: dependencyContainer.paywallManager,
7779
deviceHelper: dependencyContainer.deviceHelper,
7880
entitlementsInfo: dependencyContainer.entitlementsInfo,
81+
webEntitlementRedeemer: dependencyContainer.redeemer,
7982
factory: dependencyContainer
8083
)
8184
try? await Task.sleep(nanoseconds: 10_000_000)
@@ -108,6 +111,7 @@ final class ConfirmPaywallAssignmentOperatorTests: XCTestCase {
108111
paywallManager: dependencyContainer.paywallManager,
109112
deviceHelper: dependencyContainer.deviceHelper,
110113
entitlementsInfo: dependencyContainer.entitlementsInfo,
114+
webEntitlementRedeemer: dependencyContainer.redeemer,
111115
factory: dependencyContainer
112116
)
113117
try? await Task.sleep(nanoseconds: 10_000_000)
@@ -140,6 +144,7 @@ final class ConfirmPaywallAssignmentOperatorTests: XCTestCase {
140144
paywallManager: dependencyContainer.paywallManager,
141145
deviceHelper: dependencyContainer.deviceHelper,
142146
entitlementsInfo: dependencyContainer.entitlementsInfo,
147+
webEntitlementRedeemer: dependencyContainer.redeemer,
143148
factory: dependencyContainer
144149
)
145150
try? await Task.sleep(nanoseconds: 10_000_000)
@@ -172,6 +177,7 @@ final class ConfirmPaywallAssignmentOperatorTests: XCTestCase {
172177
paywallManager: dependencyContainer.paywallManager,
173178
deviceHelper: dependencyContainer.deviceHelper,
174179
entitlementsInfo: dependencyContainer.entitlementsInfo,
180+
webEntitlementRedeemer: dependencyContainer.redeemer,
175181
factory: dependencyContainer
176182
)
177183
try? await Task.sleep(nanoseconds: 10_000_000)
@@ -204,6 +210,7 @@ final class ConfirmPaywallAssignmentOperatorTests: XCTestCase {
204210
paywallManager: dependencyContainer.paywallManager,
205211
deviceHelper: dependencyContainer.deviceHelper,
206212
entitlementsInfo: dependencyContainer.entitlementsInfo,
213+
webEntitlementRedeemer: dependencyContainer.redeemer,
207214
factory: dependencyContainer
208215
)
209216
try? await Task.sleep(nanoseconds: 10_000_000)

0 commit comments

Comments
 (0)