mirror of
https://github.com/bitwarden/android.git
synced 2026-06-02 11:12:00 -05:00
BIT-320: Loading and error dialogs (#101)
This commit is contained in:
@@ -54,6 +54,17 @@ class IdentityServiceTest : BaseServiceTest() {
|
||||
assertEquals(Result.success(CAPTCHA_BODY), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getToken when response is a 400 with an error body should return Invalid`() = runTest {
|
||||
server.enqueue(MockResponse().setResponseCode(400).setBody(INVALID_LOGIN_JSON))
|
||||
val result = identityService.getToken(
|
||||
email = EMAIL,
|
||||
passwordHash = PASSWORD_HASH,
|
||||
captchaToken = null,
|
||||
)
|
||||
assertEquals(Result.success(INVALID_LOGIN), result)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val EMAIL = "email"
|
||||
private const val PASSWORD_HASH = "passwordHash"
|
||||
@@ -73,3 +84,17 @@ private const val LOGIN_SUCCESS_JSON = """
|
||||
}
|
||||
"""
|
||||
private val LOGIN_SUCCESS = GetTokenResponseJson.Success("123")
|
||||
|
||||
private const val INVALID_LOGIN_JSON = """
|
||||
{
|
||||
"ErrorModel": {
|
||||
"Message": "123"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
private val INVALID_LOGIN = GetTokenResponseJson.Invalid(
|
||||
errorModel = GetTokenResponseJson.Invalid.ErrorModel(
|
||||
errorMessage = "123",
|
||||
),
|
||||
)
|
||||
|
||||
@@ -50,18 +50,18 @@ class AuthRepositoryTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login when pre login fails should return Error`() = runTest {
|
||||
fun `login when pre login fails should return Error with no message`() = runTest {
|
||||
coEvery {
|
||||
accountsService.preLogin(email = EMAIL)
|
||||
} returns (Result.failure(RuntimeException()))
|
||||
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
|
||||
assertEquals(LoginResult.Error, result)
|
||||
assertEquals(LoginResult.Error(errorMessage = null), result)
|
||||
assertEquals(AuthState.Unauthenticated, repository.authStateFlow.value)
|
||||
coVerify { accountsService.preLogin(email = EMAIL) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login get token fails should return Error`() = runTest {
|
||||
fun `login get token fails should return Error with no message`() = runTest {
|
||||
coEvery {
|
||||
accountsService.preLogin(email = EMAIL)
|
||||
} returns Result.success(PRE_LOGIN_SUCCESS)
|
||||
@@ -74,7 +74,41 @@ class AuthRepositoryTest {
|
||||
}
|
||||
.returns(Result.failure(RuntimeException()))
|
||||
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
|
||||
assertEquals(LoginResult.Error, result)
|
||||
assertEquals(LoginResult.Error(errorMessage = null), result)
|
||||
assertEquals(AuthState.Unauthenticated, repository.authStateFlow.value)
|
||||
coVerify { accountsService.preLogin(email = EMAIL) }
|
||||
coVerify {
|
||||
identityService.getToken(
|
||||
email = EMAIL,
|
||||
passwordHash = PASSWORD_HASH,
|
||||
captchaToken = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `login get token returns Invalid should return Error with correct message`() = runTest {
|
||||
coEvery {
|
||||
accountsService.preLogin(email = EMAIL)
|
||||
} returns Result.success(PRE_LOGIN_SUCCESS)
|
||||
coEvery {
|
||||
identityService.getToken(
|
||||
email = EMAIL,
|
||||
passwordHash = PASSWORD_HASH,
|
||||
captchaToken = null,
|
||||
)
|
||||
}
|
||||
.returns(
|
||||
Result.success(
|
||||
GetTokenResponseJson.Invalid(
|
||||
errorModel = GetTokenResponseJson.Invalid.ErrorModel(
|
||||
errorMessage = "mock_error_message",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
val result = repository.login(email = EMAIL, password = PASSWORD, captchaToken = null)
|
||||
assertEquals(LoginResult.Error(errorMessage = "mock_error_message"), result)
|
||||
assertEquals(AuthState.Unauthenticated, repository.authStateFlow.value)
|
||||
coVerify { accountsService.preLogin(email = EMAIL) }
|
||||
coVerify {
|
||||
|
||||
@@ -14,6 +14,8 @@ import androidx.compose.ui.test.performScrollTo
|
||||
import androidx.compose.ui.test.performTextInput
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
@@ -35,6 +37,8 @@ class LoginScreenTest : BaseComposeTest() {
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -60,6 +64,8 @@ class LoginScreenTest : BaseComposeTest() {
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -85,6 +91,8 @@ class LoginScreenTest : BaseComposeTest() {
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -110,6 +118,8 @@ class LoginScreenTest : BaseComposeTest() {
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -147,6 +157,8 @@ class LoginScreenTest : BaseComposeTest() {
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -173,6 +185,8 @@ class LoginScreenTest : BaseComposeTest() {
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -199,6 +213,8 @@ class LoginScreenTest : BaseComposeTest() {
|
||||
isLoginButtonEnabled = false,
|
||||
passwordInput = "",
|
||||
region = "",
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,11 +3,15 @@ package com.x8bit.bitwarden.ui.auth.feature.login
|
||||
import android.content.Intent
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.model.LoginResult
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.util.CaptchaCallbackTokenResult
|
||||
import com.x8bit.bitwarden.data.auth.datasource.network.util.generateIntentForCaptcha
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
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.platform.components.LoadingDialogState
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
@@ -92,8 +96,7 @@ class LoginViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `LoginButtonClick login returns error should emit error ShowToast`() = runTest {
|
||||
// TODO: handle and display errors (BIT-320)
|
||||
fun `LoginButtonClick login returns error should update errorDialogState`() = runTest {
|
||||
val authRepository = mockk<AuthRepository> {
|
||||
coEvery {
|
||||
login(
|
||||
@@ -101,19 +104,32 @@ class LoginViewModelTest : BaseViewModelTest() {
|
||||
password = "",
|
||||
captchaToken = null,
|
||||
)
|
||||
} returns LoginResult.Error
|
||||
} returns LoginResult.Error(errorMessage = "mock_error")
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
}
|
||||
val viewModel = LoginViewModel(
|
||||
authRepository = authRepository,
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(LoginAction.LoginButtonClick)
|
||||
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
||||
assertEquals(LoginEvent.ShowToast("Loading..."), awaitItem())
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(DEFAULT_STATE, awaitItem())
|
||||
viewModel.trySendAction(LoginAction.LoginButtonClick)
|
||||
assertEquals(
|
||||
LoginEvent.ShowToast("Error when logging in"),
|
||||
DEFAULT_STATE.copy(
|
||||
loadingDialogState = LoadingDialogState.Shown(
|
||||
text = R.string.logging_in.asText(),
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
errorDialogState = BasicDialogState.Shown(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
message = "mock_error".asText(),
|
||||
),
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
@@ -123,19 +139,32 @@ class LoginViewModelTest : BaseViewModelTest() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `LoginButtonClick login returns success should emit loading ShowToast`() = runTest {
|
||||
fun `LoginButtonClick login returns success should update loadingDialogState`() = runTest {
|
||||
val authRepository = mockk<AuthRepository> {
|
||||
coEvery { login("test@gmail.com", "", captchaToken = null) } returns LoginResult.Success
|
||||
coEvery {
|
||||
login("test@gmail.com", "", captchaToken = null)
|
||||
} returns LoginResult.Success
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
}
|
||||
val viewModel = LoginViewModel(
|
||||
authRepository = authRepository,
|
||||
savedStateHandle = savedStateHandle,
|
||||
)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(LoginAction.LoginButtonClick)
|
||||
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
||||
assertEquals(LoginEvent.ShowToast("Loading..."), awaitItem())
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(DEFAULT_STATE, awaitItem())
|
||||
viewModel.trySendAction(LoginAction.LoginButtonClick)
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(
|
||||
loadingDialogState = LoadingDialogState.Shown(
|
||||
text = R.string.logging_in.asText(),
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
)
|
||||
assertEquals(
|
||||
DEFAULT_STATE.copy(loadingDialogState = LoadingDialogState.Hidden),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
coVerify {
|
||||
authRepository.login(email = "test@gmail.com", password = "", captchaToken = null)
|
||||
@@ -163,7 +192,6 @@ class LoginViewModelTest : BaseViewModelTest() {
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(LoginAction.LoginButtonClick)
|
||||
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
||||
assertEquals(LoginEvent.ShowToast("Loading..."), awaitItem())
|
||||
assertEquals(LoginEvent.NavigateToCaptcha(intent = mockkIntent), awaitItem())
|
||||
}
|
||||
coVerify {
|
||||
@@ -271,6 +299,8 @@ class LoginViewModelTest : BaseViewModelTest() {
|
||||
passwordInput = "",
|
||||
isLoginButtonEnabled = true,
|
||||
region = "",
|
||||
loadingDialogState = LoadingDialogState.Hidden,
|
||||
errorDialogState = BasicDialogState.Hidden,
|
||||
)
|
||||
|
||||
private const val LOGIN_RESULT_PATH =
|
||||
|
||||
Reference in New Issue
Block a user