mirror of
https://github.com/bitwarden/android.git
synced 2026-06-01 10:16:47 -05:00
BIT-1133: Add account switcher to Landing Screen (#323)
This commit is contained in:
@@ -1099,7 +1099,7 @@ class AuthRepositoryTest {
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `switchAccount when the given userId is the same as the current activeUserId should do nothing`() {
|
||||
fun `switchAccount when the given userId is the same as the current activeUserId should only clear any special circumstances`() {
|
||||
val originalUserId = USER_ID_1
|
||||
val originalUserState = SINGLE_USER_STATE_1.toUserState(
|
||||
vaultState = VAULT_STATE,
|
||||
@@ -1110,6 +1110,7 @@ class AuthRepositoryTest {
|
||||
originalUserState,
|
||||
repository.userStateFlow.value,
|
||||
)
|
||||
repository.specialCircumstance = UserState.SpecialCircumstance.PendingAccountAddition
|
||||
|
||||
assertEquals(
|
||||
SwitchAccountResult.NoChange,
|
||||
@@ -1120,6 +1121,7 @@ class AuthRepositoryTest {
|
||||
originalUserState,
|
||||
repository.userStateFlow.value,
|
||||
)
|
||||
assertNull(repository.specialCircumstance)
|
||||
verify(exactly = 0) { vaultRepository.lockVaultIfNecessary(originalUserId) }
|
||||
verify(exactly = 0) { vaultRepository.clearUnlockedData() }
|
||||
}
|
||||
@@ -1154,7 +1156,7 @@ class AuthRepositoryTest {
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `switchAccount when the userId is valid should update the current UserState, lock the vault of the previous active user, and clear the previously unlocked data`() {
|
||||
fun `switchAccount when the userId is valid should update the current UserState, lock the vault of the previous active user, clear the previously unlocked data, and reset the special circumstance`() {
|
||||
val originalUserId = USER_ID_1
|
||||
val updatedUserId = USER_ID_2
|
||||
val originalUserState = MULTI_USER_STATE.toUserState(
|
||||
@@ -1166,6 +1168,7 @@ class AuthRepositoryTest {
|
||||
originalUserState,
|
||||
repository.userStateFlow.value,
|
||||
)
|
||||
repository.specialCircumstance = UserState.SpecialCircumstance.PendingAccountAddition
|
||||
|
||||
assertEquals(
|
||||
SwitchAccountResult.AccountSwitched,
|
||||
@@ -1176,6 +1179,7 @@ class AuthRepositoryTest {
|
||||
originalUserState.copy(activeUserId = updatedUserId),
|
||||
repository.userStateFlow.value,
|
||||
)
|
||||
assertNull(repository.specialCircumstance)
|
||||
verify { vaultRepository.lockVaultIfNecessary(originalUserId) }
|
||||
verify { vaultRepository.clearUnlockedData() }
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import androidx.compose.ui.test.filterToOne
|
||||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
import androidx.compose.ui.test.isDialog
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
@@ -21,6 +22,7 @@ import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
@@ -63,6 +65,58 @@ class LandingScreenTest : BaseComposeTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `account menu icon is present according to the state`() {
|
||||
composeTestRule.onNodeWithContentDescription("Account").assertDoesNotExist()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY))
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithContentDescription("Account").assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `account menu icon click should show the account switcher`() {
|
||||
mutableStateFlow.update {
|
||||
it.copy(accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY))
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithContentDescription("Account").performClick()
|
||||
|
||||
composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `account click in the account switcher should send SwitchAccountClick and close switcher`() {
|
||||
// Show the account switcher
|
||||
mutableStateFlow.update {
|
||||
it.copy(accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY))
|
||||
}
|
||||
composeTestRule.onNodeWithContentDescription("Account").performClick()
|
||||
composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed()
|
||||
|
||||
composeTestRule.onNodeWithText("active@bitwarden.com").performClick()
|
||||
|
||||
verify {
|
||||
viewModel.trySendAction(LandingAction.SwitchAccountClick(ACTIVE_ACCOUNT_SUMMARY))
|
||||
}
|
||||
composeTestRule.onNodeWithText("active@bitwarden.com").assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `add account button in the account switcher does not exist`() {
|
||||
// Show the account switcher
|
||||
mutableStateFlow.update {
|
||||
it.copy(accountSummaries = listOf(ACTIVE_ACCOUNT_SUMMARY))
|
||||
}
|
||||
composeTestRule.onNodeWithContentDescription("Account").performClick()
|
||||
composeTestRule.onNodeWithText("active@bitwarden.com").assertIsDisplayed()
|
||||
|
||||
composeTestRule.onNodeWithText("Add account").assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `continue button should be enabled or disabled according to the state`() {
|
||||
composeTestRule.onNodeWithText("Continue").assertIsEnabled()
|
||||
@@ -224,10 +278,19 @@ class LandingScreenTest : BaseComposeTest() {
|
||||
}
|
||||
}
|
||||
|
||||
private val ACTIVE_ACCOUNT_SUMMARY = AccountSummary(
|
||||
userId = "activeUserId",
|
||||
name = "Active User",
|
||||
email = "active@bitwarden.com",
|
||||
avatarColorHex = "#aa00aa",
|
||||
status = AccountSummary.Status.ACTIVE,
|
||||
)
|
||||
|
||||
private val DEFAULT_STATE = LandingState(
|
||||
emailInput = "",
|
||||
isContinueButtonEnabled = true,
|
||||
isRememberMeEnabled = false,
|
||||
selectedEnvironmentType = Environment.Type.US,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
accountSummaries = emptyList(),
|
||||
)
|
||||
|
||||
@@ -3,13 +3,16 @@ package com.x8bit.bitwarden.ui.auth.feature.landing
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.vault.feature.vault.util.toAccountSummaries
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
@@ -42,6 +45,30 @@ class LandingViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `initial state should set the account summaries based on the UserState`() {
|
||||
val userState = UserState(
|
||||
activeUserId = "activeUserId",
|
||||
accounts = listOf(
|
||||
UserState.Account(
|
||||
userId = "activeUserId",
|
||||
name = "name",
|
||||
email = "email",
|
||||
avatarColorHex = "avatarColorHex",
|
||||
isPremium = true,
|
||||
isVaultUnlocked = true,
|
||||
),
|
||||
),
|
||||
)
|
||||
val viewModel = createViewModel(userState = userState)
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
accountSummaries = userState.toAccountSummaries(),
|
||||
),
|
||||
viewModel.stateFlow.value,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `initial state should pull from saved state handle when present`() = runTest {
|
||||
val expectedState = DEFAULT_STATE.copy(
|
||||
@@ -180,10 +207,12 @@ class LandingViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private fun createViewModel(
|
||||
rememberedEmail: String? = null,
|
||||
userState: UserState? = null,
|
||||
savedStateHandle: SavedStateHandle = SavedStateHandle(),
|
||||
): LandingViewModel = LandingViewModel(
|
||||
authRepository = mockk(relaxed = true) {
|
||||
every { rememberedEmailAddress } returns rememberedEmail
|
||||
every { userStateFlow } returns MutableStateFlow(userState)
|
||||
},
|
||||
environmentRepository = fakeEnvironmentRepository,
|
||||
savedStateHandle = savedStateHandle,
|
||||
@@ -198,6 +227,7 @@ class LandingViewModelTest : BaseViewModelTest() {
|
||||
isRememberMeEnabled = false,
|
||||
selectedEnvironmentType = Environment.Type.US,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
accountSummaries = emptyList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user