diff --git a/app/src/main/java/com/x8bit/bitwarden/data/autofill/di/AutofillModule.kt b/app/src/main/java/com/x8bit/bitwarden/data/autofill/di/AutofillModule.kt index 5c9b9db0e4..09b7b9e839 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/autofill/di/AutofillModule.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/autofill/di/AutofillModule.kt @@ -57,6 +57,7 @@ object AutofillModule { authRepository: AuthRepository, clipboardManager: BitwardenClipboardManager, dispatcherManager: DispatcherManager, + settingsRepository: SettingsRepository, vaultRepository: VaultRepository, ): AutofillCompletionManager = AutofillCompletionManagerImpl( @@ -64,6 +65,7 @@ object AutofillModule { autofillParser = autofillParser, clipboardManager = clipboardManager, dispatcherManager = dispatcherManager, + settingsRepository = settingsRepository, vaultRepository = vaultRepository, ) diff --git a/app/src/main/java/com/x8bit/bitwarden/data/autofill/manager/AutofillCompletionManagerImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/autofill/manager/AutofillCompletionManagerImpl.kt index b3f33c662e..bb0265a0b3 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/autofill/manager/AutofillCompletionManagerImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/autofill/manager/AutofillCompletionManagerImpl.kt @@ -18,6 +18,7 @@ import com.x8bit.bitwarden.data.autofill.util.toAutofillAppInfo import com.x8bit.bitwarden.data.autofill.util.toAutofillCipherProvider import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager +import com.x8bit.bitwarden.data.platform.repository.SettingsRepository import com.x8bit.bitwarden.data.vault.repository.VaultRepository import com.x8bit.bitwarden.data.vault.repository.model.GenerateTotpResult import kotlinx.coroutines.CoroutineScope @@ -26,6 +27,7 @@ import kotlinx.coroutines.launch /** * Primary implementation of [AutofillCompletionManager]. */ +@Suppress("LongParameterList") class AutofillCompletionManagerImpl( private val authRepository: AuthRepository, private val autofillParser: AutofillParser, @@ -33,6 +35,7 @@ class AutofillCompletionManagerImpl( private val dispatcherManager: DispatcherManager, private val filledDataBuilderProvider: (CipherView) -> FilledDataBuilder = { createSingleItemFilledDataBuilder(cipherView = it) }, + private val settingsRepository: SettingsRepository, private val vaultRepository: VaultRepository, ) : AutofillCompletionManager { private val mainScope = CoroutineScope(dispatcherManager.main) @@ -97,9 +100,9 @@ class AutofillCompletionManagerImpl( ) { val isPremium = authRepository.userStateFlow.value?.activeAccount?.isPremium == true val totpCode = cipherView.login?.totp + val isTotpDisabled = settingsRepository.isAutoCopyTotpDisabled - // TODO check global TOTP enabled status BIT-1093 - if (isPremium && totpCode != null) { + if (!isTotpDisabled && isPremium && totpCode != null) { val totpResult = vaultRepository.generateTotp( time = DateTime.now(), totpCode = totpCode, diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt index 1d39779c58..25def43dee 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSource.kt @@ -81,6 +81,20 @@ interface SettingsDiskSource { value: Boolean?, ) + /** + * Retrieves the preference indicating whether the TOTP code should be automatically copied to + * the clipboard for autofill suggestions associated with the specified [userId]. + */ + fun getAutoCopyTotpDisabled(userId: String): Boolean? + + /** + * Stores the given [isAutomaticallyCopyTotpDisabled] for the given [userId]. + */ + fun storeAutoCopyTotpDisabled( + userId: String, + isAutomaticallyCopyTotpDisabled: Boolean?, + ) + /** * Gets the last time the app synced the vault data for a given [userId] (or `null` if the * vault has never been synced). diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt index ef2accb658..b34b4d81f6 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceImpl.kt @@ -24,6 +24,7 @@ private const val VAULT_LAST_SYNC_TIME = "$BASE_KEY:vaultLastSyncTime" private const val VAULT_TIMEOUT_ACTION_KEY = "$BASE_KEY:vaultTimeoutAction" private const val VAULT_TIME_IN_MINUTES_KEY = "$BASE_KEY:vaultTimeout" private const val DEFAULT_URI_MATCH_TYPE_KEY = "$BASE_KEY:defaultUriMatch" +private const val DISABLE_AUTO_TOTP_COPY_KEY = "$BASE_KEY:disableAutoTotpCopy" private const val DISABLE_AUTOFILL_SAVE_PROMPT_KEY = "$BASE_KEY:autofillDisableSavePrompt" private const val DISABLE_ICON_LOADING_KEY = "$BASE_KEY:disableFavicon" private const val APPROVE_PASSWORDLESS_LOGINS_KEY = "$BASE_KEY:approvePasswordlessLogins" @@ -137,6 +138,7 @@ class SettingsDiskSourceImpl( storeVaultTimeoutInMinutes(userId = userId, vaultTimeoutInMinutes = null) storeVaultTimeoutAction(userId = userId, vaultTimeoutAction = null) storeDefaultUriMatchType(userId = userId, uriMatchType = null) + storeAutoCopyTotpDisabled(userId = userId, isAutomaticallyCopyTotpDisabled = null) storeAutofillSavePromptDisabled(userId = userId, isAutofillSavePromptDisabled = null) storePullToRefreshEnabled(userId = userId, isPullToRefreshEnabled = null) storeInlineAutofillEnabled(userId = userId, isInlineAutofillEnabled = null) @@ -170,6 +172,19 @@ class SettingsDiskSourceImpl( ) } + override fun getAutoCopyTotpDisabled(userId: String): Boolean? = + getBoolean(key = "${DISABLE_AUTO_TOTP_COPY_KEY}_$userId") + + override fun storeAutoCopyTotpDisabled( + userId: String, + isAutomaticallyCopyTotpDisabled: Boolean?, + ) { + putBoolean( + key = "${DISABLE_AUTO_TOTP_COPY_KEY}_$userId", + value = isAutomaticallyCopyTotpDisabled, + ) + } + override fun getLastSyncTime(userId: String): Instant? = getLong(key = "${VAULT_LAST_SYNC_TIME}_$userId")?.let { Instant.ofEpochMilli(it) } diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt index 516bc26ead..7522de7f48 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepository.kt @@ -103,6 +103,11 @@ interface SettingsRepository { */ var isInlineAutofillEnabled: Boolean + /** + * Whether or not the auto copying totp when autofilling is disabled for the current user. + */ + var isAutoCopyTotpDisabled: Boolean + /** * Whether or not the autofill save prompt is disabled for the current user. */ diff --git a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt index 896ec1cfbe..2b90ed7d7e 100644 --- a/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt +++ b/app/src/main/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryImpl.kt @@ -201,6 +201,18 @@ class SettingsRepositoryImpl( ) } + override var isAutoCopyTotpDisabled: Boolean + get() = activeUserId + ?.let { settingsDiskSource.getAutoCopyTotpDisabled(userId = it) } + ?: false + set(value) { + val userId = activeUserId ?: return + settingsDiskSource.storeAutoCopyTotpDisabled( + userId = userId, + isAutomaticallyCopyTotpDisabled = value, + ) + } + override var isAutofillSavePromptDisabled: Boolean get() = activeUserId ?.let { settingsDiskSource.getAutofillSavePromptDisabled(userId = it) } diff --git a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/autofill/AutoFillViewModel.kt b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/autofill/AutoFillViewModel.kt index a81c30313b..de51e6f7b5 100644 --- a/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/autofill/AutoFillViewModel.kt +++ b/app/src/main/java/com/x8bit/bitwarden/ui/platform/feature/settings/autofill/AutoFillViewModel.kt @@ -7,7 +7,6 @@ import com.x8bit.bitwarden.data.platform.repository.SettingsRepository import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType import com.x8bit.bitwarden.ui.platform.base.BaseViewModel import com.x8bit.bitwarden.ui.platform.base.util.Text -import com.x8bit.bitwarden.ui.platform.base.util.asText import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -31,7 +30,7 @@ class AutoFillViewModel @Inject constructor( ?: AutoFillState( isAskToAddLoginEnabled = !settingsRepository.isAutofillSavePromptDisabled, isAutoFillServicesEnabled = settingsRepository.isAutofillEnabledStateFlow.value, - isCopyTotpAutomaticallyEnabled = false, + isCopyTotpAutomaticallyEnabled = !settingsRepository.isAutoCopyTotpDisabled, isUseInlineAutoFillEnabled = settingsRepository.isInlineAutofillEnabled, defaultUriMatchType = settingsRepository.defaultUriMatchType, ), @@ -84,8 +83,7 @@ class AutoFillViewModel @Inject constructor( private fun handleCopyTotpAutomaticallyClick( action: AutoFillAction.CopyTotpAutomaticallyClick, ) { - // TODO BIT-1093: Persist selection - sendEvent(AutoFillEvent.ShowToast("Not yet implemented.".asText())) + settingsRepository.isAutoCopyTotpDisabled = !action.isEnabled mutableStateFlow.update { it.copy(isCopyTotpAutomaticallyEnabled = action.isEnabled) } } diff --git a/app/src/test/java/com/x8bit/bitwarden/data/autofill/manager/AutofillCompletionManagerTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/autofill/manager/AutofillCompletionManagerTest.kt index 9d94bca765..d6882e94cc 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/autofill/manager/AutofillCompletionManagerTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/autofill/manager/AutofillCompletionManagerTest.kt @@ -22,6 +22,7 @@ import com.x8bit.bitwarden.data.autofill.util.getAutofillAssistStructureOrNull import com.x8bit.bitwarden.data.autofill.util.toAutofillAppInfo import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager +import com.x8bit.bitwarden.data.platform.repository.SettingsRepository import com.x8bit.bitwarden.data.vault.repository.VaultRepository import com.x8bit.bitwarden.data.vault.repository.model.GenerateTotpResult import io.mockk.coEvery @@ -63,6 +64,7 @@ class AutofillCompletionManagerTest { private val filledDataBuilder: FilledDataBuilder = mockk() private val filledPartition: FilledPartition = mockk() private val mockIntent: Intent = mockk() + private val settingsRepository: SettingsRepository = mockk() private val resultIntent: Intent = mockk() private val toast: Toast = mockk { every { show() } just runs @@ -76,6 +78,7 @@ class AutofillCompletionManagerTest { clipboardManager = clipboardManager, dispatcherManager = dispatcherManager, filledDataBuilderProvider = { filledDataBuilder }, + settingsRepository = settingsRepository, vaultRepository = vaultRepository, ) @@ -239,6 +242,7 @@ class AutofillCompletionManagerTest { autofillAppInfo = autofillAppInfo, ) } returns dataset + every { settingsRepository.isAutoCopyTotpDisabled } returns false every { createAutofillSelectionResultIntent(dataset = dataset) } returns resultIntent coEvery { vaultRepository.generateTotp( @@ -278,6 +282,7 @@ class AutofillCompletionManagerTest { authIntentSender = null, autofillAppInfo = autofillAppInfo, ) + settingsRepository.isAutoCopyTotpDisabled createAutofillSelectionResultIntent(dataset = dataset) Toast.makeText( context, @@ -319,6 +324,7 @@ class AutofillCompletionManagerTest { autofillAppInfo = autofillAppInfo, ) } returns dataset + every { settingsRepository.isAutoCopyTotpDisabled } returns false every { createAutofillSelectionResultIntent(dataset = dataset) } returns resultIntent coEvery { vaultRepository.generateTotp( @@ -350,6 +356,7 @@ class AutofillCompletionManagerTest { authIntentSender = null, autofillAppInfo = autofillAppInfo, ) + settingsRepository.isAutoCopyTotpDisabled createAutofillSelectionResultIntent(dataset = dataset) } coVerify { @@ -385,6 +392,7 @@ class AutofillCompletionManagerTest { autofillAppInfo = autofillAppInfo, ) } returns dataset + every { settingsRepository.isAutoCopyTotpDisabled } returns false every { createAutofillSelectionResultIntent(dataset = dataset) } returns resultIntent mutableUserStateFlow.value = mockk { every { activeAccount.isPremium } returns true @@ -400,6 +408,7 @@ class AutofillCompletionManagerTest { activity.finish() } verify { + settingsRepository.isAutoCopyTotpDisabled activity.intent mockIntent.getAutofillAssistStructureOrNull() autofillParser.parse( @@ -410,6 +419,7 @@ class AutofillCompletionManagerTest { authIntentSender = null, autofillAppInfo = autofillAppInfo, ) + settingsRepository.isAutoCopyTotpDisabled createAutofillSelectionResultIntent(dataset = dataset) } coVerify { @@ -441,6 +451,7 @@ class AutofillCompletionManagerTest { autofillAppInfo = autofillAppInfo, ) } returns dataset + every { settingsRepository.isAutoCopyTotpDisabled } returns false every { createAutofillSelectionResultIntent(dataset = dataset) } returns resultIntent mutableUserStateFlow.value = mockk { every { activeAccount.isPremium } returns false @@ -466,6 +477,65 @@ class AutofillCompletionManagerTest { authIntentSender = null, autofillAppInfo = autofillAppInfo, ) + settingsRepository.isAutoCopyTotpDisabled + createAutofillSelectionResultIntent(dataset = dataset) + } + coVerify { + filledDataBuilder.build(autofillRequest = fillableRequest) + } + } + + @Suppress("MaxLineLength") + @Test + fun `completeAutofill when filled partition and totp copy disabled should build a dataset, place it in a result Intent, and finish the Activity`() { + val filledData: FilledData = mockk { + every { filledPartitions } returns listOf(filledPartition) + } + every { activity.intent } returns mockIntent + every { mockIntent.getAutofillAssistStructureOrNull() } returns assistStructure + every { + autofillParser.parse( + autofillAppInfo = autofillAppInfo, + assistStructure = assistStructure, + ) + } returns fillableRequest + every { cipherView.login?.totp } returns TOTP_CODE + coEvery { + filledDataBuilder.build(autofillRequest = fillableRequest) + } returns filledData + every { + filledPartition.buildDataset( + authIntentSender = null, + autofillAppInfo = autofillAppInfo, + ) + } returns dataset + every { settingsRepository.isAutoCopyTotpDisabled } returns true + every { createAutofillSelectionResultIntent(dataset = dataset) } returns resultIntent + mutableUserStateFlow.value = mockk { + every { activeAccount.isPremium } returns true + } + + autofillCompletionManager.completeAutofill( + activity = activity, + cipherView = cipherView, + ) + + verify { + activity.setResult(Activity.RESULT_OK, resultIntent) + activity.finish() + } + verify { + activity.intent + mockIntent.getAutofillAssistStructureOrNull() + autofillParser.parse( + autofillAppInfo = autofillAppInfo, + assistStructure = assistStructure, + ) + filledPartition.buildDataset( + authIntentSender = null, + autofillAppInfo = autofillAppInfo, + ) + settingsRepository.isAutoCopyTotpDisabled createAutofillSelectionResultIntent(dataset = dataset) } coVerify { diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceTest.kt index 6b201caba9..ab2daa0344 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/SettingsDiskSourceTest.kt @@ -107,6 +107,10 @@ class SettingsDiskSourceTest { userId = userId, uriMatchType = UriMatchType.REGULAR_EXPRESSION, ) + settingsDiskSource.storeAutoCopyTotpDisabled( + userId = userId, + isAutomaticallyCopyTotpDisabled = true, + ) settingsDiskSource.storeAutofillSavePromptDisabled( userId = userId, isAutofillSavePromptDisabled = true, @@ -147,6 +151,7 @@ class SettingsDiskSourceTest { assertNull(settingsDiskSource.getVaultTimeoutInMinutes(userId = userId)) assertNull(settingsDiskSource.getVaultTimeoutAction(userId = userId)) assertNull(settingsDiskSource.getDefaultUriMatchType(userId = userId)) + assertNull(settingsDiskSource.getAutoCopyTotpDisabled(userId = userId)) assertNull(settingsDiskSource.getAutofillSavePromptDisabled(userId = userId)) assertNull(settingsDiskSource.getPullToRefreshEnabled(userId = userId)) assertNull(settingsDiskSource.getInlineAutofillEnabled(userId = userId)) @@ -561,6 +566,50 @@ class SettingsDiskSourceTest { assertFalse(fakeSharedPreferences.contains(defaultUriMatchTypeKey)) } + @Suppress("MaxLineLength") + @Test + fun `getAutoCopyTotpDisabled when values are present should pull from SharedPreferences`() { + val disableAutoTotpCopyBaseKey = "bwPreferencesStorage:disableAutoTotpCopy" + val mockUserId = "mockUserId" + val disableAutoTotpCopyKey = "${disableAutoTotpCopyBaseKey}_$mockUserId" + fakeSharedPreferences + .edit { + putBoolean(disableAutoTotpCopyKey, true) + } + assertEquals(true, settingsDiskSource.getAutoCopyTotpDisabled(userId = mockUserId)) + } + + @Test + fun `getAutoCopyTotpDisabled when values are absent should return null`() { + val mockUserId = "mockUserId" + assertNull(settingsDiskSource.getAutoCopyTotpDisabled(userId = mockUserId)) + } + + @Test + fun `storeAutoCopyTotpDisabled for non-null values should update SharedPreferences`() { + val disableAutoTotpCopyBaseKey = "bwPreferencesStorage:disableAutoTotpCopy" + val mockUserId = "mockUserId" + val disableAutoTotpCopyKey = "${disableAutoTotpCopyBaseKey}_$mockUserId" + settingsDiskSource.storeAutoCopyTotpDisabled( + userId = mockUserId, + isAutomaticallyCopyTotpDisabled = true, + ) + assertTrue(fakeSharedPreferences.getBoolean(disableAutoTotpCopyKey, false)) + } + + @Test + fun `storeAutoCopyTotpDisabled for null values should clear SharedPreferences`() { + val disableAutoTotpCopyBaseKey = "bwPreferencesStorage:disableAutoTotpCopy" + val mockUserId = "mockUserId" + val disableAutoTotpCopyKey = "${disableAutoTotpCopyBaseKey}_$mockUserId" + fakeSharedPreferences.edit { putBoolean(disableAutoTotpCopyKey, false) } + settingsDiskSource.storeAutoCopyTotpDisabled( + userId = mockUserId, + isAutomaticallyCopyTotpDisabled = null, + ) + assertFalse(fakeSharedPreferences.contains(disableAutoTotpCopyKey)) + } + @Suppress("MaxLineLength") @Test fun `getAutofillSavePromptDisabled when values are present should pull from SharedPreferences`() { diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/util/FakeSettingsDiskSource.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/util/FakeSettingsDiskSource.kt index 33ebdc6b8f..ab23124c86 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/util/FakeSettingsDiskSource.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/datasource/disk/util/FakeSettingsDiskSource.kt @@ -45,6 +45,7 @@ class FakeSettingsDiskSource : SettingsDiskSource { private val storedVaultTimeoutInMinutes = mutableMapOf() private val storedUriMatchTypes = mutableMapOf() private val storedClearClipboardFrequency = mutableMapOf() + private val storedDisableAutoTotpCopy = mutableMapOf() private val storedDisableAutofillSavePrompt = mutableMapOf() private val storedPullToRefreshEnabled = mutableMapOf() private val storedInlineAutofillEnabled = mutableMapOf() @@ -124,6 +125,7 @@ class FakeSettingsDiskSource : SettingsDiskSource { storedVaultTimeoutActions.remove(userId) storedVaultTimeoutInMinutes.remove(userId) storedUriMatchTypes.remove(userId) + storedDisableAutoTotpCopy.remove(userId) storedDisableAutofillSavePrompt.remove(userId) storedPullToRefreshEnabled.remove(userId) storedInlineAutofillEnabled.remove(userId) @@ -194,6 +196,16 @@ class FakeSettingsDiskSource : SettingsDiskSource { storedUriMatchTypes[userId] = uriMatchType } + override fun getAutoCopyTotpDisabled(userId: String): Boolean? = + storedDisableAutoTotpCopy[userId] + + override fun storeAutoCopyTotpDisabled( + userId: String, + isAutomaticallyCopyTotpDisabled: Boolean?, + ) { + storedDisableAutoTotpCopy[userId] = isAutomaticallyCopyTotpDisabled + } + override fun getAutofillSavePromptDisabled(userId: String): Boolean? = storedDisableAutofillSavePrompt[userId] diff --git a/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt b/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt index bc6ca629bb..4ba9151918 100644 --- a/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/data/platform/repository/SettingsRepositoryTest.kt @@ -473,6 +473,24 @@ class SettingsRepositoryTest { assertTrue(fakeSettingsDiskSource.getInlineAutofillEnabled(userId = userId)!!) } + @Test + fun `isAutoCopyTotpDisabled should pull from and update SettingsDiskSource`() { + val userId = "userId" + fakeAuthDiskSource.userState = MOCK_USER_STATE + assertFalse(settingsRepository.isAutoCopyTotpDisabled) + + // Updates to the disk source change the repository value. + fakeSettingsDiskSource.storeAutoCopyTotpDisabled( + userId = userId, + isAutomaticallyCopyTotpDisabled = true, + ) + assertTrue(settingsRepository.isAutoCopyTotpDisabled) + + // Updates to the repository change the disk source value + settingsRepository.isAutoCopyTotpDisabled = false + assertFalse(fakeSettingsDiskSource.getAutoCopyTotpDisabled(userId = userId)!!) + } + @Test fun `isAutofillSavePromptDisabled should pull from and update SettingsDiskSource`() { val userId = "userId" diff --git a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/autofill/AutoFillViewModelTest.kt b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/autofill/AutoFillViewModelTest.kt index 20cde84f48..9c7059d90c 100644 --- a/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/autofill/AutoFillViewModelTest.kt +++ b/app/src/test/java/com/x8bit/bitwarden/ui/platform/feature/settings/autofill/AutoFillViewModelTest.kt @@ -5,7 +5,6 @@ import app.cash.turbine.test import com.x8bit.bitwarden.data.platform.repository.SettingsRepository import com.x8bit.bitwarden.data.platform.repository.model.UriMatchType import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest -import com.x8bit.bitwarden.ui.platform.base.util.asText import io.mockk.every import io.mockk.just import io.mockk.mockk @@ -22,6 +21,8 @@ class AutoFillViewModelTest : BaseViewModelTest() { private val settingsRepository: SettingsRepository = mockk() { every { isInlineAutofillEnabled } returns true every { isInlineAutofillEnabled = any() } just runs + every { isAutoCopyTotpDisabled } returns true + every { isAutoCopyTotpDisabled = any() } just runs every { isAutofillSavePromptDisabled } returns true every { isAutofillSavePromptDisabled = any() } just runs every { defaultUriMatchType } returns UriMatchType.DOMAIN @@ -117,19 +118,23 @@ class AutoFillViewModelTest : BaseViewModelTest() { } } + @Suppress("MaxLineLength") @Test - fun `on CopyTotpAutomaticallyClick should update the isCopyTotpAutomaticallyEnabled state`() = + fun `on CopyTotpAutomaticallyClick should update the isCopyTotpAutomaticallyEnabled state and save new value to settings`() = runTest { val viewModel = createViewModel() val isEnabled = true + viewModel.trySendAction(AutoFillAction.CopyTotpAutomaticallyClick(isEnabled)) viewModel.eventFlow.test { - viewModel.trySendAction(AutoFillAction.CopyTotpAutomaticallyClick(isEnabled)) - assertEquals(AutoFillEvent.ShowToast("Not yet implemented.".asText()), awaitItem()) + expectNoEvents() } assertEquals( DEFAULT_STATE.copy(isCopyTotpAutomaticallyEnabled = isEnabled), viewModel.stateFlow.value, ) + + // The UI enables the value, so the value gets flipped to save it as a "disabled" value. + verify { settingsRepository.isAutoCopyTotpDisabled = !isEnabled } } @Test