From 526365f15a60e25b4b1c14c0f731302fa020ebdb Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Mon, 21 Nov 2022 14:48:00 +0530 Subject: [PATCH 01/10] Add Jetpack setup flow AB test case to `ABTest` enum --- Experiments/Experiments/ABTest.swift | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Experiments/Experiments/ABTest.swift b/Experiments/Experiments/ABTest.swift index a1d5185f48a..22d555b8a86 100644 --- a/Experiments/Experiments/ABTest.swift +++ b/Experiments/Experiments/ABTest.swift @@ -16,6 +16,11 @@ public enum ABTest: String, CaseIterable { /// case abTestLoginWithWPComOnly = "woocommerceios_login_wpcom_only" + /// A/B test to measure the sign-in success rate when native Jetpack installation experience is enabled + /// Experiment ref: + /// + case abTestNativeJetpackSetupFlow = "woocommerceios_login_jetpack_setup_flow" + /// A/B test for the Products Onboarding banner on the My Store dashboard. /// Experiment ref: pbxNRc-26F-p2 case productsOnboardingBanner = "woocommerceios_products_onboarding_first_product_banner" @@ -36,7 +41,7 @@ public enum ABTest: String, CaseIterable { switch self { case .productsOnboardingBanner, .productsOnboardingTemplateProducts: return .loggedIn - case .aaTestLoggedOut, .abTestLoginWithWPComOnly: + case .aaTestLoggedOut, .abTestLoginWithWPComOnly, .abTestNativeJetpackSetupFlow: return .loggedOut case .null: return .none From 6a6d6e9b3b13a093dca8964fa7285cb538d5a70b Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Mon, 21 Nov 2022 14:48:21 +0530 Subject: [PATCH 02/10] Replace `nativeJetpackSetupFlow` feature flag with AB testing enum case. --- Experiments/Experiments/DefaultFeatureFlagService.swift | 2 -- WooCommerce/Classes/Authentication/AuthenticationManager.swift | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Experiments/Experiments/DefaultFeatureFlagService.swift b/Experiments/Experiments/DefaultFeatureFlagService.swift index 8430218a127..d9f38a5746e 100644 --- a/Experiments/Experiments/DefaultFeatureFlagService.swift +++ b/Experiments/Experiments/DefaultFeatureFlagService.swift @@ -51,8 +51,6 @@ public struct DefaultFeatureFlagService: FeatureFlagService { .performanceMonitoringUserInteraction: // Disabled by default to avoid costs spikes, unless in internal testing builds. return buildConfig == .alpha - case .nativeJetpackSetupFlow: - return buildConfig == .localDeveloper || buildConfig == .alpha case .analyticsHub: return buildConfig == .localDeveloper || buildConfig == .alpha case .tapToPayOnIPhone: diff --git a/WooCommerce/Classes/Authentication/AuthenticationManager.swift b/WooCommerce/Classes/Authentication/AuthenticationManager.swift index a7edba336c1..fabc786e660 100644 --- a/WooCommerce/Classes/Authentication/AuthenticationManager.swift +++ b/WooCommerce/Classes/Authentication/AuthenticationManager.swift @@ -761,8 +761,7 @@ private extension AuthenticationManager { } // Shows the native Jetpack flow during the site discovery flow. - // TODO-8075: replace feature flag with A/B testing - if featureFlagService.isFeatureFlagEnabled(.nativeJetpackSetupFlow) { + if ABTest.abTestNativeJetpackSetupFlow.variation == .control { return jetpackSetupUI(for: site.url, connectionMissingOnly: site.hasJetpack && site.isJetpackActive, in: navigationController) From ccb247658843ee6234e5742e674683af8f92df1b Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Mon, 21 Nov 2022 16:40:28 +0530 Subject: [PATCH 03/10] Load treatment only when the abTest is not equal to control. --- WooCommerce/Classes/Authentication/AuthenticationManager.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WooCommerce/Classes/Authentication/AuthenticationManager.swift b/WooCommerce/Classes/Authentication/AuthenticationManager.swift index fabc786e660..3a74f185115 100644 --- a/WooCommerce/Classes/Authentication/AuthenticationManager.swift +++ b/WooCommerce/Classes/Authentication/AuthenticationManager.swift @@ -761,7 +761,7 @@ private extension AuthenticationManager { } // Shows the native Jetpack flow during the site discovery flow. - if ABTest.abTestNativeJetpackSetupFlow.variation == .control { + if ABTest.abTestNativeJetpackSetupFlow.variation != .control { return jetpackSetupUI(for: site.url, connectionMissingOnly: site.hasJetpack && site.isJetpackActive, in: navigationController) From 305441e58504df1c801662a99c4ab2ad835bc58c Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Mon, 21 Nov 2022 16:49:26 +0530 Subject: [PATCH 04/10] Add experiment reference P2. --- Experiments/Experiments/ABTest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experiments/Experiments/ABTest.swift b/Experiments/Experiments/ABTest.swift index 22d555b8a86..e028beba473 100644 --- a/Experiments/Experiments/ABTest.swift +++ b/Experiments/Experiments/ABTest.swift @@ -17,7 +17,7 @@ public enum ABTest: String, CaseIterable { case abTestLoginWithWPComOnly = "woocommerceios_login_wpcom_only" /// A/B test to measure the sign-in success rate when native Jetpack installation experience is enabled - /// Experiment ref: + /// Experiment ref: pbxNRc-29W-p2 /// case abTestNativeJetpackSetupFlow = "woocommerceios_login_jetpack_setup_flow" From 198414f227e59e0c3d23ff295db83efaa1f6cb54 Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Thu, 24 Nov 2022 12:26:51 +0530 Subject: [PATCH 05/10] Treat `abTestNativeJetpackSetupFlow` as logged in experiment as the Jetpack installation happens after logging in. --- Experiments/Experiments/ABTest.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Experiments/Experiments/ABTest.swift b/Experiments/Experiments/ABTest.swift index e028beba473..9445a3763bc 100644 --- a/Experiments/Experiments/ABTest.swift +++ b/Experiments/Experiments/ABTest.swift @@ -39,9 +39,9 @@ public enum ABTest: String, CaseIterable { /// When adding a new experiment, add it to the appropriate case depending on its context (logged-in or logged-out experience). public var context: ExperimentContext { switch self { - case .productsOnboardingBanner, .productsOnboardingTemplateProducts: + case .productsOnboardingBanner, .productsOnboardingTemplateProducts, .abTestNativeJetpackSetupFlow: return .loggedIn - case .aaTestLoggedOut, .abTestLoginWithWPComOnly, .abTestNativeJetpackSetupFlow: + case .aaTestLoggedOut, .abTestLoginWithWPComOnly: return .loggedOut case .null: return .none From 56b1f4b66ee424df2e10ec69a98de64c041b7ef7 Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Fri, 25 Nov 2022 11:43:25 +0530 Subject: [PATCH 06/10] Update ABTest for the new `customTreatment` case from Tracks library. --- Experiments/Experiments/ABTest.swift | 6 +++-- Podfile | 4 +-- Podfile.lock | 27 ++++++++++++------- .../Dashboard/DashboardViewModel.swift | 2 +- .../Add Product/AddProductCoordinator.swift | 4 +-- .../Dashboard/DashboardViewModelTests.swift | 4 +-- 6 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Experiments/Experiments/ABTest.swift b/Experiments/Experiments/ABTest.swift index 9445a3763bc..2d751665ca5 100644 --- a/Experiments/Experiments/ABTest.swift +++ b/Experiments/Experiments/ABTest.swift @@ -76,8 +76,10 @@ public extension Variation { switch self { case .control: return "control" - case .treatment(let string): - return string.map { "treatment: \($0)" } ?? "treatment" + case .treatment: + return "treatment" + case .customTreatment(let string): + return "treatment: \(string)" } } } diff --git a/Podfile b/Podfile index 0a8f87975dd..3cda7788b2c 100644 --- a/Podfile +++ b/Podfile @@ -27,9 +27,9 @@ def aztec end def tracks - pod 'Automattic-Tracks-iOS', '~> 0.13.0' + # pod 'Automattic-Tracks-iOS', '~> 0.13.0' # pod 'Automattic-Tracks-iOS', :git => 'https://github.com/Automattic/Automattic-Tracks-iOS.git', :branch => '' - # pod 'Automattic-Tracks-iOS', :git => 'https://github.com/Automattic/Automattic-Tracks-iOS.git', :commit => '' + pod 'Automattic-Tracks-iOS', :git => 'https://github.com/Automattic/Automattic-Tracks-iOS.git', :commit => '5bcaa6db14d314ff388ed145af15c7a0379ee017' # pod 'Automattic-Tracks-iOS', :path => '../Automattic-Tracks-iOS' end diff --git a/Podfile.lock b/Podfile.lock index 4c898754f1f..97e98e6c4b9 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -31,14 +31,14 @@ PODS: - Kingfisher (7.2.2) - NSObject-SafeExpectations (0.0.4) - "NSURL+IDN (0.4)" - - Sentry (7.25.1): - - Sentry/Core (= 7.25.1) - - Sentry/Core (7.25.1) + - Sentry (7.31.2): + - Sentry/Core (= 7.31.2) + - Sentry/Core (7.31.2) - Sodium (0.9.1) - Sourcery (1.0.3) - StripeTerminal (2.14.0) - SVProgressHUD (2.2.5) - - UIDeviceIdentifier (2.0.0) + - UIDeviceIdentifier (2.2.0) - WordPress-Aztec-iOS (1.11.0) - WordPress-Editor-iOS (1.11.0): - WordPress-Aztec-iOS (= 1.11.0) @@ -82,7 +82,7 @@ PODS: DEPENDENCIES: - Alamofire (~> 4.8) - - Automattic-Tracks-iOS (~> 0.13.0) + - Automattic-Tracks-iOS (from `https://github.com/Automattic/Automattic-Tracks-iOS.git`, commit `5bcaa6db14d314ff388ed145af15c7a0379ee017`) - CocoaLumberjack (~> 3.7.4) - CocoaLumberjack/Swift (~> 3.7.4) - Gridicons (~> 1.2.0) @@ -106,7 +106,6 @@ SPEC REPOS: trunk: - Alamofire - AppAuth - - Automattic-Tracks-iOS - CocoaLumberjack - FormatterKit - GoogleSignIn @@ -140,6 +139,16 @@ SPEC REPOS: - ZendeskSupportProvidersSDK - ZendeskSupportSDK +EXTERNAL SOURCES: + Automattic-Tracks-iOS: + :commit: 5bcaa6db14d314ff388ed145af15c7a0379ee017 + :git: https://github.com/Automattic/Automattic-Tracks-iOS.git + +CHECKOUT OPTIONS: + Automattic-Tracks-iOS: + :commit: 5bcaa6db14d314ff388ed145af15c7a0379ee017 + :git: https://github.com/Automattic/Automattic-Tracks-iOS.git + SPEC CHECKSUMS: Alamofire: 3ec537f71edc9804815215393ae2b1a8ea33a844 AppAuth: 8fca6b5563a5baef2c04bee27538025e4ceb2add @@ -154,12 +163,12 @@ SPEC CHECKSUMS: Kingfisher: 184d4d1a8c36666e663caf8e08abe87898595c53 NSObject-SafeExpectations: ab8fe623d36b25aa1f150affa324e40a2f3c0374 "NSURL+IDN": afc873e639c18138a1589697c3add197fe8679ca - Sentry: dd29c18c32b0af9269949f079cf631d581ca76ca + Sentry: b15765d11769852fe78c9add942f7df60ed5dbf5 Sodium: 23d11554ecd556196d313cf6130d406dfe7ac6da Sourcery: 70a6048014bd4f37ea80e6bd4354d47bf3b760e1 StripeTerminal: 9bb367c9efa7bcddf2602cc29f8962390d87b6a6 SVProgressHUD: 1428aafac632c1f86f62aa4243ec12008d7a51d6 - UIDeviceIdentifier: af4e11e25a2ea670078e2bd677bb0e8144f9f063 + UIDeviceIdentifier: f33af270ba9045ea18b31d9aab88e42a0082ea67 WordPress-Aztec-iOS: 050b34d4c3adfb7c60363849049b13d60683b348 WordPress-Editor-iOS: 304098424f1051cb271546c99f906aac296b1b81 WordPressAuthenticator: 27178591a805804bd27959f1f76ddcb94605916c @@ -178,6 +187,6 @@ SPEC CHECKSUMS: ZendeskSupportProvidersSDK: 2bdf8544f7cd0fd4c002546f5704b813845beb2a ZendeskSupportSDK: 3a8e508ab1d9dd22dc038df6c694466414e037ba -PODFILE CHECKSUM: 8b243f1ea76d4db3aa638b50ef0d516185d01c2c +PODFILE CHECKSUM: 7ece374478e82b0728d3bd4eb086e5171a80e50f COCOAPODS: 1.11.3 diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewModel.swift b/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewModel.swift index f0827dc8264..8ef53835f04 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewModel.swift @@ -151,7 +151,7 @@ final class DashboardViewModel { /// and if the user is part of the treatment group for the products onboarding A/B test. /// private func setProductsOnboardingBannerIfNeeded() { - guard ABTest.productsOnboardingBanner.variation == .treatment(nil) else { + guard ABTest.productsOnboardingBanner.variation == .treatment else { return } diff --git a/WooCommerce/Classes/ViewRelated/Products/Add Product/AddProductCoordinator.swift b/WooCommerce/Classes/ViewRelated/Products/Add Product/AddProductCoordinator.swift index 46337b05e57..ed43cb844fa 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Add Product/AddProductCoordinator.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Add Product/AddProductCoordinator.swift @@ -37,7 +37,7 @@ final class AddProductCoordinator: Coordinator { init(siteID: Int64, sourceBarButtonItem: UIBarButtonItem, sourceNavigationController: UINavigationController, - isProductCreationTypeEnabled: Bool = ABTest.productsOnboardingTemplateProducts.variation == .treatment(nil), + isProductCreationTypeEnabled: Bool = ABTest.productsOnboardingTemplateProducts.variation == .treatment, storage: StorageManagerType = ServiceLocator.storageManager, productImageUploader: ProductImageUploaderProtocol = ServiceLocator.productImageUploader) { self.siteID = siteID @@ -52,7 +52,7 @@ final class AddProductCoordinator: Coordinator { init(siteID: Int64, sourceView: UIView, sourceNavigationController: UINavigationController, - isProductCreationTypeEnabled: Bool = ABTest.productsOnboardingTemplateProducts.variation == .treatment(nil), + isProductCreationTypeEnabled: Bool = ABTest.productsOnboardingTemplateProducts.variation == .treatment, storage: StorageManagerType = ServiceLocator.storageManager, productImageUploader: ProductImageUploaderProtocol = ServiceLocator.productImageUploader) { self.siteID = siteID diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Dashboard/DashboardViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Dashboard/DashboardViewModelTests.swift index 29302c669a1..1b852cd0b98 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Dashboard/DashboardViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Dashboard/DashboardViewModelTests.swift @@ -91,7 +91,7 @@ final class DashboardViewModelTests: XCTestCase { func test_products_onboarding_announcements_take_precedence() { // Given - MockABTesting.setVariation(.treatment(nil), for: .productsOnboardingBanner) + MockABTesting.setVariation(.treatment, for: .productsOnboardingBanner) stores.whenReceivingAction(ofType: ProductAction.self) { action in switch action { case let .checkProductsOnboardingEligibility(_, completion): @@ -127,7 +127,7 @@ final class DashboardViewModelTests: XCTestCase { func test_onboarding_announcement_not_displayed_when_previously_dismissed() { // Given - MockABTesting.setVariation(.treatment(nil), for: .productsOnboardingBanner) + MockABTesting.setVariation(.treatment, for: .productsOnboardingBanner) stores.whenReceivingAction(ofType: ProductAction.self) { action in switch action { case let .checkProductsOnboardingEligibility(_, completion): From 6600bf7369eb6fb342dc9b63f720100dc1349859 Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Fri, 25 Nov 2022 12:57:02 +0530 Subject: [PATCH 07/10] Revert "Update ABTest for the new `customTreatment` case from Tracks library." This reverts commit 56b1f4b66ee424df2e10ec69a98de64c041b7ef7. --- Experiments/Experiments/ABTest.swift | 6 ++--- Podfile | 4 +-- Podfile.lock | 27 +++++++------------ .../Dashboard/DashboardViewModel.swift | 2 +- .../Add Product/AddProductCoordinator.swift | 4 +-- .../Dashboard/DashboardViewModelTests.swift | 4 +-- 6 files changed, 18 insertions(+), 29 deletions(-) diff --git a/Experiments/Experiments/ABTest.swift b/Experiments/Experiments/ABTest.swift index 2d751665ca5..9445a3763bc 100644 --- a/Experiments/Experiments/ABTest.swift +++ b/Experiments/Experiments/ABTest.swift @@ -76,10 +76,8 @@ public extension Variation { switch self { case .control: return "control" - case .treatment: - return "treatment" - case .customTreatment(let string): - return "treatment: \(string)" + case .treatment(let string): + return string.map { "treatment: \($0)" } ?? "treatment" } } } diff --git a/Podfile b/Podfile index 3cda7788b2c..0a8f87975dd 100644 --- a/Podfile +++ b/Podfile @@ -27,9 +27,9 @@ def aztec end def tracks - # pod 'Automattic-Tracks-iOS', '~> 0.13.0' + pod 'Automattic-Tracks-iOS', '~> 0.13.0' # pod 'Automattic-Tracks-iOS', :git => 'https://github.com/Automattic/Automattic-Tracks-iOS.git', :branch => '' - pod 'Automattic-Tracks-iOS', :git => 'https://github.com/Automattic/Automattic-Tracks-iOS.git', :commit => '5bcaa6db14d314ff388ed145af15c7a0379ee017' + # pod 'Automattic-Tracks-iOS', :git => 'https://github.com/Automattic/Automattic-Tracks-iOS.git', :commit => '' # pod 'Automattic-Tracks-iOS', :path => '../Automattic-Tracks-iOS' end diff --git a/Podfile.lock b/Podfile.lock index 97e98e6c4b9..4c898754f1f 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -31,14 +31,14 @@ PODS: - Kingfisher (7.2.2) - NSObject-SafeExpectations (0.0.4) - "NSURL+IDN (0.4)" - - Sentry (7.31.2): - - Sentry/Core (= 7.31.2) - - Sentry/Core (7.31.2) + - Sentry (7.25.1): + - Sentry/Core (= 7.25.1) + - Sentry/Core (7.25.1) - Sodium (0.9.1) - Sourcery (1.0.3) - StripeTerminal (2.14.0) - SVProgressHUD (2.2.5) - - UIDeviceIdentifier (2.2.0) + - UIDeviceIdentifier (2.0.0) - WordPress-Aztec-iOS (1.11.0) - WordPress-Editor-iOS (1.11.0): - WordPress-Aztec-iOS (= 1.11.0) @@ -82,7 +82,7 @@ PODS: DEPENDENCIES: - Alamofire (~> 4.8) - - Automattic-Tracks-iOS (from `https://github.com/Automattic/Automattic-Tracks-iOS.git`, commit `5bcaa6db14d314ff388ed145af15c7a0379ee017`) + - Automattic-Tracks-iOS (~> 0.13.0) - CocoaLumberjack (~> 3.7.4) - CocoaLumberjack/Swift (~> 3.7.4) - Gridicons (~> 1.2.0) @@ -106,6 +106,7 @@ SPEC REPOS: trunk: - Alamofire - AppAuth + - Automattic-Tracks-iOS - CocoaLumberjack - FormatterKit - GoogleSignIn @@ -139,16 +140,6 @@ SPEC REPOS: - ZendeskSupportProvidersSDK - ZendeskSupportSDK -EXTERNAL SOURCES: - Automattic-Tracks-iOS: - :commit: 5bcaa6db14d314ff388ed145af15c7a0379ee017 - :git: https://github.com/Automattic/Automattic-Tracks-iOS.git - -CHECKOUT OPTIONS: - Automattic-Tracks-iOS: - :commit: 5bcaa6db14d314ff388ed145af15c7a0379ee017 - :git: https://github.com/Automattic/Automattic-Tracks-iOS.git - SPEC CHECKSUMS: Alamofire: 3ec537f71edc9804815215393ae2b1a8ea33a844 AppAuth: 8fca6b5563a5baef2c04bee27538025e4ceb2add @@ -163,12 +154,12 @@ SPEC CHECKSUMS: Kingfisher: 184d4d1a8c36666e663caf8e08abe87898595c53 NSObject-SafeExpectations: ab8fe623d36b25aa1f150affa324e40a2f3c0374 "NSURL+IDN": afc873e639c18138a1589697c3add197fe8679ca - Sentry: b15765d11769852fe78c9add942f7df60ed5dbf5 + Sentry: dd29c18c32b0af9269949f079cf631d581ca76ca Sodium: 23d11554ecd556196d313cf6130d406dfe7ac6da Sourcery: 70a6048014bd4f37ea80e6bd4354d47bf3b760e1 StripeTerminal: 9bb367c9efa7bcddf2602cc29f8962390d87b6a6 SVProgressHUD: 1428aafac632c1f86f62aa4243ec12008d7a51d6 - UIDeviceIdentifier: f33af270ba9045ea18b31d9aab88e42a0082ea67 + UIDeviceIdentifier: af4e11e25a2ea670078e2bd677bb0e8144f9f063 WordPress-Aztec-iOS: 050b34d4c3adfb7c60363849049b13d60683b348 WordPress-Editor-iOS: 304098424f1051cb271546c99f906aac296b1b81 WordPressAuthenticator: 27178591a805804bd27959f1f76ddcb94605916c @@ -187,6 +178,6 @@ SPEC CHECKSUMS: ZendeskSupportProvidersSDK: 2bdf8544f7cd0fd4c002546f5704b813845beb2a ZendeskSupportSDK: 3a8e508ab1d9dd22dc038df6c694466414e037ba -PODFILE CHECKSUM: 7ece374478e82b0728d3bd4eb086e5171a80e50f +PODFILE CHECKSUM: 8b243f1ea76d4db3aa638b50ef0d516185d01c2c COCOAPODS: 1.11.3 diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewModel.swift b/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewModel.swift index 8ef53835f04..f0827dc8264 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/DashboardViewModel.swift @@ -151,7 +151,7 @@ final class DashboardViewModel { /// and if the user is part of the treatment group for the products onboarding A/B test. /// private func setProductsOnboardingBannerIfNeeded() { - guard ABTest.productsOnboardingBanner.variation == .treatment else { + guard ABTest.productsOnboardingBanner.variation == .treatment(nil) else { return } diff --git a/WooCommerce/Classes/ViewRelated/Products/Add Product/AddProductCoordinator.swift b/WooCommerce/Classes/ViewRelated/Products/Add Product/AddProductCoordinator.swift index ed43cb844fa..46337b05e57 100644 --- a/WooCommerce/Classes/ViewRelated/Products/Add Product/AddProductCoordinator.swift +++ b/WooCommerce/Classes/ViewRelated/Products/Add Product/AddProductCoordinator.swift @@ -37,7 +37,7 @@ final class AddProductCoordinator: Coordinator { init(siteID: Int64, sourceBarButtonItem: UIBarButtonItem, sourceNavigationController: UINavigationController, - isProductCreationTypeEnabled: Bool = ABTest.productsOnboardingTemplateProducts.variation == .treatment, + isProductCreationTypeEnabled: Bool = ABTest.productsOnboardingTemplateProducts.variation == .treatment(nil), storage: StorageManagerType = ServiceLocator.storageManager, productImageUploader: ProductImageUploaderProtocol = ServiceLocator.productImageUploader) { self.siteID = siteID @@ -52,7 +52,7 @@ final class AddProductCoordinator: Coordinator { init(siteID: Int64, sourceView: UIView, sourceNavigationController: UINavigationController, - isProductCreationTypeEnabled: Bool = ABTest.productsOnboardingTemplateProducts.variation == .treatment, + isProductCreationTypeEnabled: Bool = ABTest.productsOnboardingTemplateProducts.variation == .treatment(nil), storage: StorageManagerType = ServiceLocator.storageManager, productImageUploader: ProductImageUploaderProtocol = ServiceLocator.productImageUploader) { self.siteID = siteID diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Dashboard/DashboardViewModelTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Dashboard/DashboardViewModelTests.swift index 1b852cd0b98..29302c669a1 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Dashboard/DashboardViewModelTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Dashboard/DashboardViewModelTests.swift @@ -91,7 +91,7 @@ final class DashboardViewModelTests: XCTestCase { func test_products_onboarding_announcements_take_precedence() { // Given - MockABTesting.setVariation(.treatment, for: .productsOnboardingBanner) + MockABTesting.setVariation(.treatment(nil), for: .productsOnboardingBanner) stores.whenReceivingAction(ofType: ProductAction.self) { action in switch action { case let .checkProductsOnboardingEligibility(_, completion): @@ -127,7 +127,7 @@ final class DashboardViewModelTests: XCTestCase { func test_onboarding_announcement_not_displayed_when_previously_dismissed() { // Given - MockABTesting.setVariation(.treatment, for: .productsOnboardingBanner) + MockABTesting.setVariation(.treatment(nil), for: .productsOnboardingBanner) stores.whenReceivingAction(ofType: ProductAction.self) { action in switch action { case let .checkProductsOnboardingEligibility(_, completion): From a90b9e5cec8c12d2cb8935ec4bd95dfbe6958af7 Mon Sep 17 00:00:00 2001 From: Jaclyn Chen Date: Fri, 25 Nov 2022 14:45:20 +0800 Subject: [PATCH 08/10] Refresh A/B tests after each `refreshUserData` where `ExPlat.shared` is reset. --- Experiments/Experiments/ABTest.swift | 1 + .../Classes/Analytics/WooAnalytics.swift | 10 +++++++++ WooCommerce/Classes/AppDelegate.swift | 22 +++++-------------- .../Epilogue/StorePickerViewController.swift | 12 ---------- .../Yosemite/DefaultStoresManager.swift | 5 ----- 5 files changed, 17 insertions(+), 33 deletions(-) diff --git a/Experiments/Experiments/ABTest.swift b/Experiments/Experiments/ABTest.swift index 9445a3763bc..96b0df61ab0 100644 --- a/Experiments/Experiments/ABTest.swift +++ b/Experiments/Experiments/ABTest.swift @@ -52,6 +52,7 @@ public enum ABTest: String, CaseIterable { public extension ABTest { /// Start the AB Testing platform if any experiment exists for the provided context /// + @MainActor static func start(for context: ExperimentContext) async { let experiments = ABTest.allCases.filter { $0.context == context } diff --git a/WooCommerce/Classes/Analytics/WooAnalytics.swift b/WooCommerce/Classes/Analytics/WooAnalytics.swift index 99b4f119491..2523201a6df 100644 --- a/WooCommerce/Classes/Analytics/WooAnalytics.swift +++ b/WooCommerce/Classes/Analytics/WooAnalytics.swift @@ -1,3 +1,4 @@ +import Experiments import Foundation import UIKit import WordPressShared @@ -60,6 +61,15 @@ public extension WooAnalytics { } analyticsProvider.refreshUserData() + + // Refreshes A/B experiments since `ExPlat.shared` is reset after each `TracksProvider.refreshUserData` call + // and any A/B test assignments that come back after the shared instance is reset won't be saved for later + // access. + let context: ExperimentContext = ServiceLocator.stores.isAuthenticated ? + .loggedIn: .loggedOut + Task { @MainActor in + await ABTest.start(for: context) + } } /// Track a spcific event without any associated properties diff --git a/WooCommerce/Classes/AppDelegate.swift b/WooCommerce/Classes/AppDelegate.swift index 848556c044d..dec6193d4c3 100644 --- a/WooCommerce/Classes/AppDelegate.swift +++ b/WooCommerce/Classes/AppDelegate.swift @@ -73,15 +73,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // ever new source code is injected into our application. Inject.animation = .interactiveSpring() - Task { @MainActor in - await startABTesting() - - // Upgrade check... - // This has to be called after A/B testing setup in `startABTesting` if any of the Tracks events - // in `checkForUpgrades` is used as an exposure event for an experiment. - // For example, `application_installed` could be the exposure event for logged-out experiments. - checkForUpgrades() - } + // Upgrade check... + // This has to be called after A/B testing setup in `setupAnalytics` (which calls + // `WooAnalytics.refreshUserData`) if any of the Tracks events in `checkForUpgrades` is + // used as an exposure event for an experiment. + // For example, `application_installed` could be the exposure event for logged-out experiments. + checkForUpgrades() return true } @@ -372,13 +369,6 @@ private extension AppDelegate { } } - /// Starts the AB testing platform and fetches test assignments for the current context - /// - func startABTesting() async { - let context: ExperimentContext = ServiceLocator.stores.isAuthenticated ? .loggedIn : .loggedOut - await ABTest.start(for: context) - } - /// Tracks if the application was opened via a widget tap. /// func trackWidgetTappedIfNeeded(userActivity: NSUserActivity) { diff --git a/WooCommerce/Classes/Authentication/Epilogue/StorePickerViewController.swift b/WooCommerce/Classes/Authentication/Epilogue/StorePickerViewController.swift index 66c1a35e8cf..0867951e050 100644 --- a/WooCommerce/Classes/Authentication/Epilogue/StorePickerViewController.swift +++ b/WooCommerce/Classes/Authentication/Epilogue/StorePickerViewController.swift @@ -201,7 +201,6 @@ final class StorePickerViewController: UIViewController { switch configuration { case .login: startListeningToNotifications() - startABTesting() case .switchingStores: secondaryActionButton.isHidden = true default: @@ -574,17 +573,6 @@ private extension StorePickerViewController { fancyAlert.transitioningDelegate = AppDelegate.shared.tabBarController present(fancyAlert, animated: true) } - - /// Refreshes the AB testing assignments (refresh is needed after a user logs in) - /// - func startABTesting() { - guard ServiceLocator.stores.isAuthenticated else { - return - } - Task { @MainActor in - await ABTest.start(for: .loggedIn) - } - } } // MARK: Transition Controller Delegate diff --git a/WooCommerce/Classes/Yosemite/DefaultStoresManager.swift b/WooCommerce/Classes/Yosemite/DefaultStoresManager.swift index b948fd8f563..e93e637a686 100644 --- a/WooCommerce/Classes/Yosemite/DefaultStoresManager.swift +++ b/WooCommerce/Classes/Yosemite/DefaultStoresManager.swift @@ -178,11 +178,6 @@ class DefaultStoresManager: StoresManager { updateAndReloadWidgetInformation(with: nil) - // Refresh the A/B test assignments for the logged-out context - Task { @MainActor in - await ABTest.start(for: .loggedOut) - } - NotificationCenter.default.post(name: .logOutEventReceived, object: nil) return self From 2121554205f05ee1ef27f3a51c138119390de803 Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Fri, 25 Nov 2022 14:32:32 +0530 Subject: [PATCH 09/10] Remove redundant abTest name from enum case. --- Experiments/Experiments/ABTest.swift | 4 ++-- .../Classes/Authentication/AuthenticationManager.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Experiments/Experiments/ABTest.swift b/Experiments/Experiments/ABTest.swift index 96b0df61ab0..b5aac38bb37 100644 --- a/Experiments/Experiments/ABTest.swift +++ b/Experiments/Experiments/ABTest.swift @@ -19,7 +19,7 @@ public enum ABTest: String, CaseIterable { /// A/B test to measure the sign-in success rate when native Jetpack installation experience is enabled /// Experiment ref: pbxNRc-29W-p2 /// - case abTestNativeJetpackSetupFlow = "woocommerceios_login_jetpack_setup_flow" + case nativeJetpackSetupFlow = "woocommerceios_login_jetpack_setup_flow" /// A/B test for the Products Onboarding banner on the My Store dashboard. /// Experiment ref: pbxNRc-26F-p2 @@ -39,7 +39,7 @@ public enum ABTest: String, CaseIterable { /// When adding a new experiment, add it to the appropriate case depending on its context (logged-in or logged-out experience). public var context: ExperimentContext { switch self { - case .productsOnboardingBanner, .productsOnboardingTemplateProducts, .abTestNativeJetpackSetupFlow: + case .productsOnboardingBanner, .productsOnboardingTemplateProducts, .nativeJetpackSetupFlow: return .loggedIn case .aaTestLoggedOut, .abTestLoginWithWPComOnly: return .loggedOut diff --git a/WooCommerce/Classes/Authentication/AuthenticationManager.swift b/WooCommerce/Classes/Authentication/AuthenticationManager.swift index 3a74f185115..aad92d2ec1a 100644 --- a/WooCommerce/Classes/Authentication/AuthenticationManager.swift +++ b/WooCommerce/Classes/Authentication/AuthenticationManager.swift @@ -761,7 +761,7 @@ private extension AuthenticationManager { } // Shows the native Jetpack flow during the site discovery flow. - if ABTest.abTestNativeJetpackSetupFlow.variation != .control { + if ABTest.nativeJetpackSetupFlow.variation != .control { return jetpackSetupUI(for: site.url, connectionMissingOnly: site.hasJetpack && site.isJetpackActive, in: navigationController) From f61ea324b622c5ffeeed751cc43ca7191267ce84 Mon Sep 17 00:00:00 2001 From: Sharma Elanthiraiyan Date: Fri, 25 Nov 2022 14:32:48 +0530 Subject: [PATCH 10/10] Remove unused feature flag. --- Experiments/Experiments/FeatureFlag.swift | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Experiments/Experiments/FeatureFlag.swift b/Experiments/Experiments/FeatureFlag.swift index 417aa0513dc..53c1177f972 100644 --- a/Experiments/Experiments/FeatureFlag.swift +++ b/Experiments/Experiments/FeatureFlag.swift @@ -130,11 +130,6 @@ public enum FeatureFlag: Int { /// - Note: The app will ignore this if `performanceMonitoring` is `false`. case performanceMonitoringViewController - /// Temporary feature flag for the native Jetpack setup flow. - /// TODO-8075: replace this with A/B test. - /// - case nativeJetpackSetupFlow - /// Temporary feature flag for the native Jetpack setup flow. /// case analyticsHub