mirror of
https://github.com/bitwarden/android.git
synced 2026-04-29 20:38:41 -05:00
PM-23354: Replace Login Approval toasts with snackbar (#5478)
This commit is contained in:
@@ -15,6 +15,9 @@ import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestUpdatesResult
|
|||||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||||
|
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelay
|
||||||
|
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
@@ -36,6 +39,7 @@ class LoginApprovalViewModel @Inject constructor(
|
|||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
private val authRepository: AuthRepository,
|
private val authRepository: AuthRepository,
|
||||||
private val specialCircumstanceManager: SpecialCircumstanceManager,
|
private val specialCircumstanceManager: SpecialCircumstanceManager,
|
||||||
|
private val snackbarRelayManager: SnackbarRelayManager,
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
) : BaseViewModel<LoginApprovalState, LoginApprovalEvent, LoginApprovalAction>(
|
) : BaseViewModel<LoginApprovalState, LoginApprovalEvent, LoginApprovalAction>(
|
||||||
initialState = savedStateHandle[KEY_STATE]
|
initialState = savedStateHandle[KEY_STATE]
|
||||||
@@ -182,8 +186,7 @@ class LoginApprovalViewModel @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
when (val result = action.result) {
|
when (val result = action.result) {
|
||||||
is AuthRequestResult.Success -> {
|
is AuthRequestResult.Success -> {
|
||||||
sendEvent(LoginApprovalEvent.ShowToast(R.string.login_approved.asText()))
|
sendClosingEvent(message = R.string.login_approved.asText())
|
||||||
sendClosingEvent()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is AuthRequestResult.Error -> {
|
is AuthRequestResult.Error -> {
|
||||||
@@ -246,8 +249,7 @@ class LoginApprovalViewModel @Inject constructor(
|
|||||||
) {
|
) {
|
||||||
when (val result = action.result) {
|
when (val result = action.result) {
|
||||||
is AuthRequestResult.Success -> {
|
is AuthRequestResult.Success -> {
|
||||||
sendEvent(LoginApprovalEvent.ShowToast(R.string.log_in_denied.asText()))
|
sendClosingEvent(message = R.string.log_in_denied.asText())
|
||||||
sendClosingEvent()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
is AuthRequestResult.Error -> {
|
is AuthRequestResult.Error -> {
|
||||||
@@ -264,14 +266,26 @@ class LoginApprovalViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendClosingEvent() {
|
private fun sendClosingEvent(message: Text? = null) {
|
||||||
val event = if (state.specialCircumstance?.shouldFinishWhenComplete == true) {
|
val shouldFinishWhenComplete = state.specialCircumstance?.shouldFinishWhenComplete == true
|
||||||
LoginApprovalEvent.ExitApp
|
message?.let {
|
||||||
} else {
|
if (shouldFinishWhenComplete) {
|
||||||
LoginApprovalEvent.NavigateBack
|
// We are about to exit the app, so we need to use a Toast here.
|
||||||
|
sendEvent(LoginApprovalEvent.ShowToast(it))
|
||||||
|
} else {
|
||||||
|
snackbarRelayManager.sendSnackbarData(
|
||||||
|
data = BitwardenSnackbarData(message = it),
|
||||||
|
relay = SnackbarRelay.LOGIN_APPROVAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
sendEvent(
|
||||||
sendEvent(event)
|
event = if (shouldFinishWhenComplete) {
|
||||||
|
LoginApprovalEvent.ExitApp
|
||||||
|
} else {
|
||||||
|
LoginApprovalEvent.NavigateBack
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ import com.x8bit.bitwarden.ui.platform.components.content.BitwardenLoadingConten
|
|||||||
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
|
import com.x8bit.bitwarden.ui.platform.components.dialog.BitwardenTwoButtonDialog
|
||||||
import com.x8bit.bitwarden.ui.platform.components.model.rememberBitwardenPullToRefreshState
|
import com.x8bit.bitwarden.ui.platform.components.model.rememberBitwardenPullToRefreshState
|
||||||
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
import com.x8bit.bitwarden.ui.platform.components.scaffold.BitwardenScaffold
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarHost
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.rememberBitwardenSnackbarHostState
|
||||||
import com.x8bit.bitwarden.ui.platform.composition.LocalPermissionsManager
|
import com.x8bit.bitwarden.ui.platform.composition.LocalPermissionsManager
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager
|
import com.x8bit.bitwarden.ui.platform.manager.permissions.PermissionsManager
|
||||||
|
|
||||||
@@ -84,12 +86,15 @@ fun PendingRequestsScreen(
|
|||||||
{ viewModel.trySendAction(PendingRequestsAction.RefreshPull) }
|
{ viewModel.trySendAction(PendingRequestsAction.RefreshPull) }
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
val snackbarHostState = rememberBitwardenSnackbarHostState()
|
||||||
EventsEffect(viewModel = viewModel) { event ->
|
EventsEffect(viewModel = viewModel) { event ->
|
||||||
when (event) {
|
when (event) {
|
||||||
PendingRequestsEvent.NavigateBack -> onNavigateBack()
|
PendingRequestsEvent.NavigateBack -> onNavigateBack()
|
||||||
is PendingRequestsEvent.NavigateToLoginApproval -> {
|
is PendingRequestsEvent.NavigateToLoginApproval -> {
|
||||||
onNavigateToLoginApproval(event.fingerprint)
|
onNavigateToLoginApproval(event.fingerprint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is PendingRequestsEvent.ShowSnackbar -> snackbarHostState.showSnackbar(event.data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +147,9 @@ fun PendingRequestsScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
pullToRefreshState = pullToRefreshState,
|
pullToRefreshState = pullToRefreshState,
|
||||||
|
snackbarHost = {
|
||||||
|
BitwardenSnackbarHost(bitwardenHostState = snackbarHostState)
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
when (val viewState = state.viewState) {
|
when (val viewState = state.viewState) {
|
||||||
is PendingRequestsState.ViewState.Content -> {
|
is PendingRequestsState.ViewState.Content -> {
|
||||||
|
|||||||
@@ -5,11 +5,15 @@ import androidx.lifecycle.SavedStateHandle
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
import com.bitwarden.core.data.util.toFormattedDateTimeStyle
|
||||||
import com.bitwarden.core.util.isOverFiveMinutesOld
|
import com.bitwarden.core.util.isOverFiveMinutesOld
|
||||||
|
import com.bitwarden.ui.platform.base.BackgroundEvent
|
||||||
import com.bitwarden.ui.platform.base.BaseViewModel
|
import com.bitwarden.ui.platform.base.BaseViewModel
|
||||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
||||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsUpdatesResult
|
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsUpdatesResult
|
||||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||||
|
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelay
|
||||||
|
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
@@ -32,6 +36,7 @@ private const val KEY_STATE = "state"
|
|||||||
class PendingRequestsViewModel @Inject constructor(
|
class PendingRequestsViewModel @Inject constructor(
|
||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
private val authRepository: AuthRepository,
|
private val authRepository: AuthRepository,
|
||||||
|
snackbarRelayManager: SnackbarRelayManager,
|
||||||
settingsRepository: SettingsRepository,
|
settingsRepository: SettingsRepository,
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
) : BaseViewModel<PendingRequestsState, PendingRequestsEvent, PendingRequestsAction>(
|
) : BaseViewModel<PendingRequestsState, PendingRequestsEvent, PendingRequestsAction>(
|
||||||
@@ -52,6 +57,11 @@ class PendingRequestsViewModel @Inject constructor(
|
|||||||
.map { PendingRequestsAction.Internal.PullToRefreshEnableReceive(it) }
|
.map { PendingRequestsAction.Internal.PullToRefreshEnableReceive(it) }
|
||||||
.onEach(::sendAction)
|
.onEach(::sendAction)
|
||||||
.launchIn(viewModelScope)
|
.launchIn(viewModelScope)
|
||||||
|
snackbarRelayManager
|
||||||
|
.getSnackbarDataFlow(SnackbarRelay.LOGIN_APPROVAL)
|
||||||
|
.map { PendingRequestsAction.Internal.SnackbarDataReceive(it) }
|
||||||
|
.onEach(::sendAction)
|
||||||
|
.launchIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleAction(action: PendingRequestsAction) {
|
override fun handleAction(action: PendingRequestsAction) {
|
||||||
@@ -117,6 +127,10 @@ class PendingRequestsViewModel @Inject constructor(
|
|||||||
handlePullToRefreshEnableReceive(action)
|
handlePullToRefreshEnableReceive(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is PendingRequestsAction.Internal.SnackbarDataReceive -> {
|
||||||
|
handleSnackbarDataReceive(action)
|
||||||
|
}
|
||||||
|
|
||||||
is PendingRequestsAction.Internal.AuthRequestsResultReceive -> {
|
is PendingRequestsAction.Internal.AuthRequestsResultReceive -> {
|
||||||
handleAuthRequestsResultReceived(action)
|
handleAuthRequestsResultReceived(action)
|
||||||
}
|
}
|
||||||
@@ -131,6 +145,12 @@ class PendingRequestsViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleSnackbarDataReceive(
|
||||||
|
action: PendingRequestsAction.Internal.SnackbarDataReceive,
|
||||||
|
) {
|
||||||
|
sendEvent(PendingRequestsEvent.ShowSnackbar(action.data))
|
||||||
|
}
|
||||||
|
|
||||||
private fun handleAuthRequestsResultReceived(
|
private fun handleAuthRequestsResultReceived(
|
||||||
action: PendingRequestsAction.Internal.AuthRequestsResultReceive,
|
action: PendingRequestsAction.Internal.AuthRequestsResultReceive,
|
||||||
) {
|
) {
|
||||||
@@ -282,6 +302,13 @@ sealed class PendingRequestsEvent {
|
|||||||
data class NavigateToLoginApproval(
|
data class NavigateToLoginApproval(
|
||||||
val fingerprint: String,
|
val fingerprint: String,
|
||||||
) : PendingRequestsEvent()
|
) : PendingRequestsEvent()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a snackbar to the user.
|
||||||
|
*/
|
||||||
|
data class ShowSnackbar(
|
||||||
|
val data: BitwardenSnackbarData,
|
||||||
|
) : PendingRequestsEvent(), BackgroundEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -332,6 +359,13 @@ sealed class PendingRequestsAction {
|
|||||||
val isPullToRefreshEnabled: Boolean,
|
val isPullToRefreshEnabled: Boolean,
|
||||||
) : Internal()
|
) : Internal()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that a snackbar data was received.
|
||||||
|
*/
|
||||||
|
data class SnackbarDataReceive(
|
||||||
|
val data: BitwardenSnackbarData,
|
||||||
|
) : Internal()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that a new auth requests result has been received.
|
* Indicates that a new auth requests result has been received.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import kotlinx.serialization.Serializable
|
|||||||
enum class SnackbarRelay {
|
enum class SnackbarRelay {
|
||||||
CIPHER_DELETED,
|
CIPHER_DELETED,
|
||||||
CIPHER_RESTORED,
|
CIPHER_RESTORED,
|
||||||
|
LOGIN_APPROVAL,
|
||||||
LOGINS_IMPORTED,
|
LOGINS_IMPORTED,
|
||||||
SEND_DELETED,
|
SEND_DELETED,
|
||||||
SEND_UPDATED,
|
SEND_UPDATED,
|
||||||
|
|||||||
@@ -18,11 +18,16 @@ import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
|||||||
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
import com.x8bit.bitwarden.data.platform.manager.model.FirstTimeState
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.PasswordlessRequestData
|
import com.x8bit.bitwarden.data.platform.manager.model.PasswordlessRequestData
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||||
|
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelay
|
||||||
|
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.mockkStatic
|
import io.mockk.mockkStatic
|
||||||
|
import io.mockk.runs
|
||||||
import io.mockk.unmockkStatic
|
import io.mockk.unmockkStatic
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@@ -55,6 +60,9 @@ class LoginApprovalViewModelTest : BaseViewModelTest() {
|
|||||||
coEvery { getAuthRequestByIdFlow(REQUEST_ID) } returns mutableAuthRequestSharedFlow
|
coEvery { getAuthRequestByIdFlow(REQUEST_ID) } returns mutableAuthRequestSharedFlow
|
||||||
every { userStateFlow } returns mutableUserStateFlow
|
every { userStateFlow } returns mutableUserStateFlow
|
||||||
}
|
}
|
||||||
|
private val snackbarRelayManager: SnackbarRelayManager = mockk {
|
||||||
|
every { sendSnackbarData(data = any(), relay = SnackbarRelay.LOGIN_APPROVAL) } just runs
|
||||||
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun setup() {
|
fun setup() {
|
||||||
@@ -270,13 +278,15 @@ class LoginApprovalViewModelTest : BaseViewModelTest() {
|
|||||||
|
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.trySendAction(LoginApprovalAction.ApproveRequestClick)
|
viewModel.trySendAction(LoginApprovalAction.ApproveRequestClick)
|
||||||
assertEquals(
|
|
||||||
LoginApprovalEvent.ShowToast(R.string.login_approved.asText()),
|
|
||||||
awaitItem(),
|
|
||||||
)
|
|
||||||
assertEquals(LoginApprovalEvent.NavigateBack, awaitItem())
|
assertEquals(LoginApprovalEvent.NavigateBack, awaitItem())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
verify {
|
||||||
|
snackbarRelayManager.sendSnackbarData(
|
||||||
|
data = BitwardenSnackbarData(message = R.string.login_approved.asText()),
|
||||||
|
relay = SnackbarRelay.LOGIN_APPROVAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
coVerify {
|
coVerify {
|
||||||
mockAuthRepository.updateAuthRequest(
|
mockAuthRepository.updateAuthRequest(
|
||||||
requestId = REQUEST_ID,
|
requestId = REQUEST_ID,
|
||||||
@@ -339,13 +349,14 @@ class LoginApprovalViewModelTest : BaseViewModelTest() {
|
|||||||
|
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.trySendAction(LoginApprovalAction.DeclineRequestClick)
|
viewModel.trySendAction(LoginApprovalAction.DeclineRequestClick)
|
||||||
assertEquals(
|
|
||||||
LoginApprovalEvent.ShowToast(R.string.log_in_denied.asText()),
|
|
||||||
awaitItem(),
|
|
||||||
)
|
|
||||||
assertEquals(LoginApprovalEvent.NavigateBack, awaitItem())
|
assertEquals(LoginApprovalEvent.NavigateBack, awaitItem())
|
||||||
}
|
}
|
||||||
|
verify {
|
||||||
|
snackbarRelayManager.sendSnackbarData(
|
||||||
|
data = BitwardenSnackbarData(message = R.string.log_in_denied.asText()),
|
||||||
|
relay = SnackbarRelay.LOGIN_APPROVAL,
|
||||||
|
)
|
||||||
|
}
|
||||||
coVerify {
|
coVerify {
|
||||||
mockAuthRepository.updateAuthRequest(
|
mockAuthRepository.updateAuthRequest(
|
||||||
requestId = REQUEST_ID,
|
requestId = REQUEST_ID,
|
||||||
@@ -429,6 +440,7 @@ class LoginApprovalViewModelTest : BaseViewModelTest() {
|
|||||||
clock = fixedClock,
|
clock = fixedClock,
|
||||||
authRepository = mockAuthRepository,
|
authRepository = mockAuthRepository,
|
||||||
specialCircumstanceManager = mockSpecialCircumstanceManager,
|
specialCircumstanceManager = mockSpecialCircumstanceManager,
|
||||||
|
snackbarRelayManager = snackbarRelayManager,
|
||||||
savedStateHandle = SavedStateHandle().apply {
|
savedStateHandle = SavedStateHandle().apply {
|
||||||
set("state", state)
|
set("state", state)
|
||||||
every { toLoginApprovalArgs() } returns LoginApprovalArgs(fingerprint = FINGERPRINT)
|
every { toLoginApprovalArgs() } returns LoginApprovalArgs(fingerprint = FINGERPRINT)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.pending
|
|||||||
|
|
||||||
import androidx.compose.ui.semantics.SemanticsActions
|
import androidx.compose.ui.semantics.SemanticsActions
|
||||||
import androidx.compose.ui.test.assert
|
import androidx.compose.ui.test.assert
|
||||||
|
import androidx.compose.ui.test.assertIsDisplayed
|
||||||
import androidx.compose.ui.test.filterToOne
|
import androidx.compose.ui.test.filterToOne
|
||||||
import androidx.compose.ui.test.hasAnyAncestor
|
import androidx.compose.ui.test.hasAnyAncestor
|
||||||
import androidx.compose.ui.test.hasClickAction
|
import androidx.compose.ui.test.hasClickAction
|
||||||
@@ -13,10 +14,12 @@ import androidx.compose.ui.test.performScrollTo
|
|||||||
import androidx.compose.ui.test.performSemanticsAction
|
import androidx.compose.ui.test.performSemanticsAction
|
||||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||||
import com.bitwarden.core.util.isBuildVersionAtLeast
|
import com.bitwarden.core.util.isBuildVersionAtLeast
|
||||||
|
import com.bitwarden.ui.util.asText
|
||||||
import com.bitwarden.ui.util.assertNoDialogExists
|
import com.bitwarden.ui.util.assertNoDialogExists
|
||||||
import com.x8bit.bitwarden.data.platform.util.isFdroid
|
import com.x8bit.bitwarden.data.platform.util.isFdroid
|
||||||
import com.x8bit.bitwarden.data.util.advanceTimeByAndRunCurrent
|
import com.x8bit.bitwarden.data.util.advanceTimeByAndRunCurrent
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BitwardenComposeTest
|
import com.x8bit.bitwarden.ui.platform.base.BitwardenComposeTest
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.permissions.FakePermissionManager
|
import com.x8bit.bitwarden.ui.platform.manager.permissions.FakePermissionManager
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.just
|
import io.mockk.just
|
||||||
@@ -72,6 +75,15 @@ class PendingRequestsScreenTest : BitwardenComposeTest() {
|
|||||||
unmockkStatic(::isBuildVersionAtLeast)
|
unmockkStatic(::isBuildVersionAtLeast)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `on ShowSnackbar should display snackbar content`() {
|
||||||
|
val message = "message"
|
||||||
|
val data = BitwardenSnackbarData(message = message.asText())
|
||||||
|
composeTestRule.onNodeWithText(text = message).assertDoesNotExist()
|
||||||
|
mutableEventFlow.tryEmit(PendingRequestsEvent.ShowSnackbar(data = data))
|
||||||
|
composeTestRule.onNodeWithText(text = message).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on NavigateBack should call onNavigateBack`() {
|
fun `on NavigateBack should call onNavigateBack`() {
|
||||||
mutableEventFlow.tryEmit(PendingRequestsEvent.NavigateBack)
|
mutableEventFlow.tryEmit(PendingRequestsEvent.NavigateBack)
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ import androidx.lifecycle.SavedStateHandle
|
|||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
|
||||||
import com.bitwarden.ui.platform.base.BaseViewModelTest
|
import com.bitwarden.ui.platform.base.BaseViewModelTest
|
||||||
|
import com.bitwarden.ui.util.asText
|
||||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequest
|
||||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestResult
|
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestResult
|
||||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsResult
|
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsResult
|
||||||
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsUpdatesResult
|
import com.x8bit.bitwarden.data.auth.manager.model.AuthRequestsUpdatesResult
|
||||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.snackbar.BitwardenSnackbarData
|
||||||
|
import com.x8bit.bitwarden.ui.platform.manager.snackbar.SnackbarRelayManager
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
import io.mockk.coVerify
|
import io.mockk.coVerify
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
@@ -40,6 +43,12 @@ class PendingRequestsViewModelTest : BaseViewModelTest() {
|
|||||||
private val settingsRepository = mockk<SettingsRepository> {
|
private val settingsRepository = mockk<SettingsRepository> {
|
||||||
every { getPullToRefreshEnabledFlow() } returns mutablePullToRefreshStateFlow
|
every { getPullToRefreshEnabledFlow() } returns mutablePullToRefreshStateFlow
|
||||||
}
|
}
|
||||||
|
private val mutableSnackbarDataFlow = bufferedMutableSharedFlow<BitwardenSnackbarData>()
|
||||||
|
private val snackbarRelayManager: SnackbarRelayManager = mockk {
|
||||||
|
every {
|
||||||
|
getSnackbarDataFlow(relay = any(), relays = anyVararg())
|
||||||
|
} returns mutableSnackbarDataFlow
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `init should call getAuthRequestsWithUpdates`() {
|
fun `init should call getAuthRequestsWithUpdates`() {
|
||||||
@@ -52,6 +61,16 @@ class PendingRequestsViewModelTest : BaseViewModelTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when SnackbarRelay flow updates, snackbar is shown`() = runTest {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
val expectedSnackbarData = BitwardenSnackbarData(message = "test message".asText())
|
||||||
|
viewModel.eventFlow.test {
|
||||||
|
mutableSnackbarDataFlow.tryEmit(expectedSnackbarData)
|
||||||
|
assertEquals(PendingRequestsEvent.ShowSnackbar(expectedSnackbarData), awaitItem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
@Test
|
@Test
|
||||||
fun `getPendingResults success with content should update state with some requests filtered`() {
|
fun `getPendingResults success with content should update state with some requests filtered`() {
|
||||||
@@ -373,6 +392,7 @@ class PendingRequestsViewModelTest : BaseViewModelTest() {
|
|||||||
clock = fixedClock,
|
clock = fixedClock,
|
||||||
authRepository = authRepository,
|
authRepository = authRepository,
|
||||||
settingsRepository = settingsRepository,
|
settingsRepository = settingsRepository,
|
||||||
|
snackbarRelayManager = snackbarRelayManager,
|
||||||
savedStateHandle = SavedStateHandle().apply { set("state", state) },
|
savedStateHandle = SavedStateHandle().apply { set("state", state) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user