diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Beta features/ApplicationPasswordsExperimentState.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Beta features/ApplicationPasswordsExperimentState.swift index 1ad27581851..03b178fd721 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Beta features/ApplicationPasswordsExperimentState.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Beta features/ApplicationPasswordsExperimentState.swift @@ -36,18 +36,26 @@ final class ApplicationPasswordsExperimentState { } protocol ApplicationPasswordsExperimentAvailabilityCheckerProtocol { - var cachedValue: Bool { get } + var isAvailable: Bool { get } func fetchAvailability() async -> Bool } final class ApplicationPasswordsExperimentAvailabilityChecker: ApplicationPasswordsExperimentAvailabilityCheckerProtocol { private let userDefaults: UserDefaults + private let stores: StoresManager - init(userDefaults: UserDefaults = .standard) { + init(userDefaults: UserDefaults = .standard, stores: StoresManager = ServiceLocator.stores) { self.userDefaults = userDefaults + self.stores = stores + } + + var isAvailable: Bool { + /// The feature is only available when the user is signed in using WordPress.com account + let isUserAuthenticatedByWPCom = !stores.isAuthenticatedWithoutWPCom + return isUserAuthenticatedByWPCom && cachedRemoteFFValue } - var cachedValue: Bool { + private var cachedRemoteFFValue: Bool { get { userDefaults[.applicationPasswordsExperimentRemoteFFValue] ?? false } set { @@ -58,13 +66,16 @@ final class ApplicationPasswordsExperimentAvailabilityChecker: ApplicationPasswo func fetchAvailability() async -> Bool { await withCheckedContinuation { continuation in //TODO: - put the remote FF checking here - let mockResultValue = true + //For now rely on local FF for mocked value to avoid unwanted exposure + let mockResultValue = ServiceLocator.featureFlagService.isFeatureFlagEnabled( + .applicationPasswordExperiment + ) DispatchQueue.main.asyncAfter(deadline: .now() + 3) { continuation.resume(returning: mockResultValue) } - cachedValue = mockResultValue + cachedRemoteFFValue = mockResultValue } } } diff --git a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Beta features/BetaFeaturesConfigurationViewModel.swift b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Beta features/BetaFeaturesConfigurationViewModel.swift index dd917e7c75c..bf86e6489cd 100644 --- a/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Beta features/BetaFeaturesConfigurationViewModel.swift +++ b/WooCommerce/Classes/ViewRelated/Dashboard/Settings/Beta features/BetaFeaturesConfigurationViewModel.swift @@ -32,7 +32,7 @@ private extension BetaFeaturesConfigurationViewModel { case .viewAddOns: return true case .applicationPasswords: - return appPasswordsExperimentAvailabilityChecker.cachedValue + return appPasswordsExperimentAvailabilityChecker.isAvailable } } diff --git a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj index 567757393c5..cc13696ac1a 100644 --- a/WooCommerce/WooCommerce.xcodeproj/project.pbxproj +++ b/WooCommerce/WooCommerce.xcodeproj/project.pbxproj @@ -1233,6 +1233,7 @@ 2D09E0D52E65C9B9005C26F3 /* ApplicationPasswordsExperimentStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D09E0D42E65C9B9005C26F3 /* ApplicationPasswordsExperimentStateTests.swift */; }; 2D880B492DFB2F3F00A6FB2C /* OptionalBinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D880B482DFB2F3D00A6FB2C /* OptionalBinding.swift */; }; 2D88C1112DF883C300A6FB2C /* AttributedString+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D88C1102DF883BD00A6FB2C /* AttributedString+Helpers.swift */; }; + 2DA63E042E69B6D400B0CB28 /* ApplicationPasswordsExperimentAvailabilityCheckerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DA63E032E69B6D200B0CB28 /* ApplicationPasswordsExperimentAvailabilityCheckerTests.swift */; }; 2DB877522E25466C0001B175 /* ShippingItemRowAccessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DB877512E25466B0001B175 /* ShippingItemRowAccessibility.swift */; }; 2DB88DA42E27DD8D0001B175 /* MarkOrderAsReadUseCase+Woo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DB88DA32E27DD790001B175 /* MarkOrderAsReadUseCase+Woo.swift */; }; 2DB891662E27F0830001B175 /* Address+Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DB891652E27F07E0001B175 /* Address+Shared.swift */; }; @@ -4419,6 +4420,7 @@ 2D09E0D42E65C9B9005C26F3 /* ApplicationPasswordsExperimentStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationPasswordsExperimentStateTests.swift; sourceTree = ""; }; 2D880B482DFB2F3D00A6FB2C /* OptionalBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalBinding.swift; sourceTree = ""; }; 2D88C1102DF883BD00A6FB2C /* AttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Helpers.swift"; sourceTree = ""; }; + 2DA63E032E69B6D200B0CB28 /* ApplicationPasswordsExperimentAvailabilityCheckerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationPasswordsExperimentAvailabilityCheckerTests.swift; sourceTree = ""; }; 2DB877512E25466B0001B175 /* ShippingItemRowAccessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingItemRowAccessibility.swift; sourceTree = ""; }; 2DB88DA32E27DD790001B175 /* MarkOrderAsReadUseCase+Woo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MarkOrderAsReadUseCase+Woo.swift"; sourceTree = ""; }; 2DB891652E27F07E0001B175 /* Address+Shared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Address+Shared.swift"; sourceTree = ""; }; @@ -11527,6 +11529,7 @@ BA143222273662DE00E4B3AB /* Settings */ = { isa = PBXGroup; children = ( + 2DA63E032E69B6D200B0CB28 /* ApplicationPasswordsExperimentAvailabilityCheckerTests.swift */, 2D09E0D42E65C9B9005C26F3 /* ApplicationPasswordsExperimentStateTests.swift */, 023BD5892BFDCF9500A10D7B /* POS */, BAFEF51D273C2151005F94CC /* SettingsViewModelTests.swift */, @@ -17327,6 +17330,7 @@ 0331A7002A334982001D2C2C /* MockInAppPurchasesForWPComPlansManager.swift in Sources */, 02DF174B2A4A134B008FD33B /* ProductFormActionsFactory+ProductCreationTests.swift in Sources */, 02564A88246C047C00D6DB2A /* Optional+StringTests.swift in Sources */, + 2DA63E042E69B6D400B0CB28 /* ApplicationPasswordsExperimentAvailabilityCheckerTests.swift in Sources */, 0269576D23726401001BA0BF /* KeyboardFrameObserverTests.swift in Sources */, 7E6A01A12725DEDE001668D5 /* FilterProductCategoryListViewModelTests.swift in Sources */, 02BF9BAF2851E7EA008CE2DD /* MockAppleIDCredentialChecker.swift in Sources */, diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Settings/ApplicationPasswordsExperimentAvailabilityCheckerTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Settings/ApplicationPasswordsExperimentAvailabilityCheckerTests.swift new file mode 100644 index 00000000000..e46879a0d7a --- /dev/null +++ b/WooCommerce/WooCommerceTests/ViewRelated/Settings/ApplicationPasswordsExperimentAvailabilityCheckerTests.swift @@ -0,0 +1,56 @@ +import XCTest +import Yosemite +@testable import WooCommerce + +final class ApplicationPasswordsExperimentAvailabilityCheckerTests: XCTestCase { + private var availabilityChecker: ApplicationPasswordsExperimentAvailabilityCheckerProtocol! + private var stores: StoresManager! + private var userDefaults: UserDefaults! + + override func tearDown() { + availabilityChecker = nil + stores = nil + userDefaults = nil + super.tearDown() + } + + private func setupEnvironment( + isWPComAuthenticated: Bool, + isRemoteFFEnabled: Bool + ) throws { + stores = MockStoresManager( + sessionManager: .makeForTesting( + authenticated: true, + isWPCom: isWPComAuthenticated + ) + ) + + userDefaults = try XCTUnwrap(UserDefaults(suiteName: "TestingSuite")) + userDefaults[.applicationPasswordsExperimentRemoteFFValue] = isRemoteFFEnabled + + availabilityChecker = ApplicationPasswordsExperimentAvailabilityChecker( + userDefaults: userDefaults, + stores: stores + ) + } + + func test_when_wpcom_authenticated_and_remote_ff_enabled_then_isAvailable_returns_true() throws { + try setupEnvironment(isWPComAuthenticated: true, isRemoteFFEnabled: true) + XCTAssertTrue(availabilityChecker.isAvailable) + } + + func test_when_wpcom_authenticated_and_remote_ff_disabled_then_isAvailable_returns_false() throws { + try setupEnvironment(isWPComAuthenticated: true, isRemoteFFEnabled: false) + XCTAssertFalse(availabilityChecker.isAvailable) + } + + func test_when_not_wpcom_authenticated_and_remote_ff_enabled_then_isAvailable_returns_false() throws { + try setupEnvironment(isWPComAuthenticated: false, isRemoteFFEnabled: true) + XCTAssertFalse(availabilityChecker.isAvailable) + } + + func test_when_not_wpcom_authenticated_and_remote_ff_disabled_then_isAvailable_returns_false() throws { + try setupEnvironment(isWPComAuthenticated: false, isRemoteFFEnabled: false) + XCTAssertFalse(availabilityChecker.isAvailable) + } +} diff --git a/WooCommerce/WooCommerceTests/ViewRelated/Settings/ApplicationPasswordsExperimentStateTests.swift b/WooCommerce/WooCommerceTests/ViewRelated/Settings/ApplicationPasswordsExperimentStateTests.swift index 7138f0a6d0e..79202d23308 100644 --- a/WooCommerce/WooCommerceTests/ViewRelated/Settings/ApplicationPasswordsExperimentStateTests.swift +++ b/WooCommerce/WooCommerceTests/ViewRelated/Settings/ApplicationPasswordsExperimentStateTests.swift @@ -89,7 +89,7 @@ final class ApplicationPasswordsExperimentStateTests: XCTestCase { private final class ApplicationPasswordsExperimentAvailabilityCheckerMock: ApplicationPasswordsExperimentAvailabilityCheckerProtocol { var mockedAvailability = false - var cachedValue: Bool { + var isAvailable: Bool { mockedAvailability }