mirror of
https://github.com/bitwarden/android.git
synced 2026-05-30 16:43:22 -05:00
BIT-74: Add Login with Device screen (#438)
This commit is contained in:
@@ -46,6 +46,7 @@ class LoginScreenTest : BaseComposeTest() {
|
||||
}
|
||||
private var onNavigateBackCalled = false
|
||||
private var onNavigateToEnterpriseSignOnCalled = false
|
||||
private var onNavigateToLoginWithDeviceCalled = false
|
||||
private val mutableEventFlow = MutableSharedFlow<LoginEvent>(
|
||||
extraBufferCapacity = Int.MAX_VALUE,
|
||||
)
|
||||
@@ -61,6 +62,7 @@ class LoginScreenTest : BaseComposeTest() {
|
||||
LoginScreen(
|
||||
onNavigateBack = { onNavigateBackCalled = true },
|
||||
onNavigateToEnterpriseSignOn = { onNavigateToEnterpriseSignOnCalled = true },
|
||||
onNavigateToLoginWithDevice = { onNavigateToLoginWithDeviceCalled = true },
|
||||
viewModel = viewModel,
|
||||
intentHandler = intentHandler,
|
||||
)
|
||||
@@ -273,6 +275,12 @@ class LoginScreenTest : BaseComposeTest() {
|
||||
mutableEventFlow.tryEmit(LoginEvent.NavigateToEnterpriseSignOn)
|
||||
assertTrue(onNavigateToEnterpriseSignOnCalled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `NavigateToLoginWithDevice should call onNavigateToLoginWithDevice`() {
|
||||
mutableEventFlow.tryEmit(LoginEvent.NavigateToLoginWithDevice)
|
||||
assertTrue(onNavigateToLoginWithDeviceCalled)
|
||||
}
|
||||
}
|
||||
|
||||
private val ACTIVE_ACCOUNT_SUMMARY = AccountSummary(
|
||||
|
||||
@@ -317,6 +317,19 @@ class LoginViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `LoginWithDeviceButtonClick should emit NavigateToLoginWithDevice`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(LoginAction.LoginWithDeviceButtonClick)
|
||||
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
||||
assertEquals(
|
||||
LoginEvent.NavigateToLoginWithDevice,
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `SingleSignOnClick should emit NavigateToEnterpriseSignOn`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.x8bit.bitwarden.ui.auth.feature.loginwithdevice
|
||||
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollTo
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.util.isProgressBar
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import junit.framework.TestCase
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
|
||||
class LoginWithDeviceScreenTest : BaseComposeTest() {
|
||||
private var onNavigateBackCalled = false
|
||||
private val mutableEventFlow = MutableSharedFlow<LoginWithDeviceEvent>(
|
||||
extraBufferCapacity = Int.MAX_VALUE,
|
||||
)
|
||||
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
||||
private val viewModel = mockk<LoginWithDeviceViewModel>(relaxed = true) {
|
||||
every { eventFlow } returns mutableEventFlow
|
||||
every { stateFlow } returns mutableStateFlow
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
composeTestRule.setContent {
|
||||
LoginWithDeviceScreen(
|
||||
onNavigateBack = { onNavigateBackCalled = true },
|
||||
viewModel = viewModel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `close button click should send CloseButtonClick action`() {
|
||||
composeTestRule.onNodeWithContentDescription("Close").performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(LoginWithDeviceAction.CloseButtonClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `resend notification click should send ResendNotificationClick action`() {
|
||||
composeTestRule.onNodeWithText("Resend notification").performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(LoginWithDeviceAction.ResendNotificationClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `view all log in options click should send ViewAllLogInOptionsClick action`() {
|
||||
composeTestRule.onNodeWithText("View all log in options").performScrollTo().performClick()
|
||||
verify {
|
||||
viewModel.trySendAction(LoginWithDeviceAction.ViewAllLogInOptionsClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `NavigateBack should call onNavigateBack`() {
|
||||
mutableEventFlow.tryEmit(LoginWithDeviceEvent.NavigateBack)
|
||||
TestCase.assertTrue(onNavigateBackCalled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `progress bar should be displayed according to state`() {
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = LoginWithDeviceState.ViewState.Loading)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = LoginWithDeviceState.ViewState.Error("Failure".asText()))
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_STATE.viewState)
|
||||
}
|
||||
composeTestRule.onNode(isProgressBar).assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `error should be displayed according to state`() {
|
||||
val errorMessage = "error"
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = LoginWithDeviceState.ViewState.Loading)
|
||||
}
|
||||
composeTestRule.onNodeWithText(errorMessage).assertDoesNotExist()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = LoginWithDeviceState.ViewState.Error(errorMessage.asText()))
|
||||
}
|
||||
composeTestRule.onNodeWithText(errorMessage).assertIsDisplayed()
|
||||
|
||||
mutableStateFlow.update {
|
||||
it.copy(viewState = DEFAULT_STATE.viewState)
|
||||
}
|
||||
composeTestRule.onNodeWithText(errorMessage).assertDoesNotExist()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_STATE = LoginWithDeviceState(
|
||||
viewState = LoginWithDeviceState.ViewState.Content(
|
||||
fingerprintPhrase = "alabster-drinkable-mystified-rapping-irrigate",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.x8bit.bitwarden.ui.auth.feature.loginwithdevice
|
||||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class LoginWithDeviceViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private val savedStateHandle = SavedStateHandle()
|
||||
|
||||
@Test
|
||||
fun `initial state should be correct`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(DEFAULT_STATE, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CloseButtonClick should emit NavigateBack`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(LoginWithDeviceAction.CloseButtonClick)
|
||||
assertEquals(
|
||||
LoginWithDeviceEvent.NavigateBack,
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ResendNotificationClick should emit ShowToast`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(LoginWithDeviceAction.ResendNotificationClick)
|
||||
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
||||
assertEquals(
|
||||
LoginWithDeviceEvent.ShowToast("Not yet implemented."),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ViewAllLogInOptionsClick should emit NavigateBack`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(LoginWithDeviceAction.ViewAllLogInOptionsClick)
|
||||
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
||||
assertEquals(
|
||||
LoginWithDeviceEvent.NavigateBack,
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createViewModel(): LoginWithDeviceViewModel =
|
||||
LoginWithDeviceViewModel(
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_STATE = LoginWithDeviceState(
|
||||
viewState = LoginWithDeviceState.ViewState.Content(
|
||||
fingerprintPhrase = "alabster-drinkable-mystified-rapping-irrigate",
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user