Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
guard let tabBarController = AppDelegate.shared.tabBarController else {
return
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 @@ -1386,6 +1386,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 @@ -3334,6 +3335,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 @@ -6325,6 +6327,7 @@
B958A7D728B5316A00823EEF /* MockURLOpener.swift */,
EE8DCA7F28BF964700F23B23 /* MockAuthentication.swift */,
AEB4DB98290AE8F300AE4340 /* MockCookieJar.swift */,
CC3DB1DB291188CA00425961 /* MockABTesting.swift */,
);
path = Mocks;
sourceTree = "<group>";
Expand Down Expand Up @@ -10791,6 +10794,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 @@ -158,30 +159,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(YosemiteJustInTimeMessage.fake()))
}
}
let viewModel = DashboardViewModel(stores: stores, featureFlags: MockFeatureFlagService())

// When
viewModel.syncAnnouncements(for: sampleSiteID)

// Then
XCTAssertNil(viewModel.announcementViewModel)
}
}