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
2 changes: 0 additions & 2 deletions Modules/Sources/Experiments/DefaultFeatureFlagService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ public struct DefaultFeatureFlagService: FeatureFlagService {
return true
case .pointOfSaleHistoricalOrdersi1:
return buildConfig == .localDeveloper || buildConfig == .alpha
case .applicationPasswordExperiment:
return buildConfig == .localDeveloper || buildConfig == .alpha
case .pointOfSaleLocalCatalogi1:
return buildConfig == .localDeveloper || buildConfig == .alpha
default:
Expand Down
4 changes: 0 additions & 4 deletions Modules/Sources/Experiments/FeatureFlag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,6 @@ public enum FeatureFlag: Int {
///
case pointOfSaleHistoricalOrdersi1

/// Enables switching Jetpack requests to use application password
///
case applicationPasswordExperiment

/// Enables Local Catalog i1 in Point of Sale.
/// It syncs products and variations to local storage and display them in POS for quick access.
///
Expand Down
3 changes: 3 additions & 0 deletions Modules/Sources/Networking/Remote/FeatureFlagRemote.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public enum RemoteFeatureFlag: Decodable {
case storeCreationCompleteNotification
case hardcodedPlanUpgradeDetailsMilestone1AreAccurate
case pointOfSale
case appPasswordsForJetpackSites

init?(rawValue: String) {
switch rawValue {
Expand All @@ -39,6 +40,8 @@ public enum RemoteFeatureFlag: Decodable {
self = .hardcodedPlanUpgradeDetailsMilestone1AreAccurate
case "woo_pos":
self = .pointOfSale
case "woo_app_passwords_for_jetpack_sites":
self = .appPasswordsForJetpackSites
default:
return nil
}
Expand Down
1 change: 1 addition & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
-----
- [*] Order details: Display only physical items in the Shipping Labels section. [https://github.com/woocommerce/woocommerce-ios/pull/16127]
- [internal] Address deprecated view modifiers usage following iOS17 API updates [https://github.com/woocommerce/woocommerce-ios/pull/16080]
- [***] Performance improvements for users logging in with WordPress.com accounts [https://github.com/woocommerce/woocommerce-ios/pull/16126]
- [internal] Fix back swipe gesture detection compatibility for iOS26 [https://github.com/woocommerce/woocommerce-ios/pull/16133]
- [internal] POS Modularization: Removed direct ServiceLocator usage within POS by requiring complex Woo app target dependencies to be injected via POS dependency protocols, and moved reusable dependencies to WooFoundation and Yosemite [https://github.com/woocommerce/woocommerce-ios/pull/16132]
- [*] Workaround to make custom field decoding more reliable with sites which return incorrectly formatted meta_data for products, variations, and orders. [https://github.com/woocommerce/woocommerce-ios/pull/16141]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,19 +84,17 @@ final class ApplicationPasswordsExperimentAvailabilityChecker: ApplicationPasswo
}
}

@MainActor
func fetchAvailability() async -> Bool {
await withCheckedContinuation { continuation in
//TODO: - put the remote FF checking here
//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)
}

cachedRemoteFFValue = mockResultValue
let isEnabled = await withCheckedContinuation { continuation in
stores.dispatch(FeatureFlagAction.isRemoteFeatureFlagEnabled(
.appPasswordsForJetpackSites,
defaultValue: false
) { isEnabled in
continuation.resume(returning: isEnabled)
})
}
cachedRemoteFFValue = isEnabled
return isEnabled
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Yosemite

final class ApplicationPasswordsExperimentAvailabilityCheckerTests: XCTestCase {
private var availabilityChecker: ApplicationPasswordsExperimentAvailabilityCheckerProtocol!
private var stores: StoresManager!
private var stores: MockStoresManager!
private var userDefaults: UserDefaults!

override func tearDown() {
Expand All @@ -16,7 +16,7 @@ final class ApplicationPasswordsExperimentAvailabilityCheckerTests: XCTestCase {

private func setupEnvironment(
isWPComAuthenticated: Bool,
isRemoteFFEnabled: Bool
cachedRemoteFFEnabled: Bool
) throws {
stores = MockStoresManager(
sessionManager: .makeForTesting(
Expand All @@ -26,31 +26,93 @@ final class ApplicationPasswordsExperimentAvailabilityCheckerTests: XCTestCase {
)

userDefaults = try XCTUnwrap(UserDefaults(suiteName: "TestingSuite"))
userDefaults[.applicationPasswordsExperimentRemoteFFValue] = isRemoteFFEnabled
userDefaults[.applicationPasswordsExperimentRemoteFFValue] = cachedRemoteFFEnabled

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)
func test_when_wpcom_authenticated_and_cached_remote_ff_enabled_then_isAvailable_returns_true() throws {
try setupEnvironment(isWPComAuthenticated: true, cachedRemoteFFEnabled: true)
XCTAssertTrue(availabilityChecker.isAvailable)
}

func test_when_wpcom_authenticated_and_remote_ff_disabled_then_isAvailable_returns_false() throws {
try setupEnvironment(isWPComAuthenticated: true, isRemoteFFEnabled: false)
func test_when_wpcom_authenticated_and_cached_remote_ff_disabled_then_isAvailable_returns_false() throws {
try setupEnvironment(isWPComAuthenticated: true, cachedRemoteFFEnabled: 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)
func test_when_not_wpcom_authenticated_and_cached_remote_ff_enabled_then_isAvailable_returns_false() throws {
try setupEnvironment(isWPComAuthenticated: false, cachedRemoteFFEnabled: 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)
func test_when_not_wpcom_authenticated_and_cached_remote_ff_disabled_then_isAvailable_returns_false() throws {
try setupEnvironment(isWPComAuthenticated: false, cachedRemoteFFEnabled: false)
XCTAssertFalse(availabilityChecker.isAvailable)
}

@MainActor
func test_when_cached_flag_is_disabled_and_remote_flag_is_enabled_then_fetchAvailability_returns_true() async throws {
// Given
stores = MockStoresManager(
sessionManager: .makeForTesting(
authenticated: true,
isWPCom: true
)
)
stores.whenReceivingAction(ofType: FeatureFlagAction.self) { action in
switch action {
case .isRemoteFeatureFlagEnabled(_, _, let completion):
completion(true)
}
}

userDefaults = try XCTUnwrap(UserDefaults(suiteName: UUID().uuidString))
userDefaults[.applicationPasswordsExperimentRemoteFFValue] = false

availabilityChecker = ApplicationPasswordsExperimentAvailabilityChecker(
userDefaults: userDefaults,
stores: stores
)

// When
let availability = await availabilityChecker.fetchAvailability()

// Then
XCTAssertTrue(availability)
}

@MainActor
func test_when_cached_flag_is_enabled_and_remote_flag_is_disabled_then_fetchAvailability_returns_false() async throws {
// Given
stores = MockStoresManager(
sessionManager: .makeForTesting(
authenticated: true,
isWPCom: true
)
)
stores.whenReceivingAction(ofType: FeatureFlagAction.self) { action in
switch action {
case .isRemoteFeatureFlagEnabled(_, _, let completion):
completion(false)
}
}

userDefaults = try XCTUnwrap(UserDefaults(suiteName: UUID().uuidString))
userDefaults[.applicationPasswordsExperimentRemoteFFValue] = true

availabilityChecker = ApplicationPasswordsExperimentAvailabilityChecker(
userDefaults: userDefaults,
stores: stores
)

// When
let availability = await availabilityChecker.fetchAvailability()

// Then
XCTAssertFalse(availability)
}
}