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
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
)
Comment on lines +69 to +72
Copy link
Contributor Author

@RafaelKayumov RafaelKayumov Sep 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@itsmeichigo I'm gonna re-create this PR and target the beta. Otherwise the feature toggle will be visible to users. There is no remote FF yet integrated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point - I missed that. You can merge this PR and create a PR targeting beta with only the replacement of the mock result for simplicity. When merging back to trunk, the change will not cause any conflict because it's identical with trunk.


DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
continuation.resume(returning: mockResultValue)
}

cachedValue = mockResultValue
cachedRemoteFFValue = mockResultValue
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ private extension BetaFeaturesConfigurationViewModel {
case .viewAddOns:
return true
case .applicationPasswords:
return appPasswordsExperimentAvailabilityChecker.cachedValue
return appPasswordsExperimentAvailabilityChecker.isAvailable
}
}

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 @@ -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 */; };
Expand Down Expand Up @@ -4419,6 +4420,7 @@
2D09E0D42E65C9B9005C26F3 /* ApplicationPasswordsExperimentStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationPasswordsExperimentStateTests.swift; sourceTree = "<group>"; };
2D880B482DFB2F3D00A6FB2C /* OptionalBinding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalBinding.swift; sourceTree = "<group>"; };
2D88C1102DF883BD00A6FB2C /* AttributedString+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+Helpers.swift"; sourceTree = "<group>"; };
2DA63E032E69B6D200B0CB28 /* ApplicationPasswordsExperimentAvailabilityCheckerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationPasswordsExperimentAvailabilityCheckerTests.swift; sourceTree = "<group>"; };
2DB877512E25466B0001B175 /* ShippingItemRowAccessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShippingItemRowAccessibility.swift; sourceTree = "<group>"; };
2DB88DA32E27DD790001B175 /* MarkOrderAsReadUseCase+Woo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MarkOrderAsReadUseCase+Woo.swift"; sourceTree = "<group>"; };
2DB891652E27F07E0001B175 /* Address+Shared.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Address+Shared.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -11527,6 +11529,7 @@
BA143222273662DE00E4B3AB /* Settings */ = {
isa = PBXGroup;
children = (
2DA63E032E69B6D200B0CB28 /* ApplicationPasswordsExperimentAvailabilityCheckerTests.swift */,
2D09E0D42E65C9B9005C26F3 /* ApplicationPasswordsExperimentStateTests.swift */,
023BD5892BFDCF9500A10D7B /* POS */,
BAFEF51D273C2151005F94CC /* SettingsViewModelTests.swift */,
Expand Down Expand Up @@ -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 */,
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ final class ApplicationPasswordsExperimentStateTests: XCTestCase {
private final class ApplicationPasswordsExperimentAvailabilityCheckerMock: ApplicationPasswordsExperimentAvailabilityCheckerProtocol {
var mockedAvailability = false

var cachedValue: Bool {
var isAvailable: Bool {
mockedAvailability
}

Expand Down
Loading