Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Experiments/Experiments/ABTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ public enum ABTest: String, CaseIterable {
/// Experiment ref: pbxNRc-1S0-p2
case aaTestLoggedOut = "woocommerceios_explat_aa_test_logged_out_202211"

/// 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"

/// Returns a variation for the given experiment
public var variation: Variation {
ExPlat.shared?.experiment(rawValue) ?? .control
Expand All @@ -26,7 +30,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 .aaTestLoggedIn202210:
case .aaTestLoggedIn202210, .productsOnboardingBanner:
return .loggedIn
case .aaTestLoggedOut:
return .loggedOut
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Yosemite
import enum Networking.DotcomError
import enum Storage.StatsVersion
import protocol Experiments.FeatureFlagService
import enum Experiments.ABTest

/// Syncs data for dashboard stats UI and determines the state of the dashboard UI based on stats version.
final class DashboardViewModel {
Expand Down Expand Up @@ -124,7 +125,7 @@ final class DashboardViewModel {
if isEligible {
ServiceLocator.analytics.track(event: .ProductsOnboarding.storeIsEligible())

if self?.featureFlagService.isFeatureFlagEnabled(.productsOnboarding) == true {
if ABTest.productsOnboardingBanner.variation == .treatment(nil) {
let viewModel = ProductsOnboardingAnnouncementCardViewModel(onCTATapped: { [weak self] in
self?.announcementViewModel = nil // Dismiss announcement
MainTabBarController.presentAddProductFlow()
Expand Down
4 changes: 4 additions & 0 deletions WooCommerce/WooCommerce.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,7 @@
CC3B35DB28E5A6830036B097 /* ReviewReply.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC3B35DA28E5A6830036B097 /* ReviewReply.swift */; };
CC3B35DD28E5A6EA0036B097 /* ReviewReplyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC3B35DC28E5A6EA0036B097 /* ReviewReplyViewModel.swift */; };
CC3B35DF28E5BE6F0036B097 /* ReviewReplyViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC3B35DE28E5BE6F0036B097 /* ReviewReplyViewModelTests.swift */; };
CC3DB1DC291188CA00425961 /* MockABTesting.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC3DB1DB291188CA00425961 /* MockABTesting.swift */; };
CC440E1E2770C6AF0074C264 /* ProductInOrderViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC440E1D2770C6AF0074C264 /* ProductInOrderViewModel.swift */; };
CC4A4E962655273D00B75DCD /* ShippingLabelPaymentMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC4A4E952655273D00B75DCD /* ShippingLabelPaymentMethods.swift */; };
CC4A4ED82655478D00B75DCD /* ShippingLabelPaymentMethodsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC4A4ED72655478D00B75DCD /* ShippingLabelPaymentMethodsViewModel.swift */; };
Expand Down Expand Up @@ -3338,6 +3339,7 @@
CC3B35DA28E5A6830036B097 /* ReviewReply.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewReply.swift; sourceTree = "<group>"; };
CC3B35DC28E5A6EA0036B097 /* ReviewReplyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewReplyViewModel.swift; sourceTree = "<group>"; };
CC3B35DE28E5BE6F0036B097 /* ReviewReplyViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewReplyViewModelTests.swift; sourceTree = "<group>"; };
CC3DB1DB291188CA00425961 /* MockABTesting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockABTesting.swift; sourceTree = "<group>"; };
CC440E1D2770C6AF0074C264 /* ProductInOrderViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProductInOrderViewModel.swift; sourceTree = "<group>"; };
CC4A4E952655273D00B75DCD /* ShippingLabelPaymentMethods.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPaymentMethods.swift; sourceTree = "<group>"; };
CC4A4ED72655478D00B75DCD /* ShippingLabelPaymentMethodsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingLabelPaymentMethodsViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -6331,6 +6333,7 @@
B958A7D728B5316A00823EEF /* MockURLOpener.swift */,
EE8DCA7F28BF964700F23B23 /* MockAuthentication.swift */,
AEB4DB98290AE8F300AE4340 /* MockCookieJar.swift */,
CC3DB1DB291188CA00425961 /* MockABTesting.swift */,
);
path = Mocks;
sourceTree = "<group>";
Expand Down Expand Up @@ -10799,6 +10802,7 @@
31F21B02263C8E150035B50A /* CardReaderSettingsSearchingViewModelTests.swift in Sources */,
45EF798624509B4C00B22BA2 /* ArrayIndexPathTests.swift in Sources */,
D8610BDD256F5ABF00A5DF27 /* JetpackErrorViewModelTests.swift in Sources */,
CC3DB1DC291188CA00425961 /* MockABTesting.swift in Sources */,
746791632108D7C0007CF1DC /* WooAnalyticsTests.swift in Sources */,
2667BFDD252F61C5008099D4 /* RefundShippingDetailsViewModelTests.swift in Sources */,
DE7B479727A3C4980018742E /* CouponDetailsViewModelTests.swift in Sources */,
Expand Down
20 changes: 20 additions & 0 deletions WooCommerce/WooCommerceTests/Mocks/MockABTesting.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import Foundation
import enum AutomatticTracks.Variation
import enum Experiments.ABTest

struct MockABTesting {
/// Sets the provided A/B Test variation in `UserDefaults`, to mock a given experiment assignment
///
static func setVariation(_ variation: AutomatticTracks.Variation, for experiment: ABTest) {
let newVariation: String?
switch variation {
case .control:
newVariation = "control"
case .treatment(let type):
newVariation = type ?? "treatment"
}

let assignment = [experiment.rawValue: newVariation]
UserDefaults.standard.setValue(assignment, forKey: "ab-testing-assignments")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ final class DashboardViewModelTests: XCTestCase {

func test_products_onboarding_announcements_take_precedence() {
// Given
MockABTesting.setVariation(.treatment(nil), for: .productsOnboardingBanner)
let stores = MockStoresManager(sessionManager: .makeForTesting())
stores.whenReceivingAction(ofType: ProductAction.self) { action in
switch action {
Expand Down Expand Up @@ -164,32 +165,4 @@ final class DashboardViewModelTests: XCTestCase {
// Then
XCTAssertNil(viewModel.announcementViewModel)
}

func test_no_announcement_synced_when_feature_flags_disabled() {
// Given
let stores = MockStoresManager(sessionManager: .makeForTesting())
stores.whenReceivingAction(ofType: ProductAction.self) { action in
switch action {
case let .checkProductsOnboardingEligibility(_, completion):
completion(.success(true))
default:
XCTFail("Received unsupported action: \(action)")
}
}
stores.whenReceivingAction(ofType: JustInTimeMessageAction.self) { action in
switch action {
case let .loadMessage(_, _, _, completion):
completion(.success(Yosemite.JustInTimeMessage.fake()))
default:
XCTFail("Received unsupported action: \(action)")
}
}
let viewModel = DashboardViewModel(stores: stores, featureFlags: MockFeatureFlagService())

// When
viewModel.syncAnnouncements(for: sampleSiteID)

// Then
XCTAssertNil(viewModel.announcementViewModel)
}
}