From a5b8de1b6f883b585b543929b8ddda7235519749 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Mon, 28 Jul 2025 13:37:34 +0700 Subject: [PATCH 01/13] Fix initialization of authenticator in Jetpack setup flow --- .../ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift b/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift index 9884af711c7..91be5d5b770 100644 --- a/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift +++ b/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift @@ -60,7 +60,7 @@ final class JetpackSetupCoordinator { /// the authenticator needs to be initialized with configs /// to be used for requesting authentication link and handle login later. - WordPressAuthenticator.initializeWithCustomConfigs(dotcomAuthScheme: dotcomAuthScheme) + ServiceLocator.authenticationManager.initialize() } func showBenefitModal() { From 73aa96fc1f6a299aaeb39e3f59f465c8668d4724 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Mon, 28 Jul 2025 17:32:18 +0700 Subject: [PATCH 02/13] Hide Jetpack benefit banner if current site is simple site (expired paid plans) --- .../Classes/ViewRelated/Dashboard/DashboardView.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/DashboardView.swift b/WooCommerce/Classes/ViewRelated/Dashboard/DashboardView.swift index 063b0cbede5..b19f109f0bb 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/DashboardView.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/DashboardView.swift @@ -70,8 +70,11 @@ struct DashboardView: View { private let connectivityObserver = ServiceLocator.connectivityObserver private var shouldShowJetpackBenefitsBanner: Bool { - let isJetpackCPSite = currentSite?.isJetpackCPConnected == true - let isNonJetpackSite = currentSite?.isNonJetpackSite == true + guard let currentSite, currentSite.isSimpleSite == false else { + return false + } + let isJetpackCPSite = currentSite.isJetpackCPConnected + let isNonJetpackSite = currentSite.isNonJetpackSite return (isJetpackCPSite || isNonJetpackSite) && viewModel.isSiteEligibleToInstallJetpack && viewModel.jetpackBannerVisibleFromAppSettings && From c05fed8d9682fb8ef307200a463b32545043f626 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Tue, 29 Jul 2025 10:11:14 +0700 Subject: [PATCH 03/13] Revert "Hide Jetpack benefit banner if current site is simple site (expired paid plans)" This reverts commit 73aa96fc1f6a299aaeb39e3f59f465c8668d4724. --- .../Classes/ViewRelated/Dashboard/DashboardView.swift | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/DashboardView.swift b/WooCommerce/Classes/ViewRelated/Dashboard/DashboardView.swift index b19f109f0bb..063b0cbede5 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/DashboardView.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/DashboardView.swift @@ -70,11 +70,8 @@ struct DashboardView: View { private let connectivityObserver = ServiceLocator.connectivityObserver private var shouldShowJetpackBenefitsBanner: Bool { - guard let currentSite, currentSite.isSimpleSite == false else { - return false - } - let isJetpackCPSite = currentSite.isJetpackCPConnected - let isNonJetpackSite = currentSite.isNonJetpackSite + let isJetpackCPSite = currentSite?.isJetpackCPConnected == true + let isNonJetpackSite = currentSite?.isNonJetpackSite == true return (isJetpackCPSite || isNonJetpackSite) && viewModel.isSiteEligibleToInstallJetpack && viewModel.jetpackBannerVisibleFromAppSettings && From 6ba0f92c7fa6de943035c6da5354b22ed91122a4 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Tue, 29 Jul 2025 10:45:11 +0700 Subject: [PATCH 04/13] Prevent reinitializing authenticator --- .../Epilogue/StorePickerViewController.swift | 1 - WooCommerce/Classes/ViewRelated/AppCoordinator.swift | 11 ++--------- .../JetpackSetup/JetpackSetupCoordinator.swift | 4 ---- .../Authenticator/WordPressAuthenticator.swift | 4 ++++ 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/WooCommerce/Classes/Authentication/Epilogue/StorePickerViewController.swift b/WooCommerce/Classes/Authentication/Epilogue/StorePickerViewController.swift index 8ae0f6354e3..05e0d565d7d 100644 --- a/WooCommerce/Classes/Authentication/Epilogue/StorePickerViewController.swift +++ b/WooCommerce/Classes/Authentication/Epilogue/StorePickerViewController.swift @@ -369,7 +369,6 @@ private extension StorePickerViewController { } func presentSiteDiscovery() { - ServiceLocator.authenticationManager.initialize() guard let viewController = WordPressAuthenticator.siteDiscoveryUI() else { return } diff --git a/WooCommerce/Classes/ViewRelated/AppCoordinator.swift b/WooCommerce/Classes/ViewRelated/AppCoordinator.swift index 55ce1a42176..61f281c4084 100644 --- a/WooCommerce/Classes/ViewRelated/AppCoordinator.swift +++ b/WooCommerce/Classes/ViewRelated/AppCoordinator.swift @@ -89,7 +89,6 @@ final class AppCoordinator { self.displayLoggedInStateWithoutDefaultStore() case (true, false): self.validateRoleEligibility { - self.configureAuthenticator() self.displayLoggedInUI() self.synchronizeAndShowWhatsNew() } @@ -200,19 +199,13 @@ private extension AppCoordinator { presentLoginOnboarding { [weak self] in guard let self = self else { return } // Only displays the authenticator when dismissing onboarding to allow time for A/B test setup. - self.configureAndDisplayAuthenticator() + self.displayAuthenticator() } } else { - configureAndDisplayAuthenticator() + displayAuthenticator() } } - /// Configures the WPAuthenticator and sets the authenticator UI as the window's root view. - func configureAndDisplayAuthenticator() { - configureAuthenticator() - displayAuthenticator() - } - /// Configures the WPAuthenticator for usage in both logged-in and logged-out states. func configureAuthenticator() { authenticationManager.initialize() diff --git a/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift b/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift index 91be5d5b770..a69808d1349 100644 --- a/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift +++ b/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift @@ -57,10 +57,6 @@ final class JetpackSetupCoordinator { self.stores = stores self.analytics = analytics self.featureFlagService = featureFlagService - - /// the authenticator needs to be initialized with configs - /// to be used for requesting authentication link and handle login later. - ServiceLocator.authenticationManager.initialize() } func showBenefitModal() { diff --git a/WooCommerce/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift b/WooCommerce/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift index 035112d9158..b2295887e47 100644 --- a/WooCommerce/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift +++ b/WooCommerce/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift @@ -84,6 +84,10 @@ import WordPressUI unifiedStyle: WordPressAuthenticatorUnifiedStyle?, displayImages: WordPressAuthenticatorDisplayImages = .defaultImages, displayStrings: WordPressAuthenticatorDisplayStrings = .defaultStrings) { + guard privateInstance == nil else { + assertionFailure("Attempting to initialize WordPressAuthenticator more than once - this would cause the delegate to be reset. Aborting... 🙅⛔️") + return + } privateInstance = WordPressAuthenticator(configuration: configuration, style: style, unifiedStyle: unifiedStyle, From 3c9be270e4443b7551a4bdc730fe09be4e911d98 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Tue, 29 Jul 2025 11:39:52 +0700 Subject: [PATCH 05/13] Avoid triggering assertionFailure for tests --- .../Authenticator/WordPressAuthenticator.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/WooCommerce/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift b/WooCommerce/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift index b2295887e47..f8b46949157 100644 --- a/WooCommerce/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift +++ b/WooCommerce/WordPressAuthenticator/Authenticator/WordPressAuthenticator.swift @@ -85,7 +85,9 @@ import WordPressUI displayImages: WordPressAuthenticatorDisplayImages = .defaultImages, displayStrings: WordPressAuthenticatorDisplayStrings = .defaultStrings) { guard privateInstance == nil else { - assertionFailure("Attempting to initialize WordPressAuthenticator more than once - this would cause the delegate to be reset. Aborting... 🙅⛔️") + if isRunningTests() == false { // avoid crashing in tests + assertionFailure("Attempting to initialize WordPressAuthenticator more than once - this would cause the delegate to be reset. Aborting... 🙅⛔️") + } return } privateInstance = WordPressAuthenticator(configuration: configuration, @@ -491,3 +493,9 @@ public extension WordPressAuthenticator { appleIDCredentialObserver = nil } } + +private extension WordPressAuthenticator { + static func isRunningTests() -> Bool { + return NSClassFromString("XCTestCase") != nil + } +} From a60575360f7a4df38cb876a5bc50d76d08d1f18e Mon Sep 17 00:00:00 2001 From: Huong Do Date: Tue, 29 Jul 2025 14:06:23 +0700 Subject: [PATCH 06/13] Improve error message when login is forced to crash --- .../WordPressAuthenticator/Signin/LoginViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/WooCommerce/WordPressAuthenticator/Signin/LoginViewController.swift b/WooCommerce/WordPressAuthenticator/Signin/LoginViewController.swift index 5def77a82a3..760f4cc9593 100644 --- a/WooCommerce/WordPressAuthenticator/Signin/LoginViewController.swift +++ b/WooCommerce/WordPressAuthenticator/Signin/LoginViewController.swift @@ -32,7 +32,7 @@ open class LoginViewController: NUXViewController, LoginFacadeDelegate { var authenticationDelegate: WordPressAuthenticatorDelegate { guard let delegate = WordPressAuthenticator.shared.delegate else { - fatalError() + fatalError("No delegate found for WordPressAuthenticator") } return delegate @@ -140,7 +140,7 @@ open class LoginViewController: NUXViewController, LoginFacadeDelegate { func showLoginEpilogue(for credentials: AuthenticatorCredentials) { guard let navigationController = navigationController else { - fatalError() + fatalError("No navigation controller found to show login epilogue") } authenticationDelegate.presentLoginEpilogue(in: navigationController, From e2c525afcebda867747012c2580a7144ec32f396 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Tue, 29 Jul 2025 16:08:57 +0700 Subject: [PATCH 07/13] Update release notes --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 236ba20fac0..9b5d422a8e0 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -3,6 +3,7 @@ 23.0 ----- +- [*] Fix initialization of authenticator to avoid crashes during login [https://github.com/woocommerce/woocommerce-ios/pull/15953] 22.9 From 40282f68879d3506dab5defbdd9a03a47dd8a83e Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 30 Jul 2025 09:21:36 +0700 Subject: [PATCH 08/13] Remove redundant dotcomAuthScheme argument from JetpackSetupCoordinator initializer --- .../ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift b/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift index a69808d1349..ec22cbb2e1f 100644 --- a/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift +++ b/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift @@ -19,7 +19,6 @@ final class JetpackSetupCoordinator { private let stores: StoresManager private let analytics: Analytics private let featureFlagService: FeatureFlagService - private let dotcomAuthScheme: String private var loginNavigationController: LoginNavigationController? private var setupStepsNavigationController: UINavigationController? @@ -43,14 +42,12 @@ final class JetpackSetupCoordinator { } init(site: Site, - dotcomAuthScheme: String = ApiCredentials.dotcomAuthScheme, rootViewController: UIViewController, accountService: WordPressComAccountServiceProtocol = WordPressComAccountService(), stores: StoresManager = ServiceLocator.stores, analytics: Analytics = ServiceLocator.analytics, featureFlagService: FeatureFlagService = ServiceLocator.featureFlagService) { self.site = site - self.dotcomAuthScheme = dotcomAuthScheme self.requiresConnectionOnly = false // to be updated later after fetching Jetpack status self.rootViewController = rootViewController self.accountService = accountService @@ -69,7 +66,7 @@ final class JetpackSetupCoordinator { } func handleAuthenticationUrl(_ url: URL) -> Bool { - let expectedPrefix = dotcomAuthScheme + "://" + Constants.magicLinkUrlHostname + let expectedPrefix = ApiCredentials.dotcomAuthScheme + "://" + Constants.magicLinkUrlHostname guard url.absoluteString.hasPrefix(expectedPrefix) else { return false } From b4f38e6b36b40e94f839b61d5034f98a5024a74b Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 30 Jul 2025 09:29:04 +0700 Subject: [PATCH 09/13] Remove redundant configureAuthenticator --- WooCommerce/Classes/ViewRelated/AppCoordinator.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/WooCommerce/Classes/ViewRelated/AppCoordinator.swift b/WooCommerce/Classes/ViewRelated/AppCoordinator.swift index 61f281c4084..b400f9327c4 100644 --- a/WooCommerce/Classes/ViewRelated/AppCoordinator.swift +++ b/WooCommerce/Classes/ViewRelated/AppCoordinator.swift @@ -289,7 +289,6 @@ private extension AppCoordinator { guard stores.isAuthenticatedWithoutWPCom == false else { return displayAuthenticatorWithOnboardingIfNeeded() } - configureAuthenticator() let matcher = ULAccountMatcher(storageManager: storageManager) matcher.refreshStoredSites() From 061fe4f1e0b52c57dd1bf6db9cf4a1c870f47bcb Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 30 Jul 2025 14:06:16 +0700 Subject: [PATCH 10/13] Fix test build failures --- .../JetpackSetupCoordinatorTests.swift | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift index e67b99102ba..dbe5dcbfa1a 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift @@ -40,8 +40,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { func test_handleAuthenticationUrl_returns_false_for_unsupported_url_scheme() throws { // Given let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) - let expectedScheme = "scheme" - let coordinator = JetpackSetupCoordinator(site: testSite, dotcomAuthScheme: expectedScheme, rootViewController: navigationController) + let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController) let url = try XCTUnwrap(URL(string: "example://handle-authentication")) // When @@ -54,9 +53,8 @@ final class JetpackSetupCoordinatorTests: XCTestCase { func test_handleAuthenticationUrl_returns_false_for_missing_queries() throws { // Given let testSite = Site.fake().copy(siteID: -1) - let expectedScheme = "scheme" - let coordinator = JetpackSetupCoordinator(site: testSite, dotcomAuthScheme: expectedScheme, rootViewController: navigationController) - let url = try XCTUnwrap(URL(string: "scheme://magic-login")) + let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController) + let url = try XCTUnwrap(URL(string: "woocommerce://magic-login")) // When let result = coordinator.handleAuthenticationUrl(url) @@ -68,9 +66,8 @@ final class JetpackSetupCoordinatorTests: XCTestCase { func test_handleAuthenticationUrl_returns_false_for_incorrect_host_name() throws { // Given let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) - let expectedScheme = "scheme" - let coordinator = JetpackSetupCoordinator(site: testSite, dotcomAuthScheme: expectedScheme, rootViewController: navigationController) - let url = try XCTUnwrap(URL(string: "scheme://handle-authentication?token=test")) + let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController) + let url = try XCTUnwrap(URL(string: "woocommerce://handle-authentication?token=test")) // When let result = coordinator.handleAuthenticationUrl(url) @@ -82,9 +79,8 @@ final class JetpackSetupCoordinatorTests: XCTestCase { func test_handleAuthenticationUrl_returns_true_for_correct_url_and_sufficient_queries() throws { // Given let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) - let expectedScheme = "scheme" - let coordinator = JetpackSetupCoordinator(site: testSite, dotcomAuthScheme: expectedScheme, rootViewController: navigationController) - let url = try XCTUnwrap(URL(string: "scheme://magic-login?token=test")) + let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController) + let url = try XCTUnwrap(URL(string: "woocommerce://magic-login?token=test")) // When let result = coordinator.handleAuthenticationUrl(url) @@ -97,9 +93,8 @@ final class JetpackSetupCoordinatorTests: XCTestCase { // Given let stores = MockStoresManager(sessionManager: .makeForTesting(authenticated: true, isWPCom: false, defaultRoles: [.shopManager])) let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) - let expectedScheme = "scheme" - let coordinator = JetpackSetupCoordinator(site: testSite, dotcomAuthScheme: expectedScheme, rootViewController: navigationController, stores: stores) - let url = try XCTUnwrap(URL(string: "scheme://magic-login?token=test")) + let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController, stores: stores) + let url = try XCTUnwrap(URL(string: "woocommerce://magic-login?token=test")) let expectedAccount = Account(userID: 123, displayName: "Test", email: "test@example.com", username: "test", gravatarUrl: nil) stores.whenReceivingAction(ofType: JetpackConnectionAction.self) { action in @@ -127,9 +122,8 @@ final class JetpackSetupCoordinatorTests: XCTestCase { // Given let stores = MockStoresManager(sessionManager: .makeForTesting(authenticated: true, isWPCom: false)) let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) - let expectedScheme = "scheme" - let coordinator = JetpackSetupCoordinator(site: testSite, dotcomAuthScheme: expectedScheme, rootViewController: navigationController, stores: stores) - let url = try XCTUnwrap(URL(string: "scheme://magic-login?token=test")) + let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController, stores: stores) + let url = try XCTUnwrap(URL(string: "woocommerce://magic-login?token=test")) let expectedAccount = Account(userID: 123, displayName: "Test", email: "test@example.com", username: "test", gravatarUrl: nil) stores.whenReceivingAction(ofType: JetpackConnectionAction.self) { action in @@ -158,9 +152,8 @@ final class JetpackSetupCoordinatorTests: XCTestCase { let stores = MockStoresManager(sessionManager: .makeForTesting(authenticated: true, isWPCom: false)) let siteURL = "https://example.com" let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID, url: siteURL) - let expectedScheme = "scheme" - let coordinator = JetpackSetupCoordinator(site: testSite, dotcomAuthScheme: expectedScheme, rootViewController: navigationController, stores: stores) - let url = try XCTUnwrap(URL(string: "scheme://magic-login?token=test")) + let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController, stores: stores) + let url = try XCTUnwrap(URL(string: "woocommerce://magic-login?token=test")) let expectedAccount = Account(userID: 123, displayName: "Test", email: "test@example.com", username: "test", gravatarUrl: nil) stores.whenReceivingAction(ofType: JetpackConnectionAction.self) { action in From 10afd4c48f891a5dc8197f44a7e9d921c54351c7 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 30 Jul 2025 15:09:40 +0700 Subject: [PATCH 11/13] Fix test failures --- .../JetpackSetup/JetpackSetupCoordinatorTests.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift index dbe5dcbfa1a..25eafac8b77 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift @@ -14,6 +14,9 @@ final class JetpackSetupCoordinatorTests: XCTestCase { window.rootViewController = UIViewController() window.makeKeyAndVisible() window.rootViewController = navigationController + + AuthenticationManager().initialize() + super.setUp() } From e3f7b31819a38f7c9d933b0f932a79e7bea92899 Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 30 Jul 2025 17:43:39 +0700 Subject: [PATCH 12/13] Use constants instead of hardcoded value in tests --- .../JetpackSetupCoordinatorTests.swift | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift index 25eafac8b77..065f6d73028 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift @@ -57,7 +57,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { // Given let testSite = Site.fake().copy(siteID: -1) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController) - let url = try XCTUnwrap(URL(string: "woocommerce://magic-login")) + let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://magic-login")) // When let result = coordinator.handleAuthenticationUrl(url) @@ -70,7 +70,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { // Given let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController) - let url = try XCTUnwrap(URL(string: "woocommerce://handle-authentication?token=test")) + let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://handle-authentication?token=test")) // When let result = coordinator.handleAuthenticationUrl(url) @@ -83,7 +83,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { // Given let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController) - let url = try XCTUnwrap(URL(string: "woocommerce://magic-login?token=test")) + let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://magic-login?token=test")) // When let result = coordinator.handleAuthenticationUrl(url) @@ -97,7 +97,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { let stores = MockStoresManager(sessionManager: .makeForTesting(authenticated: true, isWPCom: false, defaultRoles: [.shopManager])) let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController, stores: stores) - let url = try XCTUnwrap(URL(string: "woocommerce://magic-login?token=test")) + let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://magic-login?token=test")) let expectedAccount = Account(userID: 123, displayName: "Test", email: "test@example.com", username: "test", gravatarUrl: nil) stores.whenReceivingAction(ofType: JetpackConnectionAction.self) { action in @@ -113,9 +113,10 @@ final class JetpackSetupCoordinatorTests: XCTestCase { stores.mockJetpackCheck() // When - _ = coordinator.handleAuthenticationUrl(url) + let result = coordinator.handleAuthenticationUrl(url) // Then + XCTAssertTrue(result) waitUntil { (self.navigationController.presentedViewController as? UINavigationController)?.topViewController is AdminRoleRequiredHostingController } @@ -126,7 +127,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { let stores = MockStoresManager(sessionManager: .makeForTesting(authenticated: true, isWPCom: false)) let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController, stores: stores) - let url = try XCTUnwrap(URL(string: "woocommerce://magic-login?token=test")) + let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://magic-login?token=test")) let expectedAccount = Account(userID: 123, displayName: "Test", email: "test@example.com", username: "test", gravatarUrl: nil) stores.whenReceivingAction(ofType: JetpackConnectionAction.self) { action in @@ -142,9 +143,10 @@ final class JetpackSetupCoordinatorTests: XCTestCase { stores.mockJetpackCheck() // When - _ = coordinator.handleAuthenticationUrl(url) + let result = coordinator.handleAuthenticationUrl(url) // Then + XCTAssertTrue(result) waitUntil { (self.navigationController.presentedViewController as? UINavigationController)?.topViewController is JetpackSetupHostingController } @@ -156,7 +158,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { let siteURL = "https://example.com" let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID, url: siteURL) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController, stores: stores) - let url = try XCTUnwrap(URL(string: "woocommerce://magic-login?token=test")) + let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://magic-login?token=test")) let expectedAccount = Account(userID: 123, displayName: "Test", email: "test@example.com", username: "test", gravatarUrl: nil) stores.whenReceivingAction(ofType: JetpackConnectionAction.self) { action in @@ -196,9 +198,10 @@ final class JetpackSetupCoordinatorTests: XCTestCase { stores.mockJetpackCheck() // When - _ = coordinator.handleAuthenticationUrl(url) + let result = coordinator.handleAuthenticationUrl(url) // Then + XCTAssertTrue(result) waitUntil { stores.sessionManager.defaultSite == expectedSite } From df0a0dfa3bdc213c52f531d1c6d0b62c96263c7e Mon Sep 17 00:00:00 2001 From: Huong Do Date: Wed, 30 Jul 2025 18:59:55 +0700 Subject: [PATCH 13/13] Inject scheme to handleAuthenticationUrl for testing --- .../JetpackSetupCoordinator.swift | 4 +-- .../JetpackSetupCoordinatorTests.swift | 28 ++++++++++--------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift b/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift index ec22cbb2e1f..8837f3a4e8b 100644 --- a/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift +++ b/WooCommerce/Classes/ViewRelated/JetpackSetup/JetpackSetupCoordinator.swift @@ -65,8 +65,8 @@ final class JetpackSetupCoordinator { rootViewController.present(benefitsController, animated: true, completion: nil) } - func handleAuthenticationUrl(_ url: URL) -> Bool { - let expectedPrefix = ApiCredentials.dotcomAuthScheme + "://" + Constants.magicLinkUrlHostname + func handleAuthenticationUrl(_ url: URL, dotcomAuthScheme: String = ApiCredentials.dotcomAuthScheme) -> Bool { + let expectedPrefix = dotcomAuthScheme + "://" + Constants.magicLinkUrlHostname guard url.absoluteString.hasPrefix(expectedPrefix) else { return false } diff --git a/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift index 065f6d73028..723459c1ca8 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/JetpackSetup/JetpackSetupCoordinatorTests.swift @@ -6,6 +6,7 @@ import WordPressAuthenticator final class JetpackSetupCoordinatorTests: XCTestCase { private var navigationController: UINavigationController! + private let dotcomAuthScheme = "scheme" override func setUp() { navigationController = UINavigationController() @@ -47,7 +48,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { let url = try XCTUnwrap(URL(string: "example://handle-authentication")) // When - let result = coordinator.handleAuthenticationUrl(url) + let result = coordinator.handleAuthenticationUrl(url, dotcomAuthScheme: dotcomAuthScheme) // Then XCTAssertFalse(result) @@ -57,10 +58,10 @@ final class JetpackSetupCoordinatorTests: XCTestCase { // Given let testSite = Site.fake().copy(siteID: -1) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController) - let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://magic-login")) + let url = try XCTUnwrap(URL(string: "\(dotcomAuthScheme)://magic-login")) // When - let result = coordinator.handleAuthenticationUrl(url) + let result = coordinator.handleAuthenticationUrl(url, dotcomAuthScheme: dotcomAuthScheme) // Then XCTAssertFalse(result) @@ -70,10 +71,10 @@ final class JetpackSetupCoordinatorTests: XCTestCase { // Given let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController) - let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://handle-authentication?token=test")) + let url = try XCTUnwrap(URL(string: "\(dotcomAuthScheme)://handle-authentication?token=test")) // When - let result = coordinator.handleAuthenticationUrl(url) + let result = coordinator.handleAuthenticationUrl(url, dotcomAuthScheme: dotcomAuthScheme) // Then XCTAssertFalse(result) @@ -83,10 +84,10 @@ final class JetpackSetupCoordinatorTests: XCTestCase { // Given let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController) - let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://magic-login?token=test")) + let url = try XCTUnwrap(URL(string: "\(dotcomAuthScheme)://magic-login?token=test")) // When - let result = coordinator.handleAuthenticationUrl(url) + let result = coordinator.handleAuthenticationUrl(url, dotcomAuthScheme: dotcomAuthScheme) // Then XCTAssertTrue(result) @@ -97,7 +98,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { let stores = MockStoresManager(sessionManager: .makeForTesting(authenticated: true, isWPCom: false, defaultRoles: [.shopManager])) let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController, stores: stores) - let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://magic-login?token=test")) + let url = try XCTUnwrap(URL(string: "\(dotcomAuthScheme)://magic-login?token=test")) let expectedAccount = Account(userID: 123, displayName: "Test", email: "test@example.com", username: "test", gravatarUrl: nil) stores.whenReceivingAction(ofType: JetpackConnectionAction.self) { action in @@ -113,7 +114,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { stores.mockJetpackCheck() // When - let result = coordinator.handleAuthenticationUrl(url) + let result = coordinator.handleAuthenticationUrl(url, dotcomAuthScheme: dotcomAuthScheme) // Then XCTAssertTrue(result) @@ -127,7 +128,8 @@ final class JetpackSetupCoordinatorTests: XCTestCase { let stores = MockStoresManager(sessionManager: .makeForTesting(authenticated: true, isWPCom: false)) let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController, stores: stores) - let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://magic-login?token=test")) + let expectedScheme = "scheme" + let url = try XCTUnwrap(URL(string: "\(dotcomAuthScheme)://magic-login?token=test")) let expectedAccount = Account(userID: 123, displayName: "Test", email: "test@example.com", username: "test", gravatarUrl: nil) stores.whenReceivingAction(ofType: JetpackConnectionAction.self) { action in @@ -143,7 +145,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { stores.mockJetpackCheck() // When - let result = coordinator.handleAuthenticationUrl(url) + let result = coordinator.handleAuthenticationUrl(url, dotcomAuthScheme: dotcomAuthScheme) // Then XCTAssertTrue(result) @@ -158,7 +160,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { let siteURL = "https://example.com" let testSite = Site.fake().copy(siteID: WooConstants.placeholderStoreID, url: siteURL) let coordinator = JetpackSetupCoordinator(site: testSite, rootViewController: navigationController, stores: stores) - let url = try XCTUnwrap(URL(string: "\(ApiCredentials.dotcomAuthScheme)://magic-login?token=test")) + let url = try XCTUnwrap(URL(string: "\(dotcomAuthScheme)://magic-login?token=test")) let expectedAccount = Account(userID: 123, displayName: "Test", email: "test@example.com", username: "test", gravatarUrl: nil) stores.whenReceivingAction(ofType: JetpackConnectionAction.self) { action in @@ -198,7 +200,7 @@ final class JetpackSetupCoordinatorTests: XCTestCase { stores.mockJetpackCheck() // When - let result = coordinator.handleAuthenticationUrl(url) + let result = coordinator.handleAuthenticationUrl(url, dotcomAuthScheme: dotcomAuthScheme) // Then XCTAssertTrue(result)