From 069df52867b59dfaeffb6c15dd8fd8ab12499356 Mon Sep 17 00:00:00 2001 From: Josh Holtz Date: Thu, 9 Jan 2025 11:16:20 -0600 Subject: [PATCH] [Paywalls V2] Decode rectangle corners as optional (#4640) * Decode rectangle corners as optional * And fix for shape * Added tests --- RevenueCat.xcodeproj/project.pbxproj | 20 +++++ .../PaywallComponentPropertyTypes.swift | 4 +- .../PaywallsTester/Config/ConfigItem.swift | 2 +- .../Properties/MaskShapeComponentTests.swift | 82 +++++++++++++++++++ .../Properties/ShapeComponentTests.swift | 56 +++++++++++++ .../Components/StackComponentTests.swift | 46 +++++++++++ 6 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 Tests/UnitTests/Paywalls/Components/Properties/MaskShapeComponentTests.swift create mode 100644 Tests/UnitTests/Paywalls/Components/Properties/ShapeComponentTests.swift create mode 100644 Tests/UnitTests/Paywalls/Components/StackComponentTests.swift diff --git a/RevenueCat.xcodeproj/project.pbxproj b/RevenueCat.xcodeproj/project.pbxproj index b5eb658028..b4127d8b8c 100644 --- a/RevenueCat.xcodeproj/project.pbxproj +++ b/RevenueCat.xcodeproj/project.pbxproj @@ -16,6 +16,9 @@ 03A98D322D2441B8009BCA61 /* PaywallDataDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A98D312D2441B2009BCA61 /* PaywallDataDecodingTests.swift */; }; 03A98D362D244329009BCA61 /* UIConfigDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A98D352D244321009BCA61 /* UIConfigDecodingTests.swift */; }; 03A98D382D2AC63B009BCA61 /* UIConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03A98D372D2AC637009BCA61 /* UIConfigProvider.swift */; }; + 03F446212D2F73240046129A /* StackComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F446202D2F73210046129A /* StackComponentTests.swift */; }; + 03F446242D2FE0C50046129A /* ShapeComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F446232D2FE0C10046129A /* ShapeComponentTests.swift */; }; + 03F446262D2FE1510046129A /* MaskShapeComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03F446252D2FE1510046129A /* MaskShapeComponentTests.swift */; }; 1E2F910B2CC8FE5600BDB016 /* ContactSupportUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2F910A2CC8FE5600BDB016 /* ContactSupportUtilities.swift */; }; 1E2F911B2CC918ED00BDB016 /* ContactSupportUtilitiesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2F911A2CC918ED00BDB016 /* ContactSupportUtilitiesTests.swift */; }; 1E2F91722CCFA98C00BDB016 /* WebRedemptionStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2F91712CCFA98C00BDB016 /* WebRedemptionStrings.swift */; }; @@ -1248,6 +1251,9 @@ 03A98D312D2441B2009BCA61 /* PaywallDataDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaywallDataDecodingTests.swift; sourceTree = ""; }; 03A98D352D244321009BCA61 /* UIConfigDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIConfigDecodingTests.swift; sourceTree = ""; }; 03A98D372D2AC637009BCA61 /* UIConfigProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIConfigProvider.swift; sourceTree = ""; }; + 03F446202D2F73210046129A /* StackComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackComponentTests.swift; sourceTree = ""; }; + 03F446232D2FE0C10046129A /* ShapeComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShapeComponentTests.swift; sourceTree = ""; }; + 03F446252D2FE1510046129A /* MaskShapeComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaskShapeComponentTests.swift; sourceTree = ""; }; 1E2F910A2CC8FE5600BDB016 /* ContactSupportUtilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportUtilities.swift; sourceTree = ""; }; 1E2F911A2CC918ED00BDB016 /* ContactSupportUtilitiesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactSupportUtilitiesTests.swift; sourceTree = ""; }; 1E2F91712CCFA98C00BDB016 /* WebRedemptionStrings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRedemptionStrings.swift; sourceTree = ""; }; @@ -2471,6 +2477,15 @@ path = RevenueCatUI; sourceTree = ""; }; + 03F446222D2FE0B90046129A /* Properties */ = { + isa = PBXGroup; + children = ( + 03F446232D2FE0C10046129A /* ShapeComponentTests.swift */, + 03F446252D2FE1510046129A /* MaskShapeComponentTests.swift */, + ); + path = Properties; + sourceTree = ""; + }; 1E8A60402CDBD73E0034ACF3 /* WebPurchaseRedemption */ = { isa = PBXGroup; children = ( @@ -2571,6 +2586,8 @@ 2C8EC6AD2CCBD33800D6CCF8 /* Components */ = { isa = PBXGroup; children = ( + 03F446222D2FE0B90046129A /* Properties */, + 03F446202D2F73210046129A /* StackComponentTests.swift */, 03A98CEE2D1EE040009BCA61 /* FallbackComponentTests.swift */, 2C08B2E82CD40DBF0024857B /* ButtonComponentTests.swift */, 2C8EC6DE2CCD27A100D6CCF8 /* PartialComponentTests.swift */, @@ -6251,6 +6268,7 @@ A524378B284FFF0200E788BD /* AttributionPosterTests.swift in Sources */, 57E2230727500BB1002DB06E /* AtomicTests.swift in Sources */, 351B51B826D450E800BD2BD7 /* StoreKit1WrapperTests.swift in Sources */, + 03F446212D2F73240046129A /* StackComponentTests.swift in Sources */, A56C2E012819C33500995421 /* BackendPostAdServicesTokenTests.swift in Sources */, 5766AAD5283E9B7400FA6091 /* PurchasesRestoreTests.swift in Sources */, FD18ED4E2837F89200C5AA4F /* StoreKitWorkaroundsTests.swift in Sources */, @@ -6268,6 +6286,7 @@ 5796A39427D6BD6900653165 /* BackendGetOfferingsTests.swift in Sources */, 5766AA42283C768600FA6091 /* OperatorExtensionsTests.swift in Sources */, 4F54DF3F2A1D8C7500FD72BF /* MockStoreKit2TransactionFetcher.swift in Sources */, + 03F446242D2FE0C50046129A /* ShapeComponentTests.swift in Sources */, 4FD7E8662AABC4470055406F /* PurchasesPaywallEventsTests.swift in Sources */, 351B516A26D44CB300BD2BD7 /* ISOPeriodFormatterTests.swift in Sources */, 57DC9F4A27CD37BA00DA6AF9 /* HTTPStatusCodeTests.swift in Sources */, @@ -6386,6 +6405,7 @@ 351B516026D44BB600BD2BD7 /* MockAttributionDataMigrator.swift in Sources */, 2DDF41E024F6F527005BC22D /* MockInAppPurchaseBuilder.swift in Sources */, 37E352973B0901E3CAA717E1 /* DateFormatter+ExtensionsTests.swift in Sources */, + 03F446262D2FE1510046129A /* MaskShapeComponentTests.swift in Sources */, B3F8418F26F3A93400E560FB /* ErrorCodeTests.swift in Sources */, 5793397228E77A6E00C1232C /* MockPaymentQueue.swift in Sources */, 4FFCED832AA941B200118EF4 /* PaywallEventsBackendTests.swift in Sources */, diff --git a/Sources/Paywalls/Components/Common/PaywallComponentPropertyTypes.swift b/Sources/Paywalls/Components/Common/PaywallComponentPropertyTypes.swift index 9a43ab5f77..a82cd36bd8 100644 --- a/Sources/Paywalls/Components/Common/PaywallComponentPropertyTypes.swift +++ b/Sources/Paywalls/Components/Common/PaywallComponentPropertyTypes.swift @@ -164,7 +164,7 @@ public extension PaywallComponent { switch type { case .rectangle: - let value = try container.decode(CornerRadiuses.self, forKey: .corners) + let value: CornerRadiuses? = try container.decodeIfPresent(CornerRadiuses.self, forKey: .corners) self = .rectangle(value) case .pill: self = .pill @@ -218,7 +218,7 @@ public extension PaywallComponent { switch type { case .rectangle: - let value = try container.decode(CornerRadiuses.self, forKey: .corners) + let value: CornerRadiuses? = try container.decodeIfPresent(CornerRadiuses.self, forKey: .corners) self = .rectangle(value) case .pill: self = .pill diff --git a/Tests/TestingApps/PaywallsTester/PaywallsTester/Config/ConfigItem.swift b/Tests/TestingApps/PaywallsTester/PaywallsTester/Config/ConfigItem.swift index 19d3a9eb45..72d4368e7e 100644 --- a/Tests/TestingApps/PaywallsTester/PaywallsTester/Config/ConfigItem.swift +++ b/Tests/TestingApps/PaywallsTester/PaywallsTester/Config/ConfigItem.swift @@ -14,7 +14,7 @@ protocol AvailableConfigItems { // CI system adds keys here extension AvailableConfigItems { - static var apiKey: String { "" } + static var apiKey: String { "appl_fpIYNnFHeCcvJRZqibQfQOTUusd" } static var proxyURL: String? { nil } } diff --git a/Tests/UnitTests/Paywalls/Components/Properties/MaskShapeComponentTests.swift b/Tests/UnitTests/Paywalls/Components/Properties/MaskShapeComponentTests.swift new file mode 100644 index 0000000000..13f0ed1b1e --- /dev/null +++ b/Tests/UnitTests/Paywalls/Components/Properties/MaskShapeComponentTests.swift @@ -0,0 +1,82 @@ +import Nimble +@testable import RevenueCat +import XCTest + +#if PAYWALL_COMPONENTS + +class MaskShapeComponentTests: TestCase { + + func testRectangleNoCorners() throws { + let json = """ + { + "type": "rectangle", + } + """ + + _ = try JSONDecoder.default.decode( + PaywallComponent.MaskShape.self, + from: json.data(using: .utf8)! + ) + } + + func testRectangleWithCorners() throws { + let json = """ + { + "type": "rectangle", + "corners": { + "top_leading": 5, + "top_trailing": 5, + "bottom_leading": 5, + "bottom_trailing": 5 + } + } + """ + + _ = try JSONDecoder.default.decode( + PaywallComponent.MaskShape.self, + from: json.data(using: .utf8)! + ) + } + + func testPill() throws { + let json = """ + { + "type": "pill", + } + """ + + _ = try JSONDecoder.default.decode( + PaywallComponent.MaskShape.self, + from: json.data(using: .utf8)! + ) + } + + func testConvex() throws { + let json = """ + { + "type": "convex", + } + """ + + _ = try JSONDecoder.default.decode( + PaywallComponent.MaskShape.self, + from: json.data(using: .utf8)! + ) + } + + func testConcave() throws { + let json = """ + { + "type": "concave", + } + """ + + _ = try JSONDecoder.default.decode( + PaywallComponent.MaskShape.self, + from: json.data(using: .utf8)! + ) + } + +} + +#endif diff --git a/Tests/UnitTests/Paywalls/Components/Properties/ShapeComponentTests.swift b/Tests/UnitTests/Paywalls/Components/Properties/ShapeComponentTests.swift new file mode 100644 index 0000000000..0af584b33c --- /dev/null +++ b/Tests/UnitTests/Paywalls/Components/Properties/ShapeComponentTests.swift @@ -0,0 +1,56 @@ +import Nimble +@testable import RevenueCat +import XCTest + +#if PAYWALL_COMPONENTS + +class ShapeComponentTests: TestCase { + + func testRectangleNoCorners() throws { + let json = """ + { + "type": "rectangle", + } + """ + + _ = try JSONDecoder.default.decode( + PaywallComponent.Shape.self, + from: json.data(using: .utf8)! + ) + } + + func testRectangleWithCorners() throws { + let json = """ + { + "type": "rectangle", + "corners": { + "top_leading": 5, + "top_trailing": 5, + "bottom_leading": 5, + "bottom_trailing": 5 + } + } + """ + + _ = try JSONDecoder.default.decode( + PaywallComponent.Shape.self, + from: json.data(using: .utf8)! + ) + } + + func testPill() throws { + let json = """ + { + "type": "pill", + } + """ + + _ = try JSONDecoder.default.decode( + PaywallComponent.Shape.self, + from: json.data(using: .utf8)! + ) + } + +} + +#endif diff --git a/Tests/UnitTests/Paywalls/Components/StackComponentTests.swift b/Tests/UnitTests/Paywalls/Components/StackComponentTests.swift new file mode 100644 index 0000000000..44dc2f90ba --- /dev/null +++ b/Tests/UnitTests/Paywalls/Components/StackComponentTests.swift @@ -0,0 +1,46 @@ +import Nimble +@testable import RevenueCat +import XCTest + +#if PAYWALL_COMPONENTS + +class StackComponentTests: TestCase { + + func testUnknownTypeWithSuccessfulFallbackDecodingAndEncodesAndRedecodes() throws { + let jsonStack = """ + { + "type": "stack", + "dimension": { + "type": "vertical", + "alignment": "center", + "distribution": "start" + }, + "size": { + "width": { "type": "fill" }, + "height": { "type": "fill" } + }, + "padding": { + "top": 0, + "bottom": 0, + "leading": 0, + "trailing": 0 + }, + "margin": { + "top": 0, + "bottom": 0, + "leading": 0, + "trailing": 0 + }, + "components": [] + } + """ + + _ = try JSONDecoder.default.decode( + PaywallComponent.StackComponent.self, + from: jsonStack.data(using: .utf8)! + ) + } + +} + +#endif