diff --git a/Core/FeatureFlag.swift b/Core/FeatureFlag.swift index 69269aa99c..c31da129d1 100644 --- a/Core/FeatureFlag.swift +++ b/Core/FeatureFlag.swift @@ -28,6 +28,7 @@ public enum FeatureFlag: String { case autofillInlineIconCredentials case autofillAccessCredentialManagement case autofillPasswordGeneration + case autofillOnByDefault case incontextSignup case appTrackingProtection case networkProtection @@ -48,6 +49,8 @@ extension FeatureFlag: FeatureFlagSourceProviding { return .remoteReleasable(.subfeature(AutofillSubfeature.accessCredentialManagement)) case .autofillPasswordGeneration: return .remoteReleasable(.subfeature(AutofillSubfeature.autofillPasswordGeneration)) + case .autofillOnByDefault: + return .remoteReleasable(.subfeature(AutofillSubfeature.onByDefault)) case .incontextSignup: return .remoteReleasable(.feature(.incontextSignup)) } diff --git a/Core/Pixel.swift b/Core/Pixel.swift index 5c24bee78b..d358707618 100644 --- a/Core/Pixel.swift +++ b/Core/Pixel.swift @@ -126,6 +126,8 @@ public struct PixelParameters { public static let returnUserErrorCode = "error_code" public static let returnUserOldATB = "old_atb" public static let returnUserNewATB = "new_atb" + + public static let autofillDefaultState = "default_state" } public struct PixelValues { diff --git a/DuckDuckGo/AppDelegate.swift b/DuckDuckGo/AppDelegate.swift index c41c64d7ce..604b6db7f2 100644 --- a/DuckDuckGo/AppDelegate.swift +++ b/DuckDuckGo/AppDelegate.swift @@ -240,6 +240,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ThemeManager.shared.updateUserInterfaceStyle(window: window) appIsLaunching = true + + // Temporary logic for rollout of Autofill as on by default for new installs only + if AppDependencyProvider.shared.appSettings.autofillIsNewInstallForOnByDefault == nil { + AppDependencyProvider.shared.appSettings.setAutofillIsNewInstallForOnByDefault() + } + return true } diff --git a/DuckDuckGo/AppSettings.swift b/DuckDuckGo/AppSettings.swift index 6e9a72c829..d79c06e746 100644 --- a/DuckDuckGo/AppSettings.swift +++ b/DuckDuckGo/AppSettings.swift @@ -37,6 +37,8 @@ protocol AppSettings: AnyObject { var autofillCredentialsEnabled: Bool { get set } var autofillCredentialsSavePromptShowAtLeastOnce: Bool { get set } var autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary: Bool { get set } + var autofillIsNewInstallForOnByDefault: Bool? { get set } + func setAutofillIsNewInstallForOnByDefault() var voiceSearchEnabled: Bool { get set } diff --git a/DuckDuckGo/AppUserDefaults.swift b/DuckDuckGo/AppUserDefaults.swift index cdc13cbb36..0a7d98d880 100644 --- a/DuckDuckGo/AppUserDefaults.swift +++ b/DuckDuckGo/AppUserDefaults.swift @@ -60,6 +60,7 @@ public class AppUserDefaults: AppSettings { static let currentFireButtonAnimationKey = "com.duckduckgo.app.currentFireButtonAnimationKey" static let autofillCredentialsEnabled = "com.duckduckgo.ios.autofillCredentialsEnabled" + static let autofillIsNewInstallForOnByDefault = "com.duckduckgo.ios.autofillIsNewInstallForOnByDefault" } private struct DebugKeys { @@ -70,6 +71,8 @@ public class AppUserDefaults: AppSettings { return UserDefaults(suiteName: groupName) } + lazy var featureFlagger = AppDependencyProvider.shared.featureFlagger + init(groupName: String = "group.com.duckduckgo.app") { self.groupName = groupName } @@ -182,16 +185,22 @@ public class AppUserDefaults: AppSettings { return } if !autofillCredentialsSavePromptShowAtLeastOnce { - autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary = true - autofillCredentialsEnabled = true + if let isNewInstall = autofillIsNewInstallForOnByDefault, + isNewInstall, + featureFlagger.isFeatureOn(.autofillOnByDefault) { + autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary = true + autofillCredentialsEnabled = true + } } } var autofillCredentialsEnabled: Bool { get { - // In future, we'll use setAutofillCredentialsEnabledAutomaticallyIfNecessary() here to automatically turn on autofill for people - // That haven't seen the save prompt before. - // For now, whilst internal testing is still happening, it's still set to default to be enabled + // setAutofillCredentialsEnabledAutomaticallyIfNecessary() used here to automatically turn on autofill for people if: + // 1. They haven't seen the save prompt before + // 2. They are a new install + // 3. The feature flag is enabled + setAutofillCredentialsEnabledAutomaticallyIfNecessary() return userDefaults?.object(forKey: Keys.autofillCredentialsEnabled) as? Bool ?? false } @@ -205,7 +214,20 @@ public class AppUserDefaults: AppSettings { @UserDefaultsWrapper(key: .autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary, defaultValue: false) var autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary: Bool - + + var autofillIsNewInstallForOnByDefault: Bool? { + get { + return userDefaults?.object(forKey: Keys.autofillIsNewInstallForOnByDefault) as? Bool + } + set { + userDefaults?.set(newValue, forKey: Keys.autofillIsNewInstallForOnByDefault) + } + } + + func setAutofillIsNewInstallForOnByDefault() { + autofillIsNewInstallForOnByDefault = StatisticsUserDefaults().installDate == nil + } + @UserDefaultsWrapper(key: .voiceSearchEnabled, defaultValue: false) var voiceSearchEnabled: Bool diff --git a/DuckDuckGo/AutofillLoginPromptViewController.swift b/DuckDuckGo/AutofillLoginPromptViewController.swift index 1133e169d2..5b00fedf7c 100644 --- a/DuckDuckGo/AutofillLoginPromptViewController.swift +++ b/DuckDuckGo/AutofillLoginPromptViewController.swift @@ -69,9 +69,11 @@ class AutofillLoginPromptViewController: UIViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if trigger == AutofillUserScript.GetTriggerType.autoprompt { - Pixel.fire(pixel: .autofillLoginsFillLoginInlineAutopromptDisplayed) + Pixel.fire(pixel: .autofillLoginsFillLoginInlineAutopromptDisplayed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } else { - Pixel.fire(pixel: .autofillLoginsFillLoginInlineManualDisplayed) + Pixel.fire(pixel: .autofillLoginsFillLoginInlineManualDisplayed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } } @@ -95,9 +97,11 @@ class AutofillLoginPromptViewController: UIViewController { extension AutofillLoginPromptViewController: UISheetPresentationControllerDelegate { func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { if self.trigger == AutofillUserScript.GetTriggerType.autoprompt { - Pixel.fire(pixel: .autofillLoginsAutopromptDismissed) + Pixel.fire(pixel: .autofillLoginsAutopromptDismissed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } else { - Pixel.fire(pixel: .autofillLoginsFillLoginInlineManualDismissed) + Pixel.fire(pixel: .autofillLoginsFillLoginInlineManualDismissed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } completion?(nil, false) } @@ -107,9 +111,11 @@ extension AutofillLoginPromptViewController: AutofillLoginPromptViewModelDelegat func autofillLoginPromptViewModel(_ viewModel: AutofillLoginPromptViewModel, didSelectAccount account: SecureVaultModels.WebsiteAccount) { if trigger == AutofillUserScript.GetTriggerType.autoprompt { - Pixel.fire(pixel: .autofillLoginsFillLoginInlineAutopromptConfirmed) + Pixel.fire(pixel: .autofillLoginsFillLoginInlineAutopromptConfirmed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } else { - Pixel.fire(pixel: .autofillLoginsFillLoginInlineManualConfirmed) + Pixel.fire(pixel: .autofillLoginsFillLoginInlineManualConfirmed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } if AppDependencyProvider.shared.autofillLoginSession.isValidSession { @@ -163,9 +169,11 @@ extension AutofillLoginPromptViewController: AutofillLoginPromptViewModelDelegat func autofillLoginPromptViewModelDidCancel(_ viewModel: AutofillLoginPromptViewModel) { dismiss(animated: true) { if self.trigger == AutofillUserScript.GetTriggerType.autoprompt { - Pixel.fire(pixel: .autofillLoginsAutopromptDismissed) + Pixel.fire(pixel: .autofillLoginsAutopromptDismissed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } else { - Pixel.fire(pixel: .autofillLoginsFillLoginInlineManualDismissed) + Pixel.fire(pixel: .autofillLoginsFillLoginInlineManualDismissed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } self.completion?(nil, false) diff --git a/DuckDuckGo/AutofillLoginSettingsListViewController.swift b/DuckDuckGo/AutofillLoginSettingsListViewController.swift index 4775f934cb..2055e7b03f 100644 --- a/DuckDuckGo/AutofillLoginSettingsListViewController.swift +++ b/DuckDuckGo/AutofillLoginSettingsListViewController.swift @@ -658,9 +658,11 @@ extension AutofillLoginSettingsListViewController: AutofillLoginDetailsViewContr extension AutofillLoginSettingsListViewController: EnableAutofillSettingsTableViewCellDelegate { func enableAutofillSettingsTableViewCell(_ cell: EnableAutofillSettingsTableViewCell, didChangeSettings value: Bool) { if value { - Pixel.fire(pixel: .autofillLoginsSettingsEnabled) + Pixel.fire(pixel: .autofillLoginsSettingsEnabled, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } else { - Pixel.fire(pixel: .autofillLoginsSettingsDisabled) + Pixel.fire(pixel: .autofillLoginsSettingsDisabled, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } viewModel.isAutofillEnabledInSettings = value diff --git a/DuckDuckGo/AutofillSettingStatus.swift b/DuckDuckGo/AutofillSettingStatus.swift index 4e7ed3f789..ccbabfd07c 100644 --- a/DuckDuckGo/AutofillSettingStatus.swift +++ b/DuckDuckGo/AutofillSettingStatus.swift @@ -30,4 +30,8 @@ struct AutofillSettingStatus { let canAuthenticate = context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) return appSettings.autofillCredentialsEnabled && canAuthenticate } + + static var defaultState: String { + return appSettings.autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary ? "on" : "off" + } } diff --git a/DuckDuckGo/PasswordGenerationPromptViewController.swift b/DuckDuckGo/PasswordGenerationPromptViewController.swift index 4ac1c56edb..e0e015466b 100644 --- a/DuckDuckGo/PasswordGenerationPromptViewController.swift +++ b/DuckDuckGo/PasswordGenerationPromptViewController.swift @@ -49,7 +49,8 @@ class PasswordGenerationPromptViewController: UIViewController { setupPasswordGenerationPromptView() - Pixel.fire(pixel: .autofillLoginsPasswordGenerationPromptDisplayed) + Pixel.fire(pixel: .autofillLoginsPasswordGenerationPromptDisplayed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } private func setupPasswordGenerationPromptView() { @@ -67,7 +68,8 @@ class PasswordGenerationPromptViewController: UIViewController { extension PasswordGenerationPromptViewController: UISheetPresentationControllerDelegate { func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { - Pixel.fire(pixel: .autofillLoginsPasswordGenerationPromptDismissed) + Pixel.fire(pixel: .autofillLoginsPasswordGenerationPromptDismissed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) self.completion?(false) } @@ -75,7 +77,8 @@ extension PasswordGenerationPromptViewController: UISheetPresentationControllerD extension PasswordGenerationPromptViewController: PasswordGenerationPromptViewModelDelegate { func passwordGenerationPromptViewModelDidSelect(_ viewModel: PasswordGenerationPromptViewModel) { - Pixel.fire(pixel: .autofillLoginsPasswordGenerationPromptConfirmed) + Pixel.fire(pixel: .autofillLoginsPasswordGenerationPromptConfirmed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) dismiss(animated: true) { self.completion?(true) @@ -83,7 +86,8 @@ extension PasswordGenerationPromptViewController: PasswordGenerationPromptViewMo } func passwordGenerationPromptViewModelDidCancel(_ viewModel: PasswordGenerationPromptViewModel) { - Pixel.fire(pixel: .autofillLoginsPasswordGenerationPromptDismissed) + Pixel.fire(pixel: .autofillLoginsPasswordGenerationPromptDismissed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) dismiss(animated: true) { self.completion?(false) diff --git a/DuckDuckGo/SaveLoginViewController.swift b/DuckDuckGo/SaveLoginViewController.swift index fbd144e98b..82d0afec9e 100644 --- a/DuckDuckGo/SaveLoginViewController.swift +++ b/DuckDuckGo/SaveLoginViewController.swift @@ -70,12 +70,12 @@ class SaveLoginViewController: UIViewController { return } switch viewModel.layoutType { - case .newUser: - Pixel.fire(pixel: .autofillLoginsSaveLoginModalDismissed) - case .saveLogin: - Pixel.fire(pixel: .autofillLoginsSaveLoginModalDismissed) + case .newUser, .saveLogin: + Pixel.fire(pixel: .autofillLoginsSaveLoginModalDismissed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) case .savePassword: - Pixel.fire(pixel: .autofillLoginsSavePasswordModalDismissed) + Pixel.fire(pixel: .autofillLoginsSavePasswordModalDismissed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) case .updateUsername: Pixel.fire(pixel: .autofillLoginsUpdateUsernameModalDismissed) case .updatePassword: @@ -96,12 +96,12 @@ class SaveLoginViewController: UIViewController { installChildViewController(controller) switch saveViewModel.layoutType { - case .newUser: - Pixel.fire(pixel: .autofillLoginsSaveLoginModalDisplayed) - case .saveLogin: - Pixel.fire(pixel: .autofillLoginsSaveLoginModalDisplayed) + case .newUser, .saveLogin: + Pixel.fire(pixel: .autofillLoginsSaveLoginModalDisplayed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) case .savePassword: - Pixel.fire(pixel: .autofillLoginsSavePasswordModalDisplayed) + Pixel.fire(pixel: .autofillLoginsSavePasswordModalDisplayed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) case .updateUsername: Pixel.fire(pixel: .autofillLoginsUpdateUsernameModalDisplayed) case .updatePassword: @@ -115,9 +115,11 @@ extension SaveLoginViewController: SaveLoginViewModelDelegate { switch viewModel.layoutType { case .saveLogin, .savePassword, .newUser: if viewModel.layoutType == .savePassword { - Pixel.fire(pixel: .autofillLoginsSavePasswordModalConfirmed) + Pixel.fire(pixel: .autofillLoginsSavePasswordModalConfirmed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } else { - Pixel.fire(pixel: .autofillLoginsSaveLoginModalConfirmed) + Pixel.fire(pixel: .autofillLoginsSaveLoginModalConfirmed, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) } delegate?.saveLoginViewController(self, didSaveCredentials: credentialManager.credentials) case .updatePassword, .updateUsername: @@ -144,7 +146,8 @@ extension SaveLoginViewController: SaveLoginViewModelDelegate { alertController.overrideUserInterfaceStyle() let disableAction = UIAlertAction(title: UserText.autofillKeepEnabledAlertDisableAction, style: .cancel) { _ in - Pixel.fire(pixel: .autofillLoginsFillLoginInlineDisablePromptAutofillDisabled) + Pixel.fire(pixel: .autofillLoginsFillLoginInlineDisablePromptAutofillDisabled, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) if isSelfPresentingAlert { self.delegate?.saveLoginViewControllerDidCancel(self) } @@ -152,7 +155,8 @@ extension SaveLoginViewController: SaveLoginViewModelDelegate { } let keepUsingAction = UIAlertAction(title: UserText.autofillKeepEnabledAlertKeepUsingAction, style: .default) { _ in - Pixel.fire(pixel: .autofillLoginsFillLoginInlineDisablePromptAutofillKept) + Pixel.fire(pixel: .autofillLoginsFillLoginInlineDisablePromptAutofillKept, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) if isSelfPresentingAlert { self.delegate?.saveLoginViewControllerDidCancel(self) } @@ -166,7 +170,8 @@ extension SaveLoginViewController: SaveLoginViewModelDelegate { if isAlreadyDismissed { delegate?.saveLoginViewController(self, didRequestPresentConfirmKeepUsingAlertController: alertController) } else { - Pixel.fire(pixel: .autofillLoginsFillLoginInlineDisablePromptShown) + Pixel.fire(pixel: .autofillLoginsFillLoginInlineDisablePromptShown, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) present(alertController, animated: true) } } diff --git a/DuckDuckGo/SettingsViewController.swift b/DuckDuckGo/SettingsViewController.swift index 45b66e7870..2cc139c0a9 100644 --- a/DuckDuckGo/SettingsViewController.swift +++ b/DuckDuckGo/SettingsViewController.swift @@ -365,7 +365,8 @@ class SettingsViewController: UITableViewController { syncDataProviders: syncDataProviders ) autofillController.delegate = self - Pixel.fire(pixel: .autofillSettingsOpened) + Pixel.fire(pixel: .autofillSettingsOpened, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) navigationController?.pushViewController(autofillController, animated: animated) } diff --git a/DuckDuckGo/TabViewController.swift b/DuckDuckGo/TabViewController.swift index b3535ccca6..d6b4c667bd 100644 --- a/DuckDuckGo/TabViewController.swift +++ b/DuckDuckGo/TabViewController.swift @@ -2496,7 +2496,8 @@ extension TabViewController: SaveLoginViewControllerDelegate { func saveLoginViewController(_ viewController: SaveLoginViewController, didRequestPresentConfirmKeepUsingAlertController alertController: UIAlertController) { - Pixel.fire(pixel: .autofillLoginsFillLoginInlineDisablePromptShown) + Pixel.fire(pixel: .autofillLoginsFillLoginInlineDisablePromptShown, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) present(alertController, animated: true) } } diff --git a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift index a9afab2d89..3018d66275 100644 --- a/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift +++ b/DuckDuckGo/TabViewControllerBrowsingMenuExtension.swift @@ -359,7 +359,8 @@ extension TabViewController { } private func onOpenAutofillLoginsAction() { - Pixel.fire(pixel: .browsingMenuAutofill) + Pixel.fire(pixel: .browsingMenuAutofill, + withAdditionalParameters: [PixelParameters.autofillDefaultState: AutofillSettingStatus.defaultState]) delegate?.tabDidRequestAutofillLogins(tab: self) } diff --git a/DuckDuckGoTests/AppSettingsMock.swift b/DuckDuckGoTests/AppSettingsMock.swift index 53f099d6b8..a31dd2a1e1 100644 --- a/DuckDuckGoTests/AppSettingsMock.swift +++ b/DuckDuckGoTests/AppSettingsMock.swift @@ -27,6 +27,10 @@ class AppSettingsMock: AppSettings { var autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary: Bool = false + var autofillIsNewInstallForOnByDefault: Bool? + + func setAutofillIsNewInstallForOnByDefault() { } + var autocomplete: Bool = true var currentThemeName: DuckDuckGo.ThemeName = .systemDefault diff --git a/DuckDuckGoTests/AppUserDefaultsTests.swift b/DuckDuckGoTests/AppUserDefaultsTests.swift index d1eb24c056..89d6e4703f 100644 --- a/DuckDuckGoTests/AppUserDefaultsTests.swift +++ b/DuckDuckGoTests/AppUserDefaultsTests.swift @@ -19,14 +19,22 @@ import XCTest @testable import DuckDuckGo +import BrowserServicesKit class AppUserDefaultsTests: XCTestCase { let testGroupName = "test" + var internalUserDeciderStore: MockInternalUserStoring! override func setUp() { super.setUp() UserDefaults(suiteName: testGroupName)?.removePersistentDomain(forName: testGroupName) + internalUserDeciderStore = MockInternalUserStoring() + } + + override func tearDown() { + internalUserDeciderStore = nil + super.tearDown() } func testWhenLinkPreviewsIsSetThenItIsPersisted() { @@ -93,17 +101,46 @@ class AppUserDefaultsTests: XCTestCase { let appUserDefaults = AppUserDefaults(groupName: testGroupName) XCTAssertFalse(appUserDefaults.autofillCredentialsEnabled) } - - /* - These tests aren't required until we make autofill default to off, and then enable turning it on automatically - func testWhenAutofillCredentialsIsDisabledAndHasNotBeenTurnedOnAutomaticallyBeforeThenAutofillCredentialsEnabled() { + + func testWhenAutofillCredentialsIsDisabledAndHasNotBeenTurnedOnAutomaticallyBeforeWhenSavePromptShownThenDefaultAutofillStateIsFalse() { let appUserDefaults = AppUserDefaults(groupName: testGroupName) - appUserDefaults.autofillCredentialsEnabled = false + appUserDefaults.autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary = false + appUserDefaults.autofillCredentialsSavePromptShowAtLeastOnce = true + + XCTAssertFalse(appUserDefaults.autofillCredentialsEnabled) + } + + func testWhenAutofillCredentialsIsDisabledAndHasNotBeenTurnedOnAutomaticallyBeforeAndPromptHasNotBeenSeenAndIsNotNewInstallThenDefaultAutofillStateIsFalse() { + let appUserDefaults = AppUserDefaults(groupName: testGroupName) + appUserDefaults.autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary = false appUserDefaults.autofillCredentialsSavePromptShowAtLeastOnce = false + appUserDefaults.autofillIsNewInstallForOnByDefault = false + + XCTAssertFalse(appUserDefaults.autofillCredentialsEnabled) + } + + func testWhenAutofillCredentialsIsDisabledAndHasNotBeenTurnedOnAutomaticallyBeforeAndPromptHasNotBeenSeenAndIsNewInstallAndFeatureFlagDisabledThenDefaultAutofillStateIsFalse() { + let appUserDefaults = AppUserDefaults(groupName: testGroupName) appUserDefaults.autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary = false - XCTAssertEqual(appUserDefaults.autofillCredentialsEnabled, true) + appUserDefaults.autofillCredentialsSavePromptShowAtLeastOnce = false + appUserDefaults.autofillIsNewInstallForOnByDefault = true + let featureFlagger = createFeatureFlagger(withSubfeatureEnabled: false) + appUserDefaults.featureFlagger = featureFlagger + + XCTAssertFalse(appUserDefaults.autofillCredentialsEnabled) } - + + func testWhenAutofillCredentialsIsDisabledAndHasNotBeenTurnedOnAutomaticallyBeforeAndPromptHasNotBeenSeenAndIsNewInstallAndFeatureFlagEnabledThenDefaultAutofillStateIsTrue() { + let appUserDefaults = AppUserDefaults(groupName: testGroupName) + appUserDefaults.autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary = false + appUserDefaults.autofillCredentialsSavePromptShowAtLeastOnce = false + appUserDefaults.autofillIsNewInstallForOnByDefault = true + let featureFlagger = createFeatureFlagger(withSubfeatureEnabled: true) + appUserDefaults.featureFlagger = featureFlagger + + XCTAssertTrue(appUserDefaults.autofillCredentialsEnabled) + } + func testWhenAutofillCredentialsIsDisabledAndHasNotBeenTurnedOnAutomaticallyBeforeAndPromptHasBeenSeenThenAutofillCredentialsStaysDisabled() { let appUserDefaults = AppUserDefaults(groupName: testGroupName) appUserDefaults.autofillCredentialsEnabled = false @@ -119,6 +156,25 @@ class AppUserDefaultsTests: XCTestCase { appUserDefaults.autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary = true XCTAssertEqual(appUserDefaults.autofillCredentialsEnabled, false) } - */ + + + // MARK: - Mock Creation + + private func createFeatureFlagger(withSubfeatureEnabled enabled: Bool) -> DefaultFeatureFlagger { + let mockManager = MockPrivacyConfigurationManager() + mockManager.privacyConfig = mockConfiguration(subfeatureEnabled: enabled) + + let internalUserDecider = DefaultInternalUserDecider(store: internalUserDeciderStore) + return DefaultFeatureFlagger(internalUserDecider: internalUserDecider, privacyConfig: mockManager.privacyConfig) + } + + private func mockConfiguration(subfeatureEnabled: Bool) -> PrivacyConfiguration { + let mockPrivacyConfiguration = MockPrivacyConfiguration() + mockPrivacyConfiguration.isSubfeatureKeyEnabled = { _, _ in + return subfeatureEnabled + } + + return mockPrivacyConfiguration + } }