mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 07:05:35 +03:00
PM-13627 show action card on vault settings if applicable (#4101)
This commit is contained in:
parent
09c11f4890
commit
c704cd2eca
4 changed files with 240 additions and 4 deletions
|
@ -1,6 +1,7 @@
|
||||||
package com.x8bit.bitwarden.ui.platform.feature.settings.vault
|
package com.x8bit.bitwarden.ui.platform.feature.settings.vault
|
||||||
|
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
@ -18,12 +19,17 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.x8bit.bitwarden.R
|
import com.x8bit.bitwarden.R
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.standardHorizontalMargin
|
||||||
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
|
import com.x8bit.bitwarden.ui.platform.components.appbar.BitwardenTopAppBar
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.badge.NotificationBadge
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.card.BitwardenActionCard
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.card.actionCardExitAnimation
|
||||||
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenExternalLinkRow
|
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenExternalLinkRow
|
||||||
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenTextRow
|
import com.x8bit.bitwarden.ui.platform.components.row.BitwardenTextRow
|
||||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||||
|
@ -90,6 +96,35 @@ fun VaultSettingsScreen(
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(rememberScrollState()),
|
.verticalScroll(rememberScrollState()),
|
||||||
) {
|
) {
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = state.shouldShowImportCard,
|
||||||
|
label = "ImportLoginsActionCard",
|
||||||
|
exit = actionCardExitAnimation(),
|
||||||
|
) {
|
||||||
|
BitwardenActionCard(
|
||||||
|
cardTitle = stringResource(id = R.string.import_saved_logins),
|
||||||
|
actionText = stringResource(R.string.get_started),
|
||||||
|
cardSubtitle = stringResource(R.string.use_a_computer_to_import_logins),
|
||||||
|
onActionClick = remember(viewModel) {
|
||||||
|
{
|
||||||
|
viewModel.trySendAction(VaultSettingsAction.ImportLoginsCardCtaClick)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onDismissClick = remember(viewModel) {
|
||||||
|
{
|
||||||
|
viewModel.trySendAction(
|
||||||
|
VaultSettingsAction.ImportLoginsCardDismissClick,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
NotificationBadge(notificationCount = 1)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.standardHorizontalMargin()
|
||||||
|
.padding(top = 12.dp, bottom = 16.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
BitwardenTextRow(
|
BitwardenTextRow(
|
||||||
text = stringResource(R.string.folders),
|
text = stringResource(R.string.folders),
|
||||||
onClick = remember(viewModel) {
|
onClick = remember(viewModel) {
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
package com.x8bit.bitwarden.ui.platform.feature.settings.vault
|
package com.x8bit.bitwarden.ui.platform.feature.settings.vault
|
||||||
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||||
import com.x8bit.bitwarden.data.platform.repository.util.toBaseWebVaultImportUrl
|
import com.x8bit.bitwarden.data.platform.repository.util.toBaseWebVaultImportUrl
|
||||||
|
@ -16,12 +18,16 @@ import javax.inject.Inject
|
||||||
/**
|
/**
|
||||||
* View model for the vault screen.
|
* View model for the vault screen.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("TooManyFunctions")
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class VaultSettingsViewModel @Inject constructor(
|
class VaultSettingsViewModel @Inject constructor(
|
||||||
environmentRepository: EnvironmentRepository,
|
environmentRepository: EnvironmentRepository,
|
||||||
val featureFlagManager: FeatureFlagManager,
|
featureFlagManager: FeatureFlagManager,
|
||||||
|
private val authRepository: AuthRepository,
|
||||||
|
private val firstTimeActionManager: FirstTimeActionManager,
|
||||||
) : BaseViewModel<VaultSettingsState, VaultSettingsEvent, VaultSettingsAction>(
|
) : BaseViewModel<VaultSettingsState, VaultSettingsEvent, VaultSettingsAction>(
|
||||||
initialState = run {
|
initialState = run {
|
||||||
|
val firstTimeState = firstTimeActionManager.currentOrDefaultUserFirstTimeState
|
||||||
VaultSettingsState(
|
VaultSettingsState(
|
||||||
importUrl = environmentRepository
|
importUrl = environmentRepository
|
||||||
.environment
|
.environment
|
||||||
|
@ -29,6 +35,7 @@ class VaultSettingsViewModel @Inject constructor(
|
||||||
.toBaseWebVaultImportUrl,
|
.toBaseWebVaultImportUrl,
|
||||||
isNewImportLoginsFlowEnabled = featureFlagManager
|
isNewImportLoginsFlowEnabled = featureFlagManager
|
||||||
.getFeatureFlag(FlagKey.ImportLoginsFlow),
|
.getFeatureFlag(FlagKey.ImportLoginsFlow),
|
||||||
|
showImportActionCard = firstTimeState.showImportLoginsCard,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
|
@ -38,6 +45,16 @@ class VaultSettingsViewModel @Inject constructor(
|
||||||
.map { VaultSettingsAction.Internal.ImportLoginsFeatureFlagChanged(it) }
|
.map { VaultSettingsAction.Internal.ImportLoginsFeatureFlagChanged(it) }
|
||||||
.onEach(::sendAction)
|
.onEach(::sendAction)
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
|
||||||
|
firstTimeActionManager
|
||||||
|
.firstTimeStateFlow
|
||||||
|
.map {
|
||||||
|
VaultSettingsAction.Internal.UserFirstTimeStateChanged(
|
||||||
|
showImportLoginsCard = it.showImportLoginsCard,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.onEach(::sendAction)
|
||||||
|
.launchIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleAction(action: VaultSettingsAction): Unit = when (action) {
|
override fun handleAction(action: VaultSettingsAction): Unit = when (action) {
|
||||||
|
@ -45,9 +62,38 @@ class VaultSettingsViewModel @Inject constructor(
|
||||||
VaultSettingsAction.ExportVaultClick -> handleExportVaultClicked()
|
VaultSettingsAction.ExportVaultClick -> handleExportVaultClicked()
|
||||||
VaultSettingsAction.FoldersButtonClick -> handleFoldersButtonClicked()
|
VaultSettingsAction.FoldersButtonClick -> handleFoldersButtonClicked()
|
||||||
VaultSettingsAction.ImportItemsClick -> handleImportItemsClicked()
|
VaultSettingsAction.ImportItemsClick -> handleImportItemsClicked()
|
||||||
|
VaultSettingsAction.ImportLoginsCardCtaClick -> handleImportLoginsCardClicked()
|
||||||
|
VaultSettingsAction.ImportLoginsCardDismissClick -> handleImportLoginsCardDismissClicked()
|
||||||
|
is VaultSettingsAction.Internal -> handleInternalAction(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleInternalAction(action: VaultSettingsAction.Internal) {
|
||||||
|
when (action) {
|
||||||
is VaultSettingsAction.Internal.ImportLoginsFeatureFlagChanged -> {
|
is VaultSettingsAction.Internal.ImportLoginsFeatureFlagChanged -> {
|
||||||
handleImportLoginsFeatureFlagChanged(action)
|
handleImportLoginsFeatureFlagChanged(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is VaultSettingsAction.Internal.UserFirstTimeStateChanged -> {
|
||||||
|
handleUserFirstTimeStateChanged(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleImportLoginsCardDismissClicked() {
|
||||||
|
dismissImportLoginsCard()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleImportLoginsCardClicked() {
|
||||||
|
dismissImportLoginsCard()
|
||||||
|
sendEvent(VaultSettingsEvent.NavigateToImportVault(state.importUrl))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleUserFirstTimeStateChanged(
|
||||||
|
action: VaultSettingsAction.Internal.UserFirstTimeStateChanged,
|
||||||
|
) {
|
||||||
|
mutableStateFlow.update {
|
||||||
|
it.copy(showImportActionCard = action.showImportLoginsCard)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleImportLoginsFeatureFlagChanged(
|
private fun handleImportLoginsFeatureFlagChanged(
|
||||||
|
@ -75,6 +121,11 @@ class VaultSettingsViewModel @Inject constructor(
|
||||||
VaultSettingsEvent.NavigateToImportVault(state.importUrl),
|
VaultSettingsEvent.NavigateToImportVault(state.importUrl),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun dismissImportLoginsCard() {
|
||||||
|
if (!state.shouldShowImportCard) return
|
||||||
|
authRepository.setShowImportLogins(showImportLogins = false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,7 +134,14 @@ class VaultSettingsViewModel @Inject constructor(
|
||||||
data class VaultSettingsState(
|
data class VaultSettingsState(
|
||||||
val importUrl: String,
|
val importUrl: String,
|
||||||
val isNewImportLoginsFlowEnabled: Boolean,
|
val isNewImportLoginsFlowEnabled: Boolean,
|
||||||
)
|
private val showImportActionCard: Boolean,
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Should only show the import action card if the import logins feature flag is enabled.
|
||||||
|
*/
|
||||||
|
val shouldShowImportCard: Boolean
|
||||||
|
get() = showImportActionCard && isNewImportLoginsFlowEnabled
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models events for the vault screen.
|
* Models events for the vault screen.
|
||||||
|
@ -141,6 +199,16 @@ sealed class VaultSettingsAction {
|
||||||
*/
|
*/
|
||||||
data object ImportItemsClick : VaultSettingsAction()
|
data object ImportItemsClick : VaultSettingsAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the user clicked the CTA on the action card.
|
||||||
|
*/
|
||||||
|
data object ImportLoginsCardCtaClick : VaultSettingsAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the user dismissed the action card.
|
||||||
|
*/
|
||||||
|
data object ImportLoginsCardDismissClick : VaultSettingsAction()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal actions not performed by user interation
|
* Internal actions not performed by user interation
|
||||||
*/
|
*/
|
||||||
|
@ -152,5 +220,12 @@ sealed class VaultSettingsAction {
|
||||||
data class ImportLoginsFeatureFlagChanged(
|
data class ImportLoginsFeatureFlagChanged(
|
||||||
val isEnabled: Boolean,
|
val isEnabled: Boolean,
|
||||||
) : Internal()
|
) : Internal()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates user first time state has changed.
|
||||||
|
*/
|
||||||
|
data class UserFirstTimeStateChanged(
|
||||||
|
val showImportLoginsCard: Boolean,
|
||||||
|
) : Internal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import androidx.compose.ui.test.isDialog
|
||||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
|
import androidx.compose.ui.test.performScrollTo
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||||
|
@ -34,6 +35,7 @@ class VaultSettingsScreenTest : BaseComposeTest() {
|
||||||
VaultSettingsState(
|
VaultSettingsState(
|
||||||
importUrl = "testUrl/#/tools/import",
|
importUrl = "testUrl/#/tools/import",
|
||||||
isNewImportLoginsFlowEnabled = false,
|
isNewImportLoginsFlowEnabled = false,
|
||||||
|
showImportActionCard = false,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
private val intentManager: IntentManager = mockk(relaxed = true) {
|
private val intentManager: IntentManager = mockk(relaxed = true) {
|
||||||
|
@ -157,4 +159,58 @@ class VaultSettingsScreenTest : BaseComposeTest() {
|
||||||
assertTrue(onNavigateToImportLoginsCalled)
|
assertTrue(onNavigateToImportLoginsCalled)
|
||||||
verify(exactly = 0) { intentManager.launchUri(testUrl.toUri()) }
|
verify(exactly = 0) { intentManager.launchUri(testUrl.toUri()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when new show action card is true the import logins card should show`() {
|
||||||
|
mutableStateFlow.update {
|
||||||
|
it.copy(
|
||||||
|
showImportActionCard = true,
|
||||||
|
isNewImportLoginsFlowEnabled = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
composeTestRule
|
||||||
|
.onNodeWithText("Import saved logins")
|
||||||
|
.performScrollTo()
|
||||||
|
.assertIsDisplayed()
|
||||||
|
mutableStateFlow.update {
|
||||||
|
it.copy(showImportActionCard = false)
|
||||||
|
}
|
||||||
|
composeTestRule
|
||||||
|
.onNodeWithText("Import saved logins")
|
||||||
|
.assertDoesNotExist()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when action card is visible clicking the close icon should send correct action`() {
|
||||||
|
mutableStateFlow.update {
|
||||||
|
it.copy(
|
||||||
|
showImportActionCard = true,
|
||||||
|
isNewImportLoginsFlowEnabled = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
composeTestRule
|
||||||
|
.onNodeWithContentDescription("Close")
|
||||||
|
.performScrollTo()
|
||||||
|
.performClick()
|
||||||
|
verify {
|
||||||
|
viewModel.trySendAction(VaultSettingsAction.ImportLoginsCardDismissClick)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when action card is visible get started button should send correct action`() {
|
||||||
|
mutableStateFlow.update {
|
||||||
|
it.copy(
|
||||||
|
showImportActionCard = true,
|
||||||
|
isNewImportLoginsFlowEnabled = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
composeTestRule
|
||||||
|
.onNodeWithText("Get started")
|
||||||
|
.performScrollTo()
|
||||||
|
.performClick()
|
||||||
|
verify {
|
||||||
|
viewModel.trySendAction(VaultSettingsAction.ImportLoginsCardCtaClick)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
package com.x8bit.bitwarden.ui.platform.feature.settings.vault
|
package com.x8bit.bitwarden.ui.platform.feature.settings.vault
|
||||||
|
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.FirstTimeActionManager
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
|
||||||
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
import com.x8bit.bitwarden.data.platform.repository.util.FakeEnvironmentRepository
|
||||||
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
|
||||||
|
@ -22,6 +28,14 @@ class VaultSettingsViewModelTest : BaseViewModelTest() {
|
||||||
every { getFeatureFlagFlow(FlagKey.ImportLoginsFlow) } returns mutableImportLoginsFlagFlow
|
every { getFeatureFlagFlow(FlagKey.ImportLoginsFlow) } returns mutableImportLoginsFlagFlow
|
||||||
every { getFeatureFlag(FlagKey.ImportLoginsFlow) } returns false
|
every { getFeatureFlag(FlagKey.ImportLoginsFlow) } returns false
|
||||||
}
|
}
|
||||||
|
private val authRepository = mockk<AuthRepository> {
|
||||||
|
every { setShowImportLogins(any()) } just runs
|
||||||
|
}
|
||||||
|
private val mutableFirstTimeStateFlow = MutableStateFlow(DEFAULT_FIRST_TIME_STATE)
|
||||||
|
private val firstTimeActionManager = mockk<FirstTimeActionManager> {
|
||||||
|
every { currentOrDefaultUserFirstTimeState } returns DEFAULT_FIRST_TIME_STATE
|
||||||
|
every { firstTimeStateFlow } returns mutableFirstTimeStateFlow
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `BackClick should emit NavigateBack`() = runTest {
|
fun `BackClick should emit NavigateBack`() = runTest {
|
||||||
|
@ -67,8 +81,64 @@ class VaultSettingsViewModelTest : BaseViewModelTest() {
|
||||||
assertTrue(viewModel.stateFlow.value.isNewImportLoginsFlowEnabled)
|
assertTrue(viewModel.stateFlow.value.isNewImportLoginsFlowEnabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `shouldShowImportCard should update when first time state changes`() = runTest {
|
||||||
|
mutableImportLoginsFlagFlow.update { true }
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
assertTrue(viewModel.stateFlow.value.shouldShowImportCard)
|
||||||
|
mutableFirstTimeStateFlow.update {
|
||||||
|
it.copy(showImportLoginsCard = false)
|
||||||
|
}
|
||||||
|
assertFalse(viewModel.stateFlow.value.shouldShowImportCard)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `shouldShowImportCard should be false when feature flag not enabled`() = runTest {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
mutableImportLoginsFlagFlow.update { false }
|
||||||
|
assertFalse(viewModel.stateFlow.value.shouldShowImportCard)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `ImportLoginsCardCtaClick action should set repository value to false and send navigation event`() =
|
||||||
|
runTest {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
val expected = "https://vault.bitwarden.com/#/tools/import"
|
||||||
|
mutableImportLoginsFlagFlow.update { true }
|
||||||
|
viewModel.eventFlow.test {
|
||||||
|
viewModel.trySendAction(VaultSettingsAction.ImportLoginsCardCtaClick)
|
||||||
|
assertEquals(
|
||||||
|
VaultSettingsEvent.NavigateToImportVault(url = expected),
|
||||||
|
awaitItem(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
verify(exactly = 1) { authRepository.setShowImportLogins(false) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ImportLoginsCardDismissClick action should set repository value to false `() = runTest {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
mutableImportLoginsFlagFlow.update { true }
|
||||||
|
viewModel.trySendAction(VaultSettingsAction.ImportLoginsCardDismissClick)
|
||||||
|
verify(exactly = 1) { authRepository.setShowImportLogins(false) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `ImportLoginsCardDismissClick action should not set repository value to false if already false`() =
|
||||||
|
runTest {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
viewModel.trySendAction(VaultSettingsAction.ImportLoginsCardDismissClick)
|
||||||
|
verify(exactly = 0) { authRepository.setShowImportLogins(false) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun createViewModel(): VaultSettingsViewModel = VaultSettingsViewModel(
|
private fun createViewModel(): VaultSettingsViewModel = VaultSettingsViewModel(
|
||||||
environmentRepository = environmentRepository,
|
environmentRepository = environmentRepository,
|
||||||
featureFlagManager = featureFlagManager,
|
featureFlagManager = featureFlagManager,
|
||||||
|
authRepository = authRepository,
|
||||||
|
firstTimeActionManager = firstTimeActionManager,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val DEFAULT_FIRST_TIME_STATE = FirstTimeState(showImportLoginsCard = true)
|
||||||
|
|
Loading…
Reference in a new issue