mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 07:05:35 +03:00
BITAU-105 Add support for deep link to account security (#4063)
This commit is contained in:
parent
43dc2f8116
commit
1446e43c46
15 changed files with 243 additions and 9 deletions
|
@ -98,6 +98,11 @@
|
||||||
<data android:scheme="otpauth" />
|
<data android:scheme="otpauth" />
|
||||||
<data android:host="totp" />
|
<data android:host="totp" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:scheme="bitwarden" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
|
|
@ -30,6 +30,7 @@ import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||||
|
import com.x8bit.bitwarden.ui.platform.util.isAccountSecurityShortcut
|
||||||
import com.x8bit.bitwarden.ui.platform.util.isMyVaultShortcut
|
import com.x8bit.bitwarden.ui.platform.util.isMyVaultShortcut
|
||||||
import com.x8bit.bitwarden.ui.platform.util.isPasswordGeneratorShortcut
|
import com.x8bit.bitwarden.ui.platform.util.isPasswordGeneratorShortcut
|
||||||
import com.x8bit.bitwarden.ui.vault.util.getTotpDataOrNull
|
import com.x8bit.bitwarden.ui.vault.util.getTotpDataOrNull
|
||||||
|
@ -236,6 +237,7 @@ class MainViewModel @Inject constructor(
|
||||||
val totpData = intent.getTotpDataOrNull()
|
val totpData = intent.getTotpDataOrNull()
|
||||||
val hasGeneratorShortcut = intent.isPasswordGeneratorShortcut
|
val hasGeneratorShortcut = intent.isPasswordGeneratorShortcut
|
||||||
val hasVaultShortcut = intent.isMyVaultShortcut
|
val hasVaultShortcut = intent.isMyVaultShortcut
|
||||||
|
val hasAccountSecurityShortcut = intent.isAccountSecurityShortcut
|
||||||
val fido2CredentialRequestData = intent.getFido2CredentialRequestOrNull()
|
val fido2CredentialRequestData = intent.getFido2CredentialRequestOrNull()
|
||||||
val completeRegistrationData = intent.getCompleteRegistrationDataIntentOrNull()
|
val completeRegistrationData = intent.getCompleteRegistrationDataIntentOrNull()
|
||||||
val fido2CredentialAssertionRequest = intent.getFido2AssertionRequestOrNull()
|
val fido2CredentialAssertionRequest = intent.getFido2AssertionRequestOrNull()
|
||||||
|
@ -330,6 +332,11 @@ class MainViewModel @Inject constructor(
|
||||||
hasVaultShortcut -> {
|
hasVaultShortcut -> {
|
||||||
specialCircumstanceManager.specialCircumstance = SpecialCircumstance.VaultShortcut
|
specialCircumstanceManager.specialCircumstance = SpecialCircumstance.VaultShortcut
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasAccountSecurityShortcut -> {
|
||||||
|
specialCircumstanceManager.specialCircumstance =
|
||||||
|
SpecialCircumstance.AccountSecurityShortcut
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,12 @@ sealed class SpecialCircumstance : Parcelable {
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data object VaultShortcut : SpecialCircumstance()
|
data object VaultShortcut : SpecialCircumstance()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The app was launched via deeplink to the account security screen.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data object AccountSecurityShortcut : SpecialCircumstance()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subset of [SpecialCircumstance] that are only relevant in a pre-login state and should be
|
* A subset of [SpecialCircumstance] that are only relevant in a pre-login state and should be
|
||||||
* cleared after a successful login.
|
* cleared after a successful login.
|
||||||
|
|
|
@ -151,6 +151,7 @@ class RootNavViewModel @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpecialCircumstance.AccountSecurityShortcut,
|
||||||
SpecialCircumstance.GeneratorShortcut,
|
SpecialCircumstance.GeneratorShortcut,
|
||||||
SpecialCircumstance.VaultShortcut,
|
SpecialCircumstance.VaultShortcut,
|
||||||
null,
|
null,
|
||||||
|
|
|
@ -67,6 +67,7 @@ fun SettingsScreen(
|
||||||
SettingsEvent.NavigateAutoFill -> onNavigateToAutoFill()
|
SettingsEvent.NavigateAutoFill -> onNavigateToAutoFill()
|
||||||
SettingsEvent.NavigateOther -> onNavigateToOther()
|
SettingsEvent.NavigateOther -> onNavigateToOther()
|
||||||
SettingsEvent.NavigateVault -> onNavigateToVault()
|
SettingsEvent.NavigateVault -> onNavigateToVault()
|
||||||
|
SettingsEvent.NavigateAccountSecurityShortcut -> onNavigateToAccountSecurity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,11 @@ package com.x8bit.bitwarden.ui.platform.feature.settings
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.x8bit.bitwarden.R
|
import com.x8bit.bitwarden.R
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.BackgroundEvent
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
@ -20,6 +23,7 @@ import javax.inject.Inject
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class SettingsViewModel @Inject constructor(
|
class SettingsViewModel @Inject constructor(
|
||||||
settingsRepository: SettingsRepository,
|
settingsRepository: SettingsRepository,
|
||||||
|
specialCircumstanceManager: SpecialCircumstanceManager,
|
||||||
) : BaseViewModel<SettingsState, SettingsEvent, SettingsAction>(
|
) : BaseViewModel<SettingsState, SettingsEvent, SettingsAction>(
|
||||||
initialState = SettingsState(
|
initialState = SettingsState(
|
||||||
securityCount = settingsRepository.allSecuritySettingsBadgeCountFlow.value,
|
securityCount = settingsRepository.allSecuritySettingsBadgeCountFlow.value,
|
||||||
|
@ -39,6 +43,15 @@ class SettingsViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
.onEach(::sendAction)
|
.onEach(::sendAction)
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
|
when (specialCircumstanceManager.specialCircumstance) {
|
||||||
|
SpecialCircumstance.AccountSecurityShortcut -> {
|
||||||
|
sendEvent(SettingsEvent.NavigateAccountSecurityShortcut)
|
||||||
|
specialCircumstanceManager.specialCircumstance = null
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> Unit
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleAction(action: SettingsAction): Unit = when (action) {
|
override fun handleAction(action: SettingsAction): Unit = when (action) {
|
||||||
|
@ -115,6 +128,11 @@ sealed class SettingsEvent {
|
||||||
*/
|
*/
|
||||||
data object NavigateAccountSecurity : SettingsEvent()
|
data object NavigateAccountSecurity : SettingsEvent()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the account security screen.
|
||||||
|
*/
|
||||||
|
data object NavigateAccountSecurityShortcut : SettingsEvent(), BackgroundEvent
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate to the appearance screen.
|
* Navigate to the appearance screen.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -58,7 +58,7 @@ import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType
|
||||||
/**
|
/**
|
||||||
* Top level composable for the Vault Unlocked Screen.
|
* Top level composable for the Vault Unlocked Screen.
|
||||||
*/
|
*/
|
||||||
@Suppress("LongParameterList")
|
@Suppress("LongParameterList", "LongMethod")
|
||||||
@Composable
|
@Composable
|
||||||
fun VaultUnlockedNavBarScreen(
|
fun VaultUnlockedNavBarScreen(
|
||||||
viewModel: VaultUnlockedNavBarViewModel = hiltViewModel(),
|
viewModel: VaultUnlockedNavBarViewModel = hiltViewModel(),
|
||||||
|
@ -104,6 +104,10 @@ fun VaultUnlockedNavBarScreen(
|
||||||
VaultUnlockedNavBarEvent.NavigateToSettingsScreen -> {
|
VaultUnlockedNavBarEvent.NavigateToSettingsScreen -> {
|
||||||
navigateToSettingsGraph(navOptions)
|
navigateToSettingsGraph(navOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VaultUnlockedNavBarEvent.Shortcut.NavigateToSettingsScreen -> {
|
||||||
|
navigateToSettingsGraph(navOptions)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,6 +65,10 @@ class VaultUnlockedNavBarViewModel @Inject constructor(
|
||||||
specialCircumstancesManager.specialCircumstance = null
|
specialCircumstancesManager.specialCircumstance = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpecialCircumstance.AccountSecurityShortcut -> {
|
||||||
|
sendEvent(VaultUnlockedNavBarEvent.Shortcut.NavigateToSettingsScreen)
|
||||||
|
}
|
||||||
|
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,5 +287,12 @@ sealed class VaultUnlockedNavBarEvent {
|
||||||
contentDescriptionRes = contentDescRes,
|
contentDescriptionRes = contentDescRes,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the Settings Screen.
|
||||||
|
*/
|
||||||
|
data object NavigateToSettingsScreen : Shortcut() {
|
||||||
|
override val tab: VaultUnlockedNavBarTab = VaultUnlockedNavBarTab.Settings()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,3 +13,9 @@ val Intent.isMyVaultShortcut: Boolean
|
||||||
*/
|
*/
|
||||||
val Intent.isPasswordGeneratorShortcut: Boolean
|
val Intent.isPasswordGeneratorShortcut: Boolean
|
||||||
get() = dataString?.equals("bitwarden://password_generator") == true
|
get() = dataString?.equals("bitwarden://password_generator") == true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if the [Intent] is a deeplink to the account security screen, `false` otherwise.
|
||||||
|
*/
|
||||||
|
val Intent.isAccountSecurityShortcut: Boolean
|
||||||
|
get() = dataString?.equals("bitwarden://settings/account_security") == true
|
||||||
|
|
|
@ -48,6 +48,7 @@ import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||||
|
import com.x8bit.bitwarden.ui.platform.util.isAccountSecurityShortcut
|
||||||
import com.x8bit.bitwarden.ui.platform.util.isMyVaultShortcut
|
import com.x8bit.bitwarden.ui.platform.util.isMyVaultShortcut
|
||||||
import com.x8bit.bitwarden.ui.platform.util.isPasswordGeneratorShortcut
|
import com.x8bit.bitwarden.ui.platform.util.isPasswordGeneratorShortcut
|
||||||
import com.x8bit.bitwarden.ui.vault.model.TotpData
|
import com.x8bit.bitwarden.ui.vault.model.TotpData
|
||||||
|
@ -131,6 +132,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
mockkStatic(
|
mockkStatic(
|
||||||
Intent::isMyVaultShortcut,
|
Intent::isMyVaultShortcut,
|
||||||
Intent::isPasswordGeneratorShortcut,
|
Intent::isPasswordGeneratorShortcut,
|
||||||
|
Intent::isAccountSecurityShortcut,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,6 +148,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
unmockkStatic(
|
unmockkStatic(
|
||||||
Intent::isMyVaultShortcut,
|
Intent::isMyVaultShortcut,
|
||||||
Intent::isPasswordGeneratorShortcut,
|
Intent::isPasswordGeneratorShortcut,
|
||||||
|
Intent::isAccountSecurityShortcut,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,6 +315,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
|
|
||||||
viewModel.trySendAction(MainAction.ReceiveFirstIntent(intent = mockIntent))
|
viewModel.trySendAction(MainAction.ReceiveFirstIntent(intent = mockIntent))
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -334,6 +338,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
MainAction.ReceiveFirstIntent(
|
MainAction.ReceiveFirstIntent(
|
||||||
|
@ -363,6 +368,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
MainAction.ReceiveFirstIntent(
|
MainAction.ReceiveFirstIntent(
|
||||||
|
@ -394,6 +400,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { getAutofillSelectionDataOrNull() } returns null
|
every { getAutofillSelectionDataOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { authRepository.activeUserId } returns null
|
every { authRepository.activeUserId } returns null
|
||||||
|
@ -430,6 +437,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { getAutofillSelectionDataOrNull() } returns null
|
every { getAutofillSelectionDataOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { authRepository.activeUserId } returns "activeId"
|
every { authRepository.activeUserId } returns "activeId"
|
||||||
|
@ -468,6 +476,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { getAutofillSelectionDataOrNull() } returns null
|
every { getAutofillSelectionDataOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { authRepository.activeUserId } returns null
|
every { authRepository.activeUserId } returns null
|
||||||
|
@ -508,6 +517,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { getAutofillSelectionDataOrNull() } returns null
|
every { getAutofillSelectionDataOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { authRepository.activeUserId } returns null
|
every { authRepository.activeUserId } returns null
|
||||||
|
@ -550,6 +560,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { getAutofillSelectionDataOrNull() } returns null
|
every { getAutofillSelectionDataOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { authRepository.activeUserId } returns null
|
every { authRepository.activeUserId } returns null
|
||||||
|
@ -589,6 +600,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
MainAction.ReceiveFirstIntent(
|
MainAction.ReceiveFirstIntent(
|
||||||
|
@ -619,6 +631,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
MainAction.ReceiveFirstIntent(
|
MainAction.ReceiveFirstIntent(
|
||||||
|
@ -706,6 +719,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
coEvery {
|
coEvery {
|
||||||
|
@ -744,6 +758,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
coEvery {
|
coEvery {
|
||||||
|
@ -818,6 +833,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
MainAction.ReceiveNewIntent(
|
MainAction.ReceiveNewIntent(
|
||||||
|
@ -847,6 +863,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
|
|
||||||
viewModel.trySendAction(MainAction.ReceiveNewIntent(intent = mockIntent))
|
viewModel.trySendAction(MainAction.ReceiveNewIntent(intent = mockIntent))
|
||||||
assertEquals(
|
assertEquals(
|
||||||
|
@ -869,6 +886,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
MainAction.ReceiveNewIntent(
|
MainAction.ReceiveNewIntent(
|
||||||
|
@ -898,6 +916,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
MainAction.ReceiveNewIntent(
|
MainAction.ReceiveNewIntent(
|
||||||
|
@ -928,6 +947,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
MainAction.ReceiveNewIntent(
|
MainAction.ReceiveNewIntent(
|
||||||
|
@ -955,6 +975,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns true
|
every { isMyVaultShortcut } returns true
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
|
|
||||||
|
@ -969,6 +990,33 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `on ReceiveNewIntent with account security deeplink data should set the special circumstance to AccountSecurityShortcut `() {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
val mockIntent = mockk<Intent> {
|
||||||
|
every { getTotpDataOrNull() } returns null
|
||||||
|
every { getPasswordlessRequestDataIntentOrNull() } returns null
|
||||||
|
every { getAutofillSaveItemOrNull() } returns null
|
||||||
|
every { getAutofillSelectionDataOrNull() } returns null
|
||||||
|
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
||||||
|
every { isMyVaultShortcut } returns false
|
||||||
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns true
|
||||||
|
}
|
||||||
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
|
|
||||||
|
viewModel.trySendAction(
|
||||||
|
MainAction.ReceiveNewIntent(
|
||||||
|
intent = mockIntent,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
SpecialCircumstance.AccountSecurityShortcut,
|
||||||
|
specialCircumstanceManager.specialCircumstance,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `on ReceiveNewIntent with a password generator deeplink data should set the special circumstance to GeneratorShortcut`() {
|
fun `on ReceiveNewIntent with a password generator deeplink data should set the special circumstance to GeneratorShortcut`() {
|
||||||
|
@ -981,6 +1029,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns true
|
every { isPasswordGeneratorShortcut } returns true
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
|
|
||||||
|
@ -1070,6 +1119,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
every { mockIntent.isMyVaultShortcut } returns false
|
every { mockIntent.isMyVaultShortcut } returns false
|
||||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||||
|
every { mockIntent.isAccountSecurityShortcut } returns false
|
||||||
every { passwordlessRequestData.userId } returns "userId"
|
every { passwordlessRequestData.userId } returns "userId"
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
|
@ -1152,6 +1202,7 @@ private fun createMockFido2RegistrationIntent(
|
||||||
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createMockFido2AssertionIntent(
|
private fun createMockFido2AssertionIntent(
|
||||||
|
@ -1166,6 +1217,7 @@ private fun createMockFido2AssertionIntent(
|
||||||
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createMockFido2GetCredentialsIntent(
|
private fun createMockFido2GetCredentialsIntent(
|
||||||
|
@ -1183,6 +1235,7 @@ private fun createMockFido2GetCredentialsIntent(
|
||||||
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
every { getCompleteRegistrationDataIntentOrNull() } returns null
|
||||||
every { isMyVaultShortcut } returns false
|
every { isMyVaultShortcut } returns false
|
||||||
every { isPasswordGeneratorShortcut } returns false
|
every { isPasswordGeneratorShortcut } returns false
|
||||||
|
every { isAccountSecurityShortcut } returns false
|
||||||
}
|
}
|
||||||
|
|
||||||
private val FIXED_CLOCK: Clock = Clock.fixed(
|
private val FIXED_CLOCK: Clock = Clock.fixed(
|
||||||
|
|
|
@ -481,6 +481,44 @@ class RootNavViewModelTest : BaseViewModelTest() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `when the active user has an unlocked vault but there is an AccountSecurityShortcut special circumstance the nav state should be VaultUnlocked`() {
|
||||||
|
specialCircumstanceManager.specialCircumstance =
|
||||||
|
SpecialCircumstance.AccountSecurityShortcut
|
||||||
|
mutableUserStateFlow.tryEmit(
|
||||||
|
UserState(
|
||||||
|
activeUserId = "activeUserId",
|
||||||
|
accounts = listOf(
|
||||||
|
UserState.Account(
|
||||||
|
userId = "activeUserId",
|
||||||
|
name = "name",
|
||||||
|
email = "email",
|
||||||
|
avatarColorHex = "avatarColorHex",
|
||||||
|
environment = Environment.Us,
|
||||||
|
isPremium = true,
|
||||||
|
isLoggedIn = true,
|
||||||
|
isVaultUnlocked = true,
|
||||||
|
needsPasswordReset = false,
|
||||||
|
isBiometricsEnabled = false,
|
||||||
|
organizations = emptyList(),
|
||||||
|
needsMasterPassword = false,
|
||||||
|
trustedDevice = null,
|
||||||
|
hasMasterPassword = true,
|
||||||
|
isUsingKeyConnector = false,
|
||||||
|
firstTimeState = UserState.FirstTimeState(false),
|
||||||
|
onboardingStatus = OnboardingStatus.COMPLETE,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
assertEquals(
|
||||||
|
RootNavState.VaultUnlocked(activeUserId = "activeUserId"),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `when the active user has an unlocked vault but the is a ShareNewSend special circumstance the nav state should be VaultUnlockedForNewSend`() {
|
fun `when the active user has an unlocked vault but the is a ShareNewSend special circumstance the nav state should be VaultUnlockedForNewSend`() {
|
||||||
|
|
|
@ -260,6 +260,25 @@ class SettingsScreenTest : BaseComposeTest() {
|
||||||
assertTrue(haveCalledNavigateToVault)
|
assertTrue(haveCalledNavigateToVault)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `on NavigateAccountSecurityShortcut should call onNavigateToAccountSecurity`() {
|
||||||
|
var haveCalledNavigateToAccountSecurity = false
|
||||||
|
composeTestRule.setContent {
|
||||||
|
SettingsScreen(
|
||||||
|
viewModel = viewModel,
|
||||||
|
onNavigateToAbout = { },
|
||||||
|
onNavigateToAccountSecurity = { haveCalledNavigateToAccountSecurity = true },
|
||||||
|
onNavigateToAppearance = { },
|
||||||
|
onNavigateToAutoFill = { },
|
||||||
|
onNavigateToOther = { },
|
||||||
|
onNavigateToVault = {
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
mutableEventFlow.tryEmit(SettingsEvent.NavigateAccountSecurityShortcut)
|
||||||
|
assertTrue(haveCalledNavigateToAccountSecurity)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Settings screen should show correct number of notification badges based on state`() {
|
fun `Settings screen should show correct number of notification badges based on state`() {
|
||||||
composeTestRule.setContent {
|
composeTestRule.setContent {
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
package com.x8bit.bitwarden.ui.platform.feature.settings
|
package com.x8bit.bitwarden.ui.platform.feature.settings
|
||||||
|
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
|
import io.mockk.runs
|
||||||
|
import io.mockk.verify
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
|
@ -19,10 +24,13 @@ class SettingsViewModelTest : BaseViewModelTest() {
|
||||||
every { allSecuritySettingsBadgeCountFlow } returns mutableSecurityBadgeCountFlow
|
every { allSecuritySettingsBadgeCountFlow } returns mutableSecurityBadgeCountFlow
|
||||||
every { allAutofillSettingsBadgeCountFlow } returns mutableAutofillBadgeCountFlow
|
every { allAutofillSettingsBadgeCountFlow } returns mutableAutofillBadgeCountFlow
|
||||||
}
|
}
|
||||||
|
private val specialCircumstanceManager: SpecialCircumstanceManager = mockk {
|
||||||
|
every { specialCircumstance } returns null
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on SettingsClick with ABOUT should emit NavigateAbout`() = runTest {
|
fun `on SettingsClick with ABOUT should emit NavigateAbout`() = runTest {
|
||||||
val viewModel = SettingsViewModel(settingsRepository = settingsRepository)
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.ABOUT))
|
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.ABOUT))
|
||||||
assertEquals(SettingsEvent.NavigateAbout, awaitItem())
|
assertEquals(SettingsEvent.NavigateAbout, awaitItem())
|
||||||
|
@ -31,7 +39,7 @@ class SettingsViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on SettingsClick with ACCOUNT_SECURITY should emit NavigateAccountSecurity`() = runTest {
|
fun `on SettingsClick with ACCOUNT_SECURITY should emit NavigateAccountSecurity`() = runTest {
|
||||||
val viewModel = SettingsViewModel(settingsRepository = settingsRepository)
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.ACCOUNT_SECURITY))
|
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.ACCOUNT_SECURITY))
|
||||||
assertEquals(SettingsEvent.NavigateAccountSecurity, awaitItem())
|
assertEquals(SettingsEvent.NavigateAccountSecurity, awaitItem())
|
||||||
|
@ -40,7 +48,7 @@ class SettingsViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on SettingsClick with APPEARANCE should emit NavigateAppearance`() = runTest {
|
fun `on SettingsClick with APPEARANCE should emit NavigateAppearance`() = runTest {
|
||||||
val viewModel = SettingsViewModel(settingsRepository = settingsRepository)
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.APPEARANCE))
|
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.APPEARANCE))
|
||||||
assertEquals(SettingsEvent.NavigateAppearance, awaitItem())
|
assertEquals(SettingsEvent.NavigateAppearance, awaitItem())
|
||||||
|
@ -49,7 +57,7 @@ class SettingsViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on SettingsClick with AUTO_FILL should emit NavigateAutoFill`() = runTest {
|
fun `on SettingsClick with AUTO_FILL should emit NavigateAutoFill`() = runTest {
|
||||||
val viewModel = SettingsViewModel(settingsRepository = settingsRepository)
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.AUTO_FILL))
|
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.AUTO_FILL))
|
||||||
assertEquals(SettingsEvent.NavigateAutoFill, awaitItem())
|
assertEquals(SettingsEvent.NavigateAutoFill, awaitItem())
|
||||||
|
@ -58,7 +66,7 @@ class SettingsViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on SettingsClick with OTHER should emit NavigateOther`() = runTest {
|
fun `on SettingsClick with OTHER should emit NavigateOther`() = runTest {
|
||||||
val viewModel = SettingsViewModel(settingsRepository = settingsRepository)
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.OTHER))
|
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.OTHER))
|
||||||
assertEquals(SettingsEvent.NavigateOther, awaitItem())
|
assertEquals(SettingsEvent.NavigateOther, awaitItem())
|
||||||
|
@ -67,7 +75,7 @@ class SettingsViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on SettingsClick with VAULT should emit NavigateVault`() = runTest {
|
fun `on SettingsClick with VAULT should emit NavigateVault`() = runTest {
|
||||||
val viewModel = SettingsViewModel(settingsRepository = settingsRepository)
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.VAULT))
|
viewModel.trySendAction(SettingsAction.SettingsClick(Settings.VAULT))
|
||||||
assertEquals(SettingsEvent.NavigateVault, awaitItem())
|
assertEquals(SettingsEvent.NavigateVault, awaitItem())
|
||||||
|
@ -78,7 +86,7 @@ class SettingsViewModelTest : BaseViewModelTest() {
|
||||||
fun `initial state reflects the current state of the repository`() {
|
fun `initial state reflects the current state of the repository`() {
|
||||||
mutableAutofillBadgeCountFlow.update { 1 }
|
mutableAutofillBadgeCountFlow.update { 1 }
|
||||||
mutableSecurityBadgeCountFlow.update { 2 }
|
mutableSecurityBadgeCountFlow.update { 2 }
|
||||||
val viewModel = SettingsViewModel(settingsRepository = settingsRepository)
|
val viewModel = createViewModel()
|
||||||
assertEquals(
|
assertEquals(
|
||||||
SettingsState(
|
SettingsState(
|
||||||
autoFillCount = 1,
|
autoFillCount = 1,
|
||||||
|
@ -90,7 +98,7 @@ class SettingsViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `State updates when repository emits new values for badge counts`() = runTest {
|
fun `State updates when repository emits new values for badge counts`() = runTest {
|
||||||
val viewModel = SettingsViewModel(settingsRepository = settingsRepository)
|
val viewModel = createViewModel()
|
||||||
viewModel.stateFlow.test {
|
viewModel.stateFlow.test {
|
||||||
assertEquals(
|
assertEquals(
|
||||||
SettingsState(
|
SettingsState(
|
||||||
|
@ -119,4 +127,25 @@ class SettingsViewModelTest : BaseViewModelTest() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
fun `init should send NavigateAccountSecurityShortcut when special circumstance is AccountSecurityShortcut`() =
|
||||||
|
runTest {
|
||||||
|
every {
|
||||||
|
specialCircumstanceManager.specialCircumstance
|
||||||
|
} returns SpecialCircumstance.AccountSecurityShortcut
|
||||||
|
every { specialCircumstanceManager.specialCircumstance = null } just runs
|
||||||
|
createViewModel().eventFlow.test {
|
||||||
|
assertEquals(
|
||||||
|
SettingsEvent.NavigateAccountSecurityShortcut, awaitItem(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
verify { specialCircumstanceManager.specialCircumstance = null }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createViewModel() = SettingsViewModel(
|
||||||
|
settingsRepository = settingsRepository,
|
||||||
|
specialCircumstanceManager = specialCircumstanceManager,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,21 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `NavigateToSettingsScreen shortcut event should navigate to SettingsScreen`() {
|
||||||
|
mutableEventFlow.tryEmit(VaultUnlockedNavBarEvent.NavigateToSendScreen)
|
||||||
|
composeTestRule.runOnIdle { fakeNavHostController.assertCurrentRoute("send_graph") }
|
||||||
|
mutableEventFlow.tryEmit(
|
||||||
|
VaultUnlockedNavBarEvent.Shortcut.NavigateToSettingsScreen,
|
||||||
|
)
|
||||||
|
composeTestRule.runOnIdle {
|
||||||
|
fakeNavHostController.assertLastNavigation(
|
||||||
|
route = "settings_graph",
|
||||||
|
navOptions = expectedNavOptions,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `send tab click should send SendTabClick action`() {
|
fun `send tab click should send SendTabClick action`() {
|
||||||
composeTestRule.onNodeWithText("Send").performClick()
|
composeTestRule.onNodeWithText("Send").performClick()
|
||||||
|
|
|
@ -80,6 +80,27 @@ class VaultUnlockedNavBarViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `on init with AccountSecurityShortcut special circumstance should navigate to the settings screen with shortcut event`() =
|
||||||
|
runTest {
|
||||||
|
every {
|
||||||
|
specialCircumstancesManager.specialCircumstance
|
||||||
|
} returns SpecialCircumstance.AccountSecurityShortcut
|
||||||
|
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
|
||||||
|
viewModel.eventFlow.test {
|
||||||
|
assertEquals(
|
||||||
|
VaultUnlockedNavBarEvent.Shortcut.NavigateToSettingsScreen,
|
||||||
|
awaitItem(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
verify(exactly = 1) {
|
||||||
|
specialCircumstancesManager.specialCircumstance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on init with no shortcut special circumstance should do nothing`() = runTest {
|
fun `on init with no shortcut special circumstance should do nothing`() = runTest {
|
||||||
every { specialCircumstancesManager.specialCircumstance } returns null
|
every { specialCircumstancesManager.specialCircumstance } returns null
|
||||||
|
|
Loading…
Reference in a new issue