mirror of
https://github.com/bitwarden/android.git
synced 2025-12-12 00:08:00 -06:00
[PM-27001] Skip account selection only one exists on cxp flow (#6055)
This commit is contained in:
parent
ae4b398258
commit
e610a7541d
@ -68,6 +68,7 @@ import com.x8bit.bitwarden.ui.vault.feature.addedit.util.toVaultItemCipherType
|
|||||||
import com.x8bit.bitwarden.ui.vault.feature.exportitems.ExportItemsGraphRoute
|
import com.x8bit.bitwarden.ui.vault.feature.exportitems.ExportItemsGraphRoute
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.exportitems.exportItemsGraph
|
import com.x8bit.bitwarden.ui.vault.feature.exportitems.exportItemsGraph
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.exportitems.navigateToExportItemsGraph
|
import com.x8bit.bitwarden.ui.vault.feature.exportitems.navigateToExportItemsGraph
|
||||||
|
import com.x8bit.bitwarden.ui.vault.feature.exportitems.verifypassword.navigateToVerifyPassword
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.navigateToVaultItemListingAsRoot
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.navigateToVaultItemListingAsRoot
|
||||||
import com.x8bit.bitwarden.ui.vault.model.VaultAddEditType
|
import com.x8bit.bitwarden.ui.vault.model.VaultAddEditType
|
||||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
||||||
@ -142,7 +143,10 @@ fun RootNavScreen(
|
|||||||
is RootNavState.VaultUnlockedForProviderGetCredentials,
|
is RootNavState.VaultUnlockedForProviderGetCredentials,
|
||||||
-> VaultUnlockedGraphRoute
|
-> VaultUnlockedGraphRoute
|
||||||
|
|
||||||
is RootNavState.CredentialExchangeExport -> ExportItemsGraphRoute
|
is RootNavState.CredentialExchangeExport,
|
||||||
|
is RootNavState.CredentialExchangeExportSkipAccountSelection,
|
||||||
|
-> ExportItemsGraphRoute
|
||||||
|
|
||||||
RootNavState.OnboardingAccountLockSetup -> SetupUnlockRoute.AsRoot
|
RootNavState.OnboardingAccountLockSetup -> SetupUnlockRoute.AsRoot
|
||||||
RootNavState.OnboardingAutoFillSetup -> SetupAutofillRoute.AsRoot
|
RootNavState.OnboardingAutoFillSetup -> SetupAutofillRoute.AsRoot
|
||||||
RootNavState.OnboardingBrowserAutofillSetup -> SetupBrowserAutofillRoute.AsRoot
|
RootNavState.OnboardingBrowserAutofillSetup -> SetupBrowserAutofillRoute.AsRoot
|
||||||
@ -288,6 +292,13 @@ fun RootNavScreen(
|
|||||||
is RootNavState.CredentialExchangeExport -> {
|
is RootNavState.CredentialExchangeExport -> {
|
||||||
navController.navigateToExportItemsGraph(rootNavOptions)
|
navController.navigateToExportItemsGraph(rootNavOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is RootNavState.CredentialExchangeExportSkipAccountSelection -> {
|
||||||
|
navController.navigateToVerifyPassword(
|
||||||
|
userId = currentState.userId,
|
||||||
|
navOptions = rootNavOptions,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -59,7 +59,7 @@ class RootNavViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("CyclomaticComplexMethod", "MaxLineLength", "LongMethod")
|
@Suppress("CyclomaticComplexMethod", "LongMethod")
|
||||||
private fun handleUserStateUpdateReceive(
|
private fun handleUserStateUpdateReceive(
|
||||||
action: RootNavAction.Internal.UserStateUpdateReceive,
|
action: RootNavAction.Internal.UserStateUpdateReceive,
|
||||||
) {
|
) {
|
||||||
@ -89,7 +89,13 @@ class RootNavViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
specialCircumstance is SpecialCircumstance.CredentialExchangeExport -> {
|
specialCircumstance is SpecialCircumstance.CredentialExchangeExport -> {
|
||||||
RootNavState.CredentialExchangeExport
|
if (userState.accounts.size == 1) {
|
||||||
|
RootNavState.CredentialExchangeExportSkipAccountSelection(
|
||||||
|
userId = userState.accounts.first().userId,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
RootNavState.CredentialExchangeExport
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userState.activeAccount.isVaultUnlocked &&
|
userState.activeAccount.isVaultUnlocked &&
|
||||||
@ -424,6 +430,14 @@ sealed class RootNavState : Parcelable {
|
|||||||
*/
|
*/
|
||||||
@Parcelize
|
@Parcelize
|
||||||
data object CredentialExchangeExport : RootNavState()
|
data object CredentialExchangeExport : RootNavState()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App should begin the export items flow, skipping the account selection screen.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class CredentialExchangeExportSkipAccountSelection(
|
||||||
|
val userId: String,
|
||||||
|
) : RootNavState()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -23,8 +23,12 @@ import androidx.compose.ui.text.input.KeyboardType
|
|||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.credentials.providerevents.exception.ImportCredentialsCancellationException
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import com.bitwarden.cxf.manager.CredentialExchangeCompletionManager
|
||||||
|
import com.bitwarden.cxf.manager.model.ExportCredentialsResult
|
||||||
|
import com.bitwarden.cxf.ui.composition.LocalCredentialExchangeCompletionManager
|
||||||
import com.bitwarden.ui.platform.base.util.EventsEffect
|
import com.bitwarden.ui.platform.base.util.EventsEffect
|
||||||
import com.bitwarden.ui.platform.base.util.standardHorizontalMargin
|
import com.bitwarden.ui.platform.base.util.standardHorizontalMargin
|
||||||
import com.bitwarden.ui.platform.components.button.BitwardenFilledButton
|
import com.bitwarden.ui.platform.components.button.BitwardenFilledButton
|
||||||
@ -54,6 +58,8 @@ fun VerifyPasswordScreen(
|
|||||||
onNavigateBack: () -> Unit,
|
onNavigateBack: () -> Unit,
|
||||||
onPasswordVerified: (userId: String) -> Unit,
|
onPasswordVerified: (userId: String) -> Unit,
|
||||||
viewModel: VerifyPasswordViewModel = hiltViewModel(),
|
viewModel: VerifyPasswordViewModel = hiltViewModel(),
|
||||||
|
credentialExchangeCompletionManager: CredentialExchangeCompletionManager =
|
||||||
|
LocalCredentialExchangeCompletionManager.current,
|
||||||
snackbarHostState: BitwardenSnackbarHostState = rememberBitwardenSnackbarHostState(),
|
snackbarHostState: BitwardenSnackbarHostState = rememberBitwardenSnackbarHostState(),
|
||||||
) {
|
) {
|
||||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||||
@ -63,6 +69,16 @@ fun VerifyPasswordScreen(
|
|||||||
EventsEffect(viewModel) { event ->
|
EventsEffect(viewModel) { event ->
|
||||||
when (event) {
|
when (event) {
|
||||||
VerifyPasswordEvent.NavigateBack -> onNavigateBack()
|
VerifyPasswordEvent.NavigateBack -> onNavigateBack()
|
||||||
|
VerifyPasswordEvent.CancelExport -> {
|
||||||
|
credentialExchangeCompletionManager
|
||||||
|
.completeCredentialExport(
|
||||||
|
exportResult = ExportCredentialsResult.Failure(
|
||||||
|
error = ImportCredentialsCancellationException(
|
||||||
|
errorMessage = "User cancelled import.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
is VerifyPasswordEvent.PasswordVerified -> {
|
is VerifyPasswordEvent.PasswordVerified -> {
|
||||||
onPasswordVerified(event.userId)
|
onPasswordVerified(event.userId)
|
||||||
@ -81,7 +97,11 @@ fun VerifyPasswordScreen(
|
|||||||
|
|
||||||
ExportItemsScaffold(
|
ExportItemsScaffold(
|
||||||
navIcon = rememberVectorPainter(
|
navIcon = rememberVectorPainter(
|
||||||
BitwardenDrawable.ic_back,
|
id = if (state.hasOtherAccounts) {
|
||||||
|
BitwardenDrawable.ic_back
|
||||||
|
} else {
|
||||||
|
BitwardenDrawable.ic_close
|
||||||
|
},
|
||||||
),
|
),
|
||||||
onNavigationIconClick = handler.onNavigateBackClick,
|
onNavigationIconClick = handler.onNavigateBackClick,
|
||||||
navigationIconContentDescription = stringResource(BitwardenString.back),
|
navigationIconContentDescription = stringResource(BitwardenString.back),
|
||||||
@ -263,6 +283,7 @@ private fun VerifyPasswordContent_MasterPassword_preview() {
|
|||||||
val state = VerifyPasswordState(
|
val state = VerifyPasswordState(
|
||||||
title = BitwardenString.verify_your_master_password.asText(),
|
title = BitwardenString.verify_your_master_password.asText(),
|
||||||
subtext = null,
|
subtext = null,
|
||||||
|
hasOtherAccounts = true,
|
||||||
accountSummaryListItem = accountSummaryListItem,
|
accountSummaryListItem = accountSummaryListItem,
|
||||||
)
|
)
|
||||||
ExportItemsScaffold(
|
ExportItemsScaffold(
|
||||||
@ -303,6 +324,7 @@ private fun VerifyPasswordContent_Otp_preview() {
|
|||||||
.asText(),
|
.asText(),
|
||||||
accountSummaryListItem = accountSummaryListItem,
|
accountSummaryListItem = accountSummaryListItem,
|
||||||
showResendCodeButton = true,
|
showResendCodeButton = true,
|
||||||
|
hasOtherAccounts = true,
|
||||||
)
|
)
|
||||||
ExportItemsScaffold(
|
ExportItemsScaffold(
|
||||||
navIcon = rememberVectorPainter(
|
navIcon = rememberVectorPainter(
|
||||||
|
|||||||
@ -56,6 +56,12 @@ class VerifyPasswordViewModel @Inject constructor(
|
|||||||
?.firstOrNull { it.userId == args.userId }
|
?.firstOrNull { it.userId == args.userId }
|
||||||
?: throw IllegalStateException("Account not found")
|
?: throw IllegalStateException("Account not found")
|
||||||
|
|
||||||
|
val singleAccount = authRepository
|
||||||
|
.userStateFlow
|
||||||
|
.value
|
||||||
|
?.accounts
|
||||||
|
?.size == 1
|
||||||
|
|
||||||
val restrictedItemPolicyOrgIds = policyManager
|
val restrictedItemPolicyOrgIds = policyManager
|
||||||
.getActivePolicies(PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
.getActivePolicies(PolicyTypeJson.RESTRICT_ITEM_TYPES)
|
||||||
.filter { it.isEnabled }
|
.filter { it.isEnabled }
|
||||||
@ -81,6 +87,7 @@ class VerifyPasswordViewModel @Inject constructor(
|
|||||||
.any { it.id in restrictedItemPolicyOrgIds },
|
.any { it.id in restrictedItemPolicyOrgIds },
|
||||||
),
|
),
|
||||||
showResendCodeButton = !account.hasMasterPassword,
|
showResendCodeButton = !account.hasMasterPassword,
|
||||||
|
hasOtherAccounts = !singleAccount,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
@ -138,7 +145,11 @@ class VerifyPasswordViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun handleNavigateBackClick() {
|
private fun handleNavigateBackClick() {
|
||||||
sendEvent(VerifyPasswordEvent.NavigateBack)
|
if (state.hasOtherAccounts) {
|
||||||
|
sendEvent(VerifyPasswordEvent.NavigateBack)
|
||||||
|
} else {
|
||||||
|
sendEvent(VerifyPasswordEvent.CancelExport)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleContinueClick() {
|
private fun handleContinueClick() {
|
||||||
@ -421,8 +432,10 @@ data class VerifyPasswordState(
|
|||||||
val accountSummaryListItem: AccountSelectionListItem,
|
val accountSummaryListItem: AccountSelectionListItem,
|
||||||
val title: Text,
|
val title: Text,
|
||||||
val subtext: Text?,
|
val subtext: Text?,
|
||||||
|
val hasOtherAccounts: Boolean,
|
||||||
// We never want this saved since the input is sensitive data.
|
// We never want this saved since the input is sensitive data.
|
||||||
@IgnoredOnParcel val input: String = "",
|
@IgnoredOnParcel
|
||||||
|
val input: String = "",
|
||||||
val dialog: DialogState? = null,
|
val dialog: DialogState? = null,
|
||||||
val showResendCodeButton: Boolean = false,
|
val showResendCodeButton: Boolean = false,
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
@ -475,6 +488,11 @@ sealed class VerifyPasswordEvent {
|
|||||||
*/
|
*/
|
||||||
data class PasswordVerified(val userId: String) : VerifyPasswordEvent()
|
data class PasswordVerified(val userId: String) : VerifyPasswordEvent()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel the export request.
|
||||||
|
*/
|
||||||
|
data object CancelExport : VerifyPasswordEvent()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a snackbar with the given data.
|
* Show a snackbar with the given data.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import com.x8bit.bitwarden.ui.tools.feature.send.model.SendItemType
|
|||||||
import com.x8bit.bitwarden.ui.vault.feature.addedit.VaultAddEditMode
|
import com.x8bit.bitwarden.ui.vault.feature.addedit.VaultAddEditMode
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.addedit.VaultAddEditRoute
|
import com.x8bit.bitwarden.ui.vault.feature.addedit.VaultAddEditRoute
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.exportitems.ExportItemsGraphRoute
|
import com.x8bit.bitwarden.ui.vault.feature.exportitems.ExportItemsGraphRoute
|
||||||
|
import com.x8bit.bitwarden.ui.vault.feature.exportitems.verifypassword.VerifyPasswordRoute
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.ItemListingType
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.ItemListingType
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingRoute
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingRoute
|
||||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType
|
import com.x8bit.bitwarden.ui.vault.model.VaultItemCipherType
|
||||||
@ -450,6 +451,26 @@ class RootNavScreenTest : BitwardenComposeTest() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure navigating to export items graph works as expected:
|
||||||
|
rootNavStateFlow.value = RootNavState.CredentialExchangeExportSkipAccountSelection(
|
||||||
|
userId = "activeUserId",
|
||||||
|
)
|
||||||
|
composeTestRule.runOnIdle {
|
||||||
|
verify {
|
||||||
|
mockNavHostController.navigate(
|
||||||
|
route = ExportItemsGraphRoute,
|
||||||
|
navOptions = expectedNavOptions,
|
||||||
|
)
|
||||||
|
|
||||||
|
mockNavHostController.navigate(
|
||||||
|
route = VerifyPasswordRoute(
|
||||||
|
userId = "activeUserId",
|
||||||
|
),
|
||||||
|
navOptions = expectedNavOptions,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1441,7 +1441,7 @@ class RootNavViewModelTest : BaseViewModelTest() {
|
|||||||
requestJson = "mockRequestJson",
|
requestJson = "mockRequestJson",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
mutableUserStateFlow.tryEmit(MOCK_VAULT_UNLOCKED_USER_STATE)
|
mutableUserStateFlow.tryEmit(MOCK_VAULT_UNLOCKED_USER_MULTIPLE_ACCOUNTS_STATE)
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
assertEquals(
|
assertEquals(
|
||||||
RootNavState.CredentialExchangeExport,
|
RootNavState.CredentialExchangeExport,
|
||||||
@ -1449,6 +1449,26 @@ class RootNavViewModelTest : BaseViewModelTest() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `when SpecialCircumstance is CredentialExchangeExport and only has 1 account, the nav state should be CredentialExchangeExportSkipAccountSelection`() {
|
||||||
|
specialCircumstanceManager.specialCircumstance =
|
||||||
|
SpecialCircumstance.CredentialExchangeExport(
|
||||||
|
data = ImportCredentialsRequestData(
|
||||||
|
uri = mockk(),
|
||||||
|
requestJson = "mockRequestJson",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
mutableUserStateFlow.tryEmit(MOCK_VAULT_UNLOCKED_USER_STATE)
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
assertEquals(
|
||||||
|
RootNavState.CredentialExchangeExportSkipAccountSelection(
|
||||||
|
userId = "activeUserId",
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun createViewModel(): RootNavViewModel =
|
private fun createViewModel(): RootNavViewModel =
|
||||||
RootNavViewModel(
|
RootNavViewModel(
|
||||||
authRepository = authRepository,
|
authRepository = authRepository,
|
||||||
@ -1487,3 +1507,48 @@ private val MOCK_VAULT_UNLOCKED_USER_STATE = UserState(
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val MOCK_VAULT_UNLOCKED_USER_MULTIPLE_ACCOUNTS_STATE = 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 = FirstTimeState(false),
|
||||||
|
onboardingStatus = OnboardingStatus.COMPLETE,
|
||||||
|
),
|
||||||
|
|
||||||
|
UserState.Account(
|
||||||
|
userId = "activeUserTwoId",
|
||||||
|
name = "name two",
|
||||||
|
email = "email two",
|
||||||
|
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 = FirstTimeState(false),
|
||||||
|
onboardingStatus = OnboardingStatus.COMPLETE,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|||||||
@ -297,4 +297,5 @@ private val DEFAULT_STATE = VerifyPasswordState(
|
|||||||
accountSummaryListItem = DEFAULT_ACCOUNT_SELECTION_LIST_ITEM,
|
accountSummaryListItem = DEFAULT_ACCOUNT_SELECTION_LIST_ITEM,
|
||||||
input = "",
|
input = "",
|
||||||
dialog = null,
|
dialog = null,
|
||||||
|
hasOtherAccounts = true,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -104,6 +104,7 @@ class VerifyPasswordViewModelTest : BaseViewModelTest() {
|
|||||||
initials = DEFAULT_USER_STATE.activeAccount.initials,
|
initials = DEFAULT_USER_STATE.activeAccount.initials,
|
||||||
),
|
),
|
||||||
showResendCodeButton = true,
|
showResendCodeButton = true,
|
||||||
|
hasOtherAccounts = true,
|
||||||
),
|
),
|
||||||
it.stateFlow.value,
|
it.stateFlow.value,
|
||||||
)
|
)
|
||||||
@ -119,6 +120,7 @@ class VerifyPasswordViewModelTest : BaseViewModelTest() {
|
|||||||
VerifyPasswordState(
|
VerifyPasswordState(
|
||||||
title = BitwardenString.verify_your_master_password.asText(),
|
title = BitwardenString.verify_your_master_password.asText(),
|
||||||
subtext = null,
|
subtext = null,
|
||||||
|
hasOtherAccounts = true,
|
||||||
accountSummaryListItem = AccountSelectionListItem(
|
accountSummaryListItem = AccountSelectionListItem(
|
||||||
userId = DEFAULT_USER_ID,
|
userId = DEFAULT_USER_ID,
|
||||||
email = DEFAULT_USER_STATE.activeAccount.email,
|
email = DEFAULT_USER_STATE.activeAccount.email,
|
||||||
@ -150,6 +152,7 @@ class VerifyPasswordViewModelTest : BaseViewModelTest() {
|
|||||||
VerifyPasswordState(
|
VerifyPasswordState(
|
||||||
title = BitwardenString.verify_your_master_password.asText(),
|
title = BitwardenString.verify_your_master_password.asText(),
|
||||||
subtext = null,
|
subtext = null,
|
||||||
|
hasOtherAccounts = true,
|
||||||
accountSummaryListItem = DEFAULT_ACCOUNT_SELECTION_LIST_ITEM
|
accountSummaryListItem = DEFAULT_ACCOUNT_SELECTION_LIST_ITEM
|
||||||
.copy(isItemRestricted = true),
|
.copy(isItemRestricted = true),
|
||||||
),
|
),
|
||||||
@ -285,6 +288,21 @@ class VerifyPasswordViewModelTest : BaseViewModelTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `NavigateBackClick should send CancelExport event when hasOtherAccounts is false`() =
|
||||||
|
runTest {
|
||||||
|
val initialState = DEFAULT_STATE.copy(hasOtherAccounts = false)
|
||||||
|
createViewModel(state = initialState).also {
|
||||||
|
it.trySendAction(VerifyPasswordAction.NavigateBackClick)
|
||||||
|
it.eventFlow.test {
|
||||||
|
assertEquals(
|
||||||
|
VerifyPasswordEvent.CancelExport,
|
||||||
|
awaitItem(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ContinueClick with empty input should show error dialog`() = runTest {
|
fun `ContinueClick with empty input should show error dialog`() = runTest {
|
||||||
createViewModel().also {
|
createViewModel().also {
|
||||||
@ -724,6 +742,36 @@ private val DEFAULT_USER_STATE = UserState(
|
|||||||
onboardingStatus = OnboardingStatus.COMPLETE,
|
onboardingStatus = OnboardingStatus.COMPLETE,
|
||||||
firstTimeState = FirstTimeState(showImportLoginsCard = true),
|
firstTimeState = FirstTimeState(showImportLoginsCard = true),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
UserState.Account(
|
||||||
|
userId = "activeUserId2",
|
||||||
|
name = "Active User Two",
|
||||||
|
email = "active+two@bitwarden.com",
|
||||||
|
avatarColorHex = "#aa00aa",
|
||||||
|
environment = Environment.Us,
|
||||||
|
isPremium = true,
|
||||||
|
isLoggedIn = true,
|
||||||
|
isVaultUnlocked = true,
|
||||||
|
needsPasswordReset = false,
|
||||||
|
isBiometricsEnabled = false,
|
||||||
|
organizations = listOf(
|
||||||
|
Organization(
|
||||||
|
id = DEFAULT_ORGANIZATION_ID,
|
||||||
|
name = "Organization User Two",
|
||||||
|
shouldUseKeyConnector = false,
|
||||||
|
shouldManageResetPassword = false,
|
||||||
|
role = OrganizationType.USER,
|
||||||
|
keyConnectorUrl = null,
|
||||||
|
userIsClaimedByOrganization = false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
needsMasterPassword = false,
|
||||||
|
trustedDevice = null,
|
||||||
|
hasMasterPassword = true,
|
||||||
|
isUsingKeyConnector = false,
|
||||||
|
onboardingStatus = OnboardingStatus.COMPLETE,
|
||||||
|
firstTimeState = FirstTimeState(showImportLoginsCard = true),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
private val DEFAULT_ACCOUNT_SELECTION_LIST_ITEM = AccountSelectionListItem(
|
private val DEFAULT_ACCOUNT_SELECTION_LIST_ITEM = AccountSelectionListItem(
|
||||||
@ -736,6 +784,7 @@ private val DEFAULT_ACCOUNT_SELECTION_LIST_ITEM = AccountSelectionListItem(
|
|||||||
private val DEFAULT_STATE = VerifyPasswordState(
|
private val DEFAULT_STATE = VerifyPasswordState(
|
||||||
title = BitwardenString.verify_your_master_password.asText(),
|
title = BitwardenString.verify_your_master_password.asText(),
|
||||||
subtext = null,
|
subtext = null,
|
||||||
|
hasOtherAccounts = true,
|
||||||
accountSummaryListItem = DEFAULT_ACCOUNT_SELECTION_LIST_ITEM,
|
accountSummaryListItem = DEFAULT_ACCOUNT_SELECTION_LIST_ITEM,
|
||||||
input = "",
|
input = "",
|
||||||
dialog = null,
|
dialog = null,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user