mirror of
https://github.com/bitwarden/android.git
synced 2026-04-28 11:58:40 -05:00
PM-19294: Propagate the Register errors to the UI (#4883)
This commit is contained in:
@@ -900,7 +900,10 @@ class AuthRepositoryImpl(
|
||||
is RegisterResponseJson.CaptchaRequired -> {
|
||||
it.validationErrors.captchaKeys.firstOrNull()
|
||||
?.let { key -> RegisterResult.CaptchaRequired(captchaId = key) }
|
||||
?: RegisterResult.Error(errorMessage = null)
|
||||
?: RegisterResult.Error(
|
||||
errorMessage = null,
|
||||
error = MissingPropertyException("Captcha ID"),
|
||||
)
|
||||
}
|
||||
|
||||
is RegisterResponseJson.Success -> {
|
||||
@@ -909,11 +912,11 @@ class AuthRepositoryImpl(
|
||||
}
|
||||
|
||||
is RegisterResponseJson.Invalid -> {
|
||||
RegisterResult.Error(errorMessage = it.message)
|
||||
RegisterResult.Error(errorMessage = it.message, error = null)
|
||||
}
|
||||
}
|
||||
},
|
||||
onFailure = { RegisterResult.Error(errorMessage = null) },
|
||||
onFailure = { RegisterResult.Error(errorMessage = null, error = it) },
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,10 @@ sealed class RegisterResult {
|
||||
*
|
||||
* @param errorMessage a message describing the error.
|
||||
*/
|
||||
data class Error(val errorMessage: String?) : RegisterResult()
|
||||
data class Error(
|
||||
val errorMessage: String?,
|
||||
val error: Throwable?,
|
||||
) : RegisterResult()
|
||||
|
||||
/**
|
||||
* Password hash was found in a data breach.
|
||||
|
||||
@@ -108,6 +108,7 @@ fun CompleteRegistrationScreen(
|
||||
BitwardenBasicDialog(
|
||||
title = dialog.title?.invoke(),
|
||||
message = dialog.message(),
|
||||
throwable = dialog.error,
|
||||
onDismissRequest = handler.onDismissErrorDialog,
|
||||
)
|
||||
}
|
||||
@@ -141,7 +142,8 @@ fun CompleteRegistrationScreen(
|
||||
title = stringResource(
|
||||
id = R.string.create_account
|
||||
.takeIf { state.onboardingEnabled }
|
||||
?: R.string.set_password),
|
||||
?: R.string.set_password,
|
||||
),
|
||||
scrollBehavior = scrollBehavior,
|
||||
navigationIcon = rememberVectorPainter(id = R.drawable.ic_back),
|
||||
navigationIconContentDescription = stringResource(id = R.string.back),
|
||||
|
||||
@@ -210,6 +210,7 @@ class CompleteRegistrationViewModel @Inject constructor(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
message = registerAccountResult.errorMessage?.asText()
|
||||
?: R.string.generic_error_message.asText(),
|
||||
error = registerAccountResult.error,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -525,6 +526,7 @@ sealed class CompleteRegistrationDialog : Parcelable {
|
||||
data class Error(
|
||||
val title: Text?,
|
||||
val message: Text,
|
||||
val error: Throwable? = null,
|
||||
) : CompleteRegistrationDialog()
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@ fun CreateAccountScreen(
|
||||
BitwardenBasicDialog(
|
||||
title = dialog.title?.invoke(),
|
||||
message = dialog.message(),
|
||||
throwable = dialog.error,
|
||||
onDismissRequest = remember(viewModel) {
|
||||
{ viewModel.trySendAction(ErrorDialogDismiss) }
|
||||
},
|
||||
|
||||
@@ -180,6 +180,7 @@ class CreateAccountViewModel @Inject constructor(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
message = registerAccountResult.errorMessage?.asText()
|
||||
?: R.string.generic_error_message.asText(),
|
||||
error = registerAccountResult.error,
|
||||
),
|
||||
)
|
||||
}
|
||||
@@ -464,6 +465,7 @@ sealed class CreateAccountDialog : Parcelable {
|
||||
data class Error(
|
||||
val title: Text?,
|
||||
val message: Text,
|
||||
val error: Throwable? = null,
|
||||
) : CreateAccountDialog()
|
||||
}
|
||||
|
||||
|
||||
@@ -4276,7 +4276,13 @@ class AuthRepositoryTest {
|
||||
shouldCheckDataBreaches = false,
|
||||
isMasterPasswordStrong = true,
|
||||
)
|
||||
assertEquals(RegisterResult.Error(errorMessage = null), result)
|
||||
assertEquals(
|
||||
RegisterResult.Error(
|
||||
errorMessage = null,
|
||||
error = MissingPropertyException("Captcha ID"),
|
||||
),
|
||||
result,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -4322,6 +4328,7 @@ class AuthRepositoryTest {
|
||||
|
||||
@Test
|
||||
fun `register Failure should return Error with no message`() = runTest {
|
||||
val error = RuntimeException()
|
||||
coEvery { identityService.preLogin(EMAIL) } returns PRE_LOGIN_SUCCESS.asSuccess()
|
||||
coEvery {
|
||||
identityService.register(
|
||||
@@ -4339,7 +4346,7 @@ class AuthRepositoryTest {
|
||||
kdfIterations = DEFAULT_KDF_ITERATIONS.toUInt(),
|
||||
),
|
||||
)
|
||||
} returns RuntimeException().asFailure()
|
||||
} returns error.asFailure()
|
||||
|
||||
val result = repository.register(
|
||||
email = EMAIL,
|
||||
@@ -4349,7 +4356,7 @@ class AuthRepositoryTest {
|
||||
shouldCheckDataBreaches = false,
|
||||
isMasterPasswordStrong = true,
|
||||
)
|
||||
assertEquals(RegisterResult.Error(errorMessage = null), result)
|
||||
assertEquals(RegisterResult.Error(errorMessage = null, error = error), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -4383,7 +4390,7 @@ class AuthRepositoryTest {
|
||||
shouldCheckDataBreaches = false,
|
||||
isMasterPasswordStrong = true,
|
||||
)
|
||||
assertEquals(RegisterResult.Error(errorMessage = "message"), result)
|
||||
assertEquals(RegisterResult.Error(errorMessage = "message", error = null), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -4420,7 +4427,7 @@ class AuthRepositoryTest {
|
||||
shouldCheckDataBreaches = false,
|
||||
isMasterPasswordStrong = true,
|
||||
)
|
||||
assertEquals(RegisterResult.Error(errorMessage = "expected"), result)
|
||||
assertEquals(RegisterResult.Error(errorMessage = "expected", error = null), result)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -178,6 +178,7 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
|
||||
@Test
|
||||
fun `CallToActionClick register returns error should update errorDialogState`() = runTest {
|
||||
val error = Throwable("Fail!")
|
||||
coEvery {
|
||||
mockAuthRepository.register(
|
||||
email = EMAIL,
|
||||
@@ -188,7 +189,7 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
shouldCheckDataBreaches = false,
|
||||
isMasterPasswordStrong = true,
|
||||
)
|
||||
} returns RegisterResult.Error(errorMessage = "mock_error")
|
||||
} returns RegisterResult.Error(errorMessage = "mock_error", error = error)
|
||||
val viewModel = createCompleteRegistrationViewModel(VALID_INPUT_STATE)
|
||||
viewModel.stateFlow.test {
|
||||
assertEquals(VALID_INPUT_STATE, awaitItem())
|
||||
@@ -202,6 +203,7 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
dialog = CompleteRegistrationDialog.Error(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
message = "mock_error".asText(),
|
||||
error = error,
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
@@ -273,7 +275,7 @@ class CompleteRegistrationViewModelTest : BaseViewModelTest() {
|
||||
shouldCheckDataBreaches = false,
|
||||
isMasterPasswordStrong = true,
|
||||
)
|
||||
} returns RegisterResult.Error(null)
|
||||
} returns RegisterResult.Error(errorMessage = null, error = null)
|
||||
val viewModel = createCompleteRegistrationViewModel(VALID_INPUT_STATE)
|
||||
viewModel.trySendAction(CompleteRegistrationAction.ContinueWithBreachedPasswordClick)
|
||||
coVerify {
|
||||
|
||||
@@ -252,6 +252,7 @@ class CreateAccountViewModelTest : BaseViewModelTest() {
|
||||
|
||||
@Test
|
||||
fun `SubmitClick register returns error should update errorDialogState`() = runTest {
|
||||
val error = Throwable("Fail!")
|
||||
val repo = mockk<AuthRepository> {
|
||||
every { captchaTokenResultFlow } returns flowOf()
|
||||
coEvery {
|
||||
@@ -263,7 +264,7 @@ class CreateAccountViewModelTest : BaseViewModelTest() {
|
||||
shouldCheckDataBreaches = false,
|
||||
isMasterPasswordStrong = true,
|
||||
)
|
||||
} returns RegisterResult.Error(errorMessage = "mock_error")
|
||||
} returns RegisterResult.Error(errorMessage = "mock_error", error = error)
|
||||
}
|
||||
val viewModel = CreateAccountViewModel(
|
||||
savedStateHandle = validInputHandle,
|
||||
@@ -281,6 +282,7 @@ class CreateAccountViewModelTest : BaseViewModelTest() {
|
||||
dialog = CreateAccountDialog.Error(
|
||||
title = R.string.an_error_has_occurred.asText(),
|
||||
message = "mock_error".asText(),
|
||||
error = error,
|
||||
),
|
||||
),
|
||||
awaitItem(),
|
||||
@@ -368,7 +370,7 @@ class CreateAccountViewModelTest : BaseViewModelTest() {
|
||||
shouldCheckDataBreaches = false,
|
||||
isMasterPasswordStrong = true,
|
||||
)
|
||||
} returns RegisterResult.Error(null)
|
||||
} returns RegisterResult.Error(errorMessage = null, error = null)
|
||||
}
|
||||
val viewModel = CreateAccountViewModel(
|
||||
savedStateHandle = validInputHandle,
|
||||
|
||||
Reference in New Issue
Block a user