diff --git a/platforms/swift/Sources/ShopifyCheckoutKit/CheckoutViewController.swift b/platforms/swift/Sources/ShopifyCheckoutKit/CheckoutViewController.swift index 4957b013..e1ccb4c6 100644 --- a/platforms/swift/Sources/ShopifyCheckoutKit/CheckoutViewController.swift +++ b/platforms/swift/Sources/ShopifyCheckoutKit/CheckoutViewController.swift @@ -119,31 +119,31 @@ public protocol CheckoutConfigurable { extension CheckoutConfigurable { @MainActor @discardableResult public func backgroundColor(_ color: UIColor) -> Self { - ShopifyCheckoutKit.configuration.backgroundColor = color + ShopifyCheckoutKit.configure { $0.backgroundColor = color } return self } @MainActor @discardableResult public func colorScheme(_ colorScheme: ShopifyCheckoutKit.Configuration.ColorScheme) -> Self { - ShopifyCheckoutKit.configuration.colorScheme = colorScheme + ShopifyCheckoutKit.configure { $0.colorScheme = colorScheme } return self } @MainActor @discardableResult public func tintColor(_ color: UIColor) -> Self { - ShopifyCheckoutKit.configuration.tintColor = color + ShopifyCheckoutKit.configure { $0.tintColor = color } return self } @MainActor @discardableResult public func title(_ title: String) -> Self { - ShopifyCheckoutKit.configuration.title = title + ShopifyCheckoutKit.configure { $0.title = title } return self } @MainActor @discardableResult public func closeButtonTintColor(_ color: UIColor?) -> Self { - ShopifyCheckoutKit.configuration.closeButtonTintColor = color + ShopifyCheckoutKit.configure { $0.closeButtonTintColor = color } return self } } diff --git a/platforms/swift/Sources/ShopifyCheckoutKit/Configuration.swift b/platforms/swift/Sources/ShopifyCheckoutKit/Configuration.swift index f855a613..c8d7e8ae 100644 --- a/platforms/swift/Sources/ShopifyCheckoutKit/Configuration.swift +++ b/platforms/swift/Sources/ShopifyCheckoutKit/Configuration.swift @@ -79,10 +79,6 @@ extension Configuration { extension Configuration { public struct Preloading { - public var enabled: Bool = true { - didSet { - CheckoutWebView.preloadingActivatedByClient = false - } - } + public var enabled: Bool = true } } diff --git a/platforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swift b/platforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swift index 3645a7a9..9f9981be 100644 --- a/platforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swift +++ b/platforms/swift/Sources/ShopifyCheckoutKit/ShopifyCheckoutKit.swift @@ -30,22 +30,42 @@ import UIKit public let version = "3.8.0" @MainActor var invalidateOnConfigurationChange = true +@MainActor private var currentConfiguration = Configuration() /// The configuration options for the `ShopifyCheckoutKit` library. @MainActor -public var configuration = Configuration() { - didSet { - if invalidateOnConfigurationChange { - CheckoutWebView.invalidate() - } - OSLogger.shared.logLevel = configuration.logLevel +public var configuration: Configuration { + get { + currentConfiguration + } + set { + currentConfiguration = newValue + applyConfigurationChange() } } /// A convienence function for configuring the `ShopifyCheckoutKit` library. @MainActor public func configure(_ block: (inout Configuration) -> Void) { - block(&configuration) + block(¤tConfiguration) + applyConfigurationChange() +} + +@MainActor +package func setConfiguration(_ configuration: Configuration) { + currentConfiguration = configuration + applyConfigurationChange() +} + +@MainActor +private func applyConfigurationChange() { + if invalidateOnConfigurationChange { + CheckoutWebView.invalidate() + } + if !currentConfiguration.preloading.enabled { + CheckoutWebView.preloadingActivatedByClient = false + } + OSLogger.shared.logLevel = currentConfiguration.logLevel } /// Preloads the checkout for faster presentation. diff --git a/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutBridgeTests.swift b/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutBridgeTests.swift index e6b4eef2..4fea9013 100644 --- a/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutBridgeTests.swift +++ b/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutBridgeTests.swift @@ -59,7 +59,7 @@ class CheckoutBridgeTests: XCTestCase { func testReturnsUserAgentWithEntryPointAndPlatform() { let version = ShopifyCheckoutKit.version let schemaVersion = MetaData.schemaVersion - ShopifyCheckoutKit.configuration.platform = Platform.reactNative + ShopifyCheckoutKit.configure { $0.platform = Platform.reactNative } let applicationNameWithEntryPoint = CheckoutBridge.applicationName(entryPoint: .acceleratedCheckouts) let recoveryAgentWithEntryPoint = CheckoutBridge.recoveryAgent(entryPoint: .acceleratedCheckouts) @@ -67,7 +67,7 @@ class CheckoutBridgeTests: XCTestCase { XCTAssertEqual(applicationNameWithEntryPoint, "ShopifyCheckoutKit/\(version) (\(schemaVersion);automatic;standard) ReactNative AcceleratedCheckouts") XCTAssertEqual(recoveryAgentWithEntryPoint, "ShopifyCheckoutKit/\(version) (noconnect;automatic;standard_recovery) ReactNative AcceleratedCheckouts") - ShopifyCheckoutKit.configuration.platform = nil + ShopifyCheckoutKit.configure { $0.platform = nil } } func testInstrumentationPayloadToBridgeEvent() { diff --git a/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutViewControllerTests.swift b/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutViewControllerTests.swift index e005b39a..9dad35c9 100644 --- a/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutViewControllerTests.swift +++ b/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutViewControllerTests.swift @@ -177,7 +177,7 @@ class CheckoutViewDelegateTests: XCTestCase { } func testCloseButtonUsesSystemDefaultWhenTintColorIsNil() { - ShopifyCheckoutKit.configuration.closeButtonTintColor = nil + ShopifyCheckoutKit.configure { $0.closeButtonTintColor = nil } let controller = MockCheckoutWebViewController(checkoutURL: checkoutURL) let closeButton = controller.navigationItem.rightBarButtonItem @@ -188,7 +188,7 @@ class CheckoutViewDelegateTests: XCTestCase { func testCloseButtonUsesCustomImageAndTintWhenColorIsSet() { let customColor = UIColor.red - ShopifyCheckoutKit.configuration.closeButtonTintColor = customColor + ShopifyCheckoutKit.configure { $0.closeButtonTintColor = customColor } let controller = MockCheckoutWebViewController(checkoutURL: checkoutURL) let closeButton = controller.navigationItem.rightBarButtonItem @@ -199,7 +199,7 @@ class CheckoutViewDelegateTests: XCTestCase { } func testCloseButtonImageIsXMarkCircleFill() { - ShopifyCheckoutKit.configuration.closeButtonTintColor = .blue + ShopifyCheckoutKit.configure { $0.closeButtonTintColor = .blue } let controller = MockCheckoutWebViewController(checkoutURL: checkoutURL) let closeButton = controller.navigationItem.rightBarButtonItem diff --git a/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutWebViewTests.swift b/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutWebViewTests.swift index 15be4376..5c3ef62d 100644 --- a/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutWebViewTests.swift +++ b/platforms/swift/Tests/ShopifyCheckoutKitTests/CheckoutWebViewTests.swift @@ -33,7 +33,7 @@ class CheckoutWebViewTests: XCTestCase { private var url = URL(string: "http://shopify1.shopify.com/checkouts/cn/123")! override func setUp() { - ShopifyCheckoutKit.configuration.preloading.enabled = true + ShopifyCheckoutKit.configure { $0.preloading.enabled = true } view = CheckoutWebView.for(checkout: url) mockDelegate = MockCheckoutWebViewDelegate() view.viewDelegate = mockDelegate @@ -56,8 +56,10 @@ class CheckoutWebViewTests: XCTestCase { func testUsesRecoveryAgent() { let backgroundColor: UIColor = .systemRed - ShopifyCheckoutKit.configuration.backgroundColor = backgroundColor - ShopifyCheckoutKit.configuration.colorScheme = .automatic + ShopifyCheckoutKit.configure { + $0.backgroundColor = backgroundColor + $0.colorScheme = .automatic + } recovery = createRecoveryAgent() XCTAssertTrue(recovery.isRecovery) diff --git a/platforms/swift/Tests/ShopifyCheckoutKitTests/ConfigurationTests.swift b/platforms/swift/Tests/ShopifyCheckoutKitTests/ConfigurationTests.swift index ee4d5144..4e911619 100644 --- a/platforms/swift/Tests/ShopifyCheckoutKitTests/ConfigurationTests.swift +++ b/platforms/swift/Tests/ShopifyCheckoutKitTests/ConfigurationTests.swift @@ -28,8 +28,18 @@ import XCTest class ConfigurationTests: XCTestCase { override func setUp() { super.setUp() - // Reset configuration to defaults - ShopifyCheckoutKit.configuration = Configuration() + resetConfigurationState() + } + + override func tearDown() { + resetConfigurationState() + super.tearDown() + } + + private func resetConfigurationState() { + ShopifyCheckoutKit.invalidateOnConfigurationChange = true + CheckoutWebView.invalidate() + ShopifyCheckoutKit.setConfiguration(Configuration()) } func testCloseButtonTintColorDefaultsToNil() { @@ -50,4 +60,47 @@ class ConfigurationTests: XCTestCase { ShopifyCheckoutKit.configuration.closeButtonTintColor = nil XCTAssertNil(ShopifyCheckoutKit.configuration.closeButtonTintColor) } + + func testColorSchemeCanBeSetDirectly() { + ShopifyCheckoutKit.configuration.colorScheme = .light + + XCTAssertEqual(ShopifyCheckoutKit.configuration.colorScheme, .light) + } + + func testConfigureCanBatchConfigurationChanges() { + ShopifyCheckoutKit.configure { + $0.colorScheme = .dark + $0.closeButtonTintColor = .blue + } + + XCTAssertEqual(ShopifyCheckoutKit.configuration.colorScheme, .dark) + XCTAssertEqual(ShopifyCheckoutKit.configuration.closeButtonTintColor, .blue) + } + + func testDirectConfigurationMutationUpdatesLogger() { + ShopifyCheckoutKit.configuration.logLevel = .all + + XCTAssertEqual(ShopifyCheckoutKit.configuration.logLevel, .all) + XCTAssertEqual(OSLogger.shared.logLevel, .all) + } + + func testDirectConfigurationMutationInvalidatesCheckoutCache() throws { + ShopifyCheckoutKit.invalidateOnConfigurationChange = true + + let url = try XCTUnwrap(URL(string: "http://shopify1.shopify.com/checkouts/cn/123")) + _ = CheckoutWebView.for(checkout: url) + XCTAssertTrue(CheckoutWebView.hasCacheEntry()) + + ShopifyCheckoutKit.configuration.title = "Updated title" + + XCTAssertFalse(CheckoutWebView.hasCacheEntry()) + } + + func testDirectConfigurationMutationDisablesPreloadingActivatedByClient() { + CheckoutWebView.preloadingActivatedByClient = true + + ShopifyCheckoutKit.configuration.preloading.enabled = false + + XCTAssertFalse(CheckoutWebView.preloadingActivatedByClient) + } } diff --git a/platforms/swift/Tests/ShopifyCheckoutKitTests/LoggerTests.swift b/platforms/swift/Tests/ShopifyCheckoutKitTests/LoggerTests.swift index 88b74d17..f902ff3e 100644 --- a/platforms/swift/Tests/ShopifyCheckoutKitTests/LoggerTests.swift +++ b/platforms/swift/Tests/ShopifyCheckoutKitTests/LoggerTests.swift @@ -52,7 +52,7 @@ final class OSLoggerTests: XCTestCase { } override func tearDown() { - ShopifyCheckoutKit.configuration = originalConfiguration + ShopifyCheckoutKit.setConfiguration(originalConfiguration) super.tearDown() } @@ -138,7 +138,7 @@ final class OSLoggerTests: XCTestCase { } func test_sharedLogger_withConfigurationLogLevel_shouldMaintainBackwardsCompatibility() { - ShopifyCheckoutKit.configuration.logLevel = .all + ShopifyCheckoutKit.configure { $0.logLevel = .all } OSLogger.shared.info("test message") } diff --git a/platforms/swift/Tests/ShopifyCheckoutKitTests/ShopifyCheckoutKitTests.swift b/platforms/swift/Tests/ShopifyCheckoutKitTests/ShopifyCheckoutKitTests.swift index 004261e7..256ce287 100644 --- a/platforms/swift/Tests/ShopifyCheckoutKitTests/ShopifyCheckoutKitTests.swift +++ b/platforms/swift/Tests/ShopifyCheckoutKitTests/ShopifyCheckoutKitTests.swift @@ -54,7 +54,7 @@ class ShopifyCheckoutKitTests: XCTestCase { let originalLogger = OSLogger.shared let originalLogLevel = OSLogger.shared.logLevel - ShopifyCheckoutKit.configuration.logLevel = originalLogLevel + ShopifyCheckoutKit.configure { $0.logLevel = originalLogLevel } let newLogger = OSLogger.shared XCTAssertTrue( @@ -64,28 +64,28 @@ class ShopifyCheckoutKitTests: XCTestCase { } func test_logger_withDifferentLogLevels_shouldHaveCorrectLogLevel() { - ShopifyCheckoutKit.configuration.logLevel = .all + ShopifyCheckoutKit.configure { $0.logLevel = .all } XCTAssertEqual( OSLogger.shared.logLevel, .all, "Logger should have .all log level" ) - ShopifyCheckoutKit.configuration.logLevel = .debug + ShopifyCheckoutKit.configure { $0.logLevel = .debug } XCTAssertEqual( OSLogger.shared.logLevel, .debug, "Logger should have .debug log level" ) - ShopifyCheckoutKit.configuration.logLevel = .error + ShopifyCheckoutKit.configure { $0.logLevel = .error } XCTAssertEqual( OSLogger.shared.logLevel, .error, "Logger should have .error log level" ) - ShopifyCheckoutKit.configuration.logLevel = .none + ShopifyCheckoutKit.configure { $0.logLevel = .none } XCTAssertEqual( OSLogger.shared.logLevel, .none,