mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 15:15:34 +03:00
Fix incorrect VM state access & unnecessary eventFlow usages (#1218)
This commit is contained in:
parent
ab55b5e535
commit
87254b4436
13 changed files with 381 additions and 430 deletions
|
@ -191,7 +191,7 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
mutableStateFlow.update { it.copy(dialog = null) }
|
mutableStateFlow.update { it.copy(dialog = null) }
|
||||||
sendEvent(
|
sendEvent(
|
||||||
CreateAccountEvent.NavigateToLogin(
|
CreateAccountEvent.NavigateToLogin(
|
||||||
email = mutableStateFlow.value.emailInput,
|
email = state.emailInput,
|
||||||
captchaToken = registerAccountResult.captchaToken,
|
captchaToken = registerAccountResult.captchaToken,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -251,7 +251,7 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
} else {
|
} else {
|
||||||
passwordStrengthJob = viewModelScope.launch {
|
passwordStrengthJob = viewModelScope.launch {
|
||||||
val result = authRepository.getPasswordStrength(
|
val result = authRepository.getPasswordStrength(
|
||||||
email = mutableStateFlow.value.emailInput,
|
email = state.emailInput,
|
||||||
password = action.input,
|
password = action.input,
|
||||||
)
|
)
|
||||||
trySendAction(ReceivePasswordStrengthResult(result))
|
trySendAction(ReceivePasswordStrengthResult(result))
|
||||||
|
@ -264,7 +264,7 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSubmitClick() = when {
|
private fun handleSubmitClick() = when {
|
||||||
mutableStateFlow.value.emailInput.isBlank() -> {
|
state.emailInput.isBlank() -> {
|
||||||
val dialog = BasicDialogState.Shown(
|
val dialog = BasicDialogState.Shown(
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
message = R.string.validation_field_required
|
message = R.string.validation_field_required
|
||||||
|
@ -273,7 +273,7 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
mutableStateFlow.update { it.copy(dialog = CreateAccountDialog.Error(dialog)) }
|
mutableStateFlow.update { it.copy(dialog = CreateAccountDialog.Error(dialog)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
!mutableStateFlow.value.emailInput.isValidEmail() -> {
|
!state.emailInput.isValidEmail() -> {
|
||||||
val dialog = BasicDialogState.Shown(
|
val dialog = BasicDialogState.Shown(
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
message = R.string.invalid_email.asText(),
|
message = R.string.invalid_email.asText(),
|
||||||
|
@ -281,7 +281,7 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
mutableStateFlow.update { it.copy(dialog = CreateAccountDialog.Error(dialog)) }
|
mutableStateFlow.update { it.copy(dialog = CreateAccountDialog.Error(dialog)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
mutableStateFlow.value.passwordInput.length < MIN_PASSWORD_LENGTH -> {
|
state.passwordInput.length < MIN_PASSWORD_LENGTH -> {
|
||||||
val dialog = BasicDialogState.Shown(
|
val dialog = BasicDialogState.Shown(
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
message = R.string.master_password_length_val_message_x.asText(MIN_PASSWORD_LENGTH),
|
message = R.string.master_password_length_val_message_x.asText(MIN_PASSWORD_LENGTH),
|
||||||
|
@ -289,7 +289,7 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
mutableStateFlow.update { it.copy(dialog = CreateAccountDialog.Error(dialog)) }
|
mutableStateFlow.update { it.copy(dialog = CreateAccountDialog.Error(dialog)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
mutableStateFlow.value.passwordInput != mutableStateFlow.value.confirmPasswordInput -> {
|
state.passwordInput != state.confirmPasswordInput -> {
|
||||||
val dialog = BasicDialogState.Shown(
|
val dialog = BasicDialogState.Shown(
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
message = R.string.master_password_confirmation_val_message.asText(),
|
message = R.string.master_password_confirmation_val_message.asText(),
|
||||||
|
@ -297,7 +297,7 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
mutableStateFlow.update { it.copy(dialog = CreateAccountDialog.Error(dialog)) }
|
mutableStateFlow.update { it.copy(dialog = CreateAccountDialog.Error(dialog)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
!mutableStateFlow.value.isAcceptPoliciesToggled -> {
|
!state.isAcceptPoliciesToggled -> {
|
||||||
val dialog = BasicDialogState.Shown(
|
val dialog = BasicDialogState.Shown(
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
message = R.string.accept_policies_error.asText(),
|
message = R.string.accept_policies_error.asText(),
|
||||||
|
@ -307,7 +307,7 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
submitRegisterAccountRequest(
|
submitRegisterAccountRequest(
|
||||||
shouldCheckForDataBreaches = mutableStateFlow.value.isCheckDataBreachesToggled,
|
shouldCheckForDataBreaches = state.isCheckDataBreachesToggled,
|
||||||
captchaToken = null,
|
captchaToken = null,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -327,9 +327,9 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val result = authRepository.register(
|
val result = authRepository.register(
|
||||||
shouldCheckDataBreaches = shouldCheckForDataBreaches,
|
shouldCheckDataBreaches = shouldCheckForDataBreaches,
|
||||||
email = mutableStateFlow.value.emailInput,
|
email = state.emailInput,
|
||||||
masterPassword = mutableStateFlow.value.passwordInput,
|
masterPassword = state.passwordInput,
|
||||||
masterPasswordHint = mutableStateFlow.value.passwordHintInput.ifBlank { null },
|
masterPasswordHint = state.passwordHintInput.ifBlank { null },
|
||||||
captchaToken = captchaToken,
|
captchaToken = captchaToken,
|
||||||
)
|
)
|
||||||
sendAction(
|
sendAction(
|
||||||
|
|
|
@ -72,8 +72,6 @@ class EnvironmentViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSaveClickAction() {
|
private fun handleSaveClickAction() {
|
||||||
val state = mutableStateFlow.value
|
|
||||||
|
|
||||||
val urlsAreAllNullOrValid = listOf(
|
val urlsAreAllNullOrValid = listOf(
|
||||||
state.serverUrl,
|
state.serverUrl,
|
||||||
state.webVaultServerUrl,
|
state.webVaultServerUrl,
|
||||||
|
|
|
@ -128,7 +128,7 @@ class LandingViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleContinueButtonClicked() {
|
private fun handleContinueButtonClicked() {
|
||||||
if (!mutableStateFlow.value.emailInput.isValidEmail()) {
|
if (!state.emailInput.isValidEmail()) {
|
||||||
mutableStateFlow.update {
|
mutableStateFlow.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
dialog = LandingState.DialogState.Error(
|
dialog = LandingState.DialogState.Error(
|
||||||
|
@ -150,8 +150,8 @@ class LandingViewModel @Inject constructor(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val email = mutableStateFlow.value.emailInput
|
val email = state.emailInput
|
||||||
val isRememberMeEnabled = mutableStateFlow.value.isRememberMeEnabled
|
val isRememberMeEnabled = state.isRememberMeEnabled
|
||||||
|
|
||||||
// Update the remembered email address
|
// Update the remembered email address
|
||||||
authRepository.rememberedEmailAddress = email.takeUnless { !isRememberMeEnabled }
|
authRepository.rememberedEmailAddress = email.takeUnless { !isRememberMeEnabled }
|
||||||
|
|
|
@ -232,9 +232,9 @@ class LoginViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val result = authRepository.login(
|
val result = authRepository.login(
|
||||||
email = mutableStateFlow.value.emailAddress,
|
email = state.emailAddress,
|
||||||
password = mutableStateFlow.value.passwordInput,
|
password = state.passwordInput,
|
||||||
captchaToken = mutableStateFlow.value.captchaToken,
|
captchaToken = state.captchaToken,
|
||||||
)
|
)
|
||||||
sendAction(
|
sendAction(
|
||||||
LoginAction.Internal.ReceiveLoginResult(
|
LoginAction.Internal.ReceiveLoginResult(
|
||||||
|
@ -245,7 +245,7 @@ class LoginViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleMasterPasswordHintClicked() {
|
private fun handleMasterPasswordHintClicked() {
|
||||||
val email = mutableStateFlow.value.emailAddress
|
val email = state.emailAddress
|
||||||
sendEvent(LoginEvent.NavigateToMasterPasswordHint(email))
|
sendEvent(LoginEvent.NavigateToMasterPasswordHint(email))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +254,7 @@ class LoginViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSingleSignOnClicked() {
|
private fun handleSingleSignOnClicked() {
|
||||||
val email = mutableStateFlow.value.emailAddress
|
val email = state.emailAddress
|
||||||
sendEvent(LoginEvent.NavigateToEnterpriseSignOn(email))
|
sendEvent(LoginEvent.NavigateToEnterpriseSignOn(email))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,13 +160,13 @@ class VaultUnlockViewModel @Inject constructor(
|
||||||
val vaultUnlockResult = when (state.vaultUnlockType) {
|
val vaultUnlockResult = when (state.vaultUnlockType) {
|
||||||
VaultUnlockType.MASTER_PASSWORD -> {
|
VaultUnlockType.MASTER_PASSWORD -> {
|
||||||
vaultRepo.unlockVaultWithMasterPassword(
|
vaultRepo.unlockVaultWithMasterPassword(
|
||||||
mutableStateFlow.value.input,
|
state.input,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
VaultUnlockType.PIN -> {
|
VaultUnlockType.PIN -> {
|
||||||
vaultRepo.unlockVaultWithPin(
|
vaultRepo.unlockVaultWithPin(
|
||||||
mutableStateFlow.value.input,
|
state.input,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,9 +97,9 @@ class LoginApprovalViewModel @Inject constructor(
|
||||||
trySendAction(
|
trySendAction(
|
||||||
LoginApprovalAction.Internal.ApproveRequestResultReceive(
|
LoginApprovalAction.Internal.ApproveRequestResultReceive(
|
||||||
result = authRepository.updateAuthRequest(
|
result = authRepository.updateAuthRequest(
|
||||||
requestId = mutableStateFlow.value.requestId,
|
requestId = state.requestId,
|
||||||
masterPasswordHash = mutableStateFlow.value.masterPasswordHash,
|
masterPasswordHash = state.masterPasswordHash,
|
||||||
publicKey = mutableStateFlow.value.publicKey,
|
publicKey = state.publicKey,
|
||||||
isApproved = true,
|
isApproved = true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -116,9 +116,9 @@ class LoginApprovalViewModel @Inject constructor(
|
||||||
trySendAction(
|
trySendAction(
|
||||||
LoginApprovalAction.Internal.DeclineRequestResultReceive(
|
LoginApprovalAction.Internal.DeclineRequestResultReceive(
|
||||||
result = authRepository.updateAuthRequest(
|
result = authRepository.updateAuthRequest(
|
||||||
requestId = mutableStateFlow.value.requestId,
|
requestId = state.requestId,
|
||||||
masterPasswordHash = mutableStateFlow.value.masterPasswordHash,
|
masterPasswordHash = state.masterPasswordHash,
|
||||||
publicKey = mutableStateFlow.value.publicKey,
|
publicKey = state.publicKey,
|
||||||
isApproved = false,
|
isApproved = false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -76,7 +76,7 @@ class PendingRequestsViewModel @Inject constructor(
|
||||||
viewState = PendingRequestsState.ViewState.Loading,
|
viewState = PendingRequestsState.ViewState.Loading,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
mutableStateFlow.value.authRequests.forEach { request ->
|
state.authRequests.forEach { request ->
|
||||||
authRepository.updateAuthRequest(
|
authRepository.updateAuthRequest(
|
||||||
requestId = request.id,
|
requestId = request.id,
|
||||||
masterPasswordHash = request.masterPasswordHash,
|
masterPasswordHash = request.masterPasswordHash,
|
||||||
|
|
|
@ -121,7 +121,7 @@ class ExportVaultViewModel @Inject constructor(
|
||||||
@Suppress("ReturnCount")
|
@Suppress("ReturnCount")
|
||||||
private fun handleConfirmExportVaultClicked() {
|
private fun handleConfirmExportVaultClicked() {
|
||||||
// Display an error alert if the user hasn't entered a password.
|
// Display an error alert if the user hasn't entered a password.
|
||||||
if (mutableStateFlow.value.passwordInput.isBlank()) {
|
if (state.passwordInput.isBlank()) {
|
||||||
updateStateWithError(
|
updateStateWithError(
|
||||||
message = R.string.validation_field_required.asText(
|
message = R.string.validation_field_required.asText(
|
||||||
R.string.master_password.asText(),
|
R.string.master_password.asText(),
|
||||||
|
@ -149,7 +149,7 @@ class ExportVaultViewModel @Inject constructor(
|
||||||
sendAction(
|
sendAction(
|
||||||
ExportVaultAction.Internal.ReceiveValidatePasswordResult(
|
ExportVaultAction.Internal.ReceiveValidatePasswordResult(
|
||||||
result = authRepository.validatePassword(
|
result = authRepository.validatePassword(
|
||||||
password = mutableStateFlow.value.passwordInput,
|
password = state.passwordInput,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
@ -550,7 +550,7 @@ class GeneratorViewModel @Inject constructor(
|
||||||
private fun handleRegenerationClick() {
|
private fun handleRegenerationClick() {
|
||||||
// Go through the update process with the current state to trigger a
|
// Go through the update process with the current state to trigger a
|
||||||
// regeneration of the generated text for the same state.
|
// regeneration of the generated text for the same state.
|
||||||
updateGeneratorMainType(forceRegeneration = true) { mutableStateFlow.value.selectedType }
|
updateGeneratorMainType(forceRegeneration = true) { state.selectedType }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleCopyClick() {
|
private fun handleCopyClick() {
|
||||||
|
@ -1294,7 +1294,7 @@ class GeneratorViewModel @Inject constructor(
|
||||||
forceRegeneration: Boolean = false,
|
forceRegeneration: Boolean = false,
|
||||||
crossinline block: (GeneratorState.MainType) -> GeneratorState.MainType?,
|
crossinline block: (GeneratorState.MainType) -> GeneratorState.MainType?,
|
||||||
) {
|
) {
|
||||||
val currentSelectedType = mutableStateFlow.value.selectedType
|
val currentSelectedType = state.selectedType
|
||||||
val updatedMainType = block(currentSelectedType) ?: return
|
val updatedMainType = block(currentSelectedType) ?: return
|
||||||
mutableStateFlow.update { it.copy(selectedType = updatedMainType) }
|
mutableStateFlow.update { it.copy(selectedType = updatedMainType) }
|
||||||
|
|
||||||
|
|
|
@ -434,7 +434,7 @@ class VaultAddEditViewModel @Inject constructor(
|
||||||
when (action.customFieldAction) {
|
when (action.customFieldAction) {
|
||||||
CustomFieldAction.MOVE_UP -> {
|
CustomFieldAction.MOVE_UP -> {
|
||||||
val items =
|
val items =
|
||||||
(mutableStateFlow.value.viewState as VaultAddEditState.ViewState.Content)
|
(state.viewState as VaultAddEditState.ViewState.Content)
|
||||||
.common
|
.common
|
||||||
.customFieldData
|
.customFieldData
|
||||||
.toMutableList()
|
.toMutableList()
|
||||||
|
@ -455,7 +455,7 @@ class VaultAddEditViewModel @Inject constructor(
|
||||||
|
|
||||||
CustomFieldAction.MOVE_DOWN -> {
|
CustomFieldAction.MOVE_DOWN -> {
|
||||||
val items =
|
val items =
|
||||||
(mutableStateFlow.value.viewState as VaultAddEditState.ViewState.Content)
|
(state.viewState as VaultAddEditState.ViewState.Content)
|
||||||
.common
|
.common
|
||||||
.customFieldData
|
.customFieldData
|
||||||
.toMutableList()
|
.toMutableList()
|
||||||
|
|
|
@ -42,75 +42,67 @@ class ResetPasswordViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `CurrentPasswordInputChanged should update the current password input in the state`() =
|
fun `CurrentPasswordInputChanged should update the current password input in the state`() {
|
||||||
runTest {
|
|
||||||
val viewModel = createViewModel()
|
|
||||||
viewModel.eventFlow.test {
|
|
||||||
viewModel.trySendAction(ResetPasswordAction.CurrentPasswordInputChanged("Test123"))
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
DEFAULT_STATE.copy(
|
|
||||||
currentPasswordInput = "Test123",
|
|
||||||
),
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `SubmitClicked with blank password shows error alert`() = runTest {
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ResetPasswordAction.CurrentPasswordInputChanged("Test123"))
|
||||||
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
dialogState = ResetPasswordState.DialogState.Error(
|
currentPasswordInput = "Test123",
|
||||||
title = null,
|
),
|
||||||
message = R.string.validation_field_required
|
viewModel.stateFlow.value,
|
||||||
.asText(R.string.master_password.asText()),
|
)
|
||||||
),
|
|
||||||
),
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
|
|
||||||
// Dismiss the alert.
|
|
||||||
viewModel.trySendAction(ResetPasswordAction.DialogDismiss)
|
|
||||||
assertEquals(
|
|
||||||
DEFAULT_STATE,
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `SubmitClicked with invalid password shows error alert for weak password reason`() =
|
fun `SubmitClicked with blank password shows error alert`() {
|
||||||
runTest {
|
val viewModel = createViewModel()
|
||||||
val password = "Test123"
|
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
||||||
coEvery {
|
|
||||||
authRepository.validatePasswordAgainstPolicies(password)
|
|
||||||
} returns false
|
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
assertEquals(
|
||||||
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged(password))
|
DEFAULT_STATE.copy(
|
||||||
viewModel.eventFlow.test {
|
dialogState = ResetPasswordState.DialogState.Error(
|
||||||
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
title = null,
|
||||||
|
message = R.string.validation_field_required
|
||||||
|
.asText(R.string.master_password.asText()),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
|
|
||||||
assertEquals(
|
// Dismiss the alert.
|
||||||
DEFAULT_STATE.copy(
|
viewModel.trySendAction(ResetPasswordAction.DialogDismiss)
|
||||||
dialogState = ResetPasswordState.DialogState.Error(
|
assertEquals(
|
||||||
title = R.string.master_password_policy_validation_title.asText(),
|
DEFAULT_STATE,
|
||||||
message = R.string.master_password_policy_validation_message.asText(),
|
viewModel.stateFlow.value,
|
||||||
),
|
)
|
||||||
passwordInput = password,
|
}
|
||||||
),
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `SubmitClicked with invalid password shows error alert for admin reset reason`() = runTest {
|
fun `SubmitClicked with invalid password shows error alert for weak password reason`() {
|
||||||
|
val password = "Test123"
|
||||||
|
coEvery {
|
||||||
|
authRepository.validatePasswordAgainstPolicies(password)
|
||||||
|
} returns false
|
||||||
|
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged(password))
|
||||||
|
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
DEFAULT_STATE.copy(
|
||||||
|
dialogState = ResetPasswordState.DialogState.Error(
|
||||||
|
title = R.string.master_password_policy_validation_title.asText(),
|
||||||
|
message = R.string.master_password_policy_validation_message.asText(),
|
||||||
|
),
|
||||||
|
passwordInput = password,
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `SubmitClicked with invalid password shows error alert for admin reset reason`() {
|
||||||
val password = "Test123"
|
val password = "Test123"
|
||||||
every {
|
every {
|
||||||
authRepository.passwordResetReason
|
authRepository.passwordResetReason
|
||||||
|
@ -118,26 +110,24 @@ class ResetPasswordViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged(password))
|
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged(password))
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
||||||
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
resetReason = ForcePasswordResetReason.ADMIN_FORCE_PASSWORD_RESET,
|
resetReason = ForcePasswordResetReason.ADMIN_FORCE_PASSWORD_RESET,
|
||||||
dialogState = ResetPasswordState.DialogState.Error(
|
dialogState = ResetPasswordState.DialogState.Error(
|
||||||
title = null,
|
title = null,
|
||||||
message = R.string.master_password_length_val_message_x
|
message = R.string.master_password_length_val_message_x
|
||||||
.asText(MIN_PASSWORD_LENGTH),
|
.asText(MIN_PASSWORD_LENGTH),
|
||||||
),
|
|
||||||
passwordInput = password,
|
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
passwordInput = password,
|
||||||
)
|
),
|
||||||
}
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `SubmitClicked with non-matching retyped password shows error alert`() = runTest {
|
fun `SubmitClicked with non-matching retyped password shows error alert`() {
|
||||||
val password = "Test123"
|
val password = "Test123"
|
||||||
coEvery {
|
coEvery {
|
||||||
authRepository.validatePasswordAgainstPolicies(password)
|
authRepository.validatePasswordAgainstPolicies(password)
|
||||||
|
@ -146,24 +136,22 @@ class ResetPasswordViewModelTest : BaseViewModelTest() {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged(password))
|
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged(password))
|
||||||
|
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
||||||
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
dialogState = ResetPasswordState.DialogState.Error(
|
dialogState = ResetPasswordState.DialogState.Error(
|
||||||
title = null,
|
title = null,
|
||||||
message = R.string.master_password_confirmation_val_message.asText(),
|
message = R.string.master_password_confirmation_val_message.asText(),
|
||||||
),
|
|
||||||
passwordInput = password,
|
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
passwordInput = password,
|
||||||
)
|
),
|
||||||
}
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `SubmitClicked with error for validating current password shows error alert`() = runTest {
|
fun `SubmitClicked with error for validating current password shows error alert`() {
|
||||||
val currentPassword = "CurrentTest123"
|
val currentPassword = "CurrentTest123"
|
||||||
val password = "Test123"
|
val password = "Test123"
|
||||||
coEvery {
|
coEvery {
|
||||||
|
@ -178,26 +166,24 @@ class ResetPasswordViewModelTest : BaseViewModelTest() {
|
||||||
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged(password))
|
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged(password))
|
||||||
viewModel.trySendAction(ResetPasswordAction.RetypePasswordInputChanged(password))
|
viewModel.trySendAction(ResetPasswordAction.RetypePasswordInputChanged(password))
|
||||||
|
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
||||||
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
dialogState = ResetPasswordState.DialogState.Error(
|
dialogState = ResetPasswordState.DialogState.Error(
|
||||||
title = null,
|
title = null,
|
||||||
message = R.string.generic_error_message.asText(),
|
message = R.string.generic_error_message.asText(),
|
||||||
),
|
|
||||||
currentPasswordInput = currentPassword,
|
|
||||||
passwordInput = password,
|
|
||||||
retypePasswordInput = password,
|
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
currentPasswordInput = currentPassword,
|
||||||
)
|
passwordInput = password,
|
||||||
}
|
retypePasswordInput = password,
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `SubmitClicked with invalid current password shows alert`() = runTest {
|
fun `SubmitClicked with invalid current password shows alert`() {
|
||||||
val currentPassword = "CurrentTest123"
|
val currentPassword = "CurrentTest123"
|
||||||
val password = "Test123"
|
val password = "Test123"
|
||||||
coEvery {
|
coEvery {
|
||||||
|
@ -212,22 +198,20 @@ class ResetPasswordViewModelTest : BaseViewModelTest() {
|
||||||
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged(password))
|
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged(password))
|
||||||
viewModel.trySendAction(ResetPasswordAction.RetypePasswordInputChanged(password))
|
viewModel.trySendAction(ResetPasswordAction.RetypePasswordInputChanged(password))
|
||||||
|
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
||||||
viewModel.trySendAction(ResetPasswordAction.SubmitClick)
|
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
dialogState = ResetPasswordState.DialogState.Error(
|
dialogState = ResetPasswordState.DialogState.Error(
|
||||||
title = null,
|
title = null,
|
||||||
message = R.string.invalid_master_password.asText(),
|
message = R.string.invalid_master_password.asText(),
|
||||||
),
|
|
||||||
currentPasswordInput = currentPassword,
|
|
||||||
passwordInput = password,
|
|
||||||
retypePasswordInput = password,
|
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
currentPasswordInput = currentPassword,
|
||||||
)
|
passwordInput = password,
|
||||||
}
|
retypePasswordInput = password,
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -289,49 +273,42 @@ class ResetPasswordViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `PasswordInputChanged should update the password input in the state`() = runTest {
|
fun `PasswordInputChanged should update the password input in the state`() {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged("Test123"))
|
||||||
viewModel.trySendAction(ResetPasswordAction.PasswordInputChanged("Test123"))
|
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
passwordInput = "Test123",
|
passwordInput = "Test123",
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `RetypePasswordInputChanged should update the retype password input in the state`() =
|
fun `RetypePasswordInputChanged should update the retype password input in the state`() {
|
||||||
runTest {
|
val viewModel = createViewModel()
|
||||||
val viewModel = createViewModel()
|
viewModel.trySendAction(ResetPasswordAction.RetypePasswordInputChanged("Test123"))
|
||||||
viewModel.eventFlow.test {
|
|
||||||
viewModel.trySendAction(ResetPasswordAction.RetypePasswordInputChanged("Test123"))
|
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
retypePasswordInput = "Test123",
|
retypePasswordInput = "Test123",
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `PasswordHintInputChanged should update the password hint input in the state`() = runTest {
|
fun `PasswordHintInputChanged should update the password hint input in the state`() {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ResetPasswordAction.PasswordHintInputChanged("Test123"))
|
||||||
viewModel.trySendAction(ResetPasswordAction.PasswordHintInputChanged("Test123"))
|
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
passwordHintInput = "Test123",
|
passwordHintInput = "Test123",
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createViewModel(): ResetPasswordViewModel =
|
private fun createViewModel(): ResetPasswordViewModel =
|
||||||
|
|
|
@ -162,24 +162,6 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
|
||||||
runTest {
|
runTest {
|
||||||
val input = "123456"
|
val input = "123456"
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
|
||||||
viewModel.trySendAction(TwoFactorLoginAction.CodeInputChanged(input))
|
|
||||||
assertEquals(
|
|
||||||
DEFAULT_STATE.copy(
|
|
||||||
codeInput = input,
|
|
||||||
isContinueButtonEnabled = true,
|
|
||||||
),
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `CodeInputChanged should update input and disable button if code is blank`() = runTest {
|
|
||||||
val input = "123456"
|
|
||||||
val viewModel = createViewModel()
|
|
||||||
viewModel.eventFlow.test {
|
|
||||||
// Set it to true.
|
|
||||||
viewModel.trySendAction(TwoFactorLoginAction.CodeInputChanged(input))
|
viewModel.trySendAction(TwoFactorLoginAction.CodeInputChanged(input))
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
|
@ -188,17 +170,31 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
)
|
)
|
||||||
|
|
||||||
// Set it to false.
|
|
||||||
viewModel.trySendAction(TwoFactorLoginAction.CodeInputChanged(""))
|
|
||||||
assertEquals(
|
|
||||||
DEFAULT_STATE.copy(
|
|
||||||
codeInput = "",
|
|
||||||
isContinueButtonEnabled = false,
|
|
||||||
),
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `CodeInputChanged should update input and disable button if code is blank`() {
|
||||||
|
val input = "123456"
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
// Set it to true.
|
||||||
|
viewModel.trySendAction(TwoFactorLoginAction.CodeInputChanged(input))
|
||||||
|
assertEquals(
|
||||||
|
DEFAULT_STATE.copy(
|
||||||
|
codeInput = input,
|
||||||
|
isContinueButtonEnabled = true,
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set it to false.
|
||||||
|
viewModel.trySendAction(TwoFactorLoginAction.CodeInputChanged(""))
|
||||||
|
assertEquals(
|
||||||
|
DEFAULT_STATE.copy(
|
||||||
|
codeInput = "",
|
||||||
|
isContinueButtonEnabled = false,
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -415,17 +411,15 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `RememberMeToggle should update the state`() = runTest {
|
fun `RememberMeToggle should update the state`() {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(TwoFactorLoginAction.RememberMeToggle(true))
|
||||||
viewModel.trySendAction(TwoFactorLoginAction.RememberMeToggle(true))
|
assertEquals(
|
||||||
assertEquals(
|
DEFAULT_STATE.copy(
|
||||||
DEFAULT_STATE.copy(
|
isRememberMeEnabled = true,
|
||||||
isRememberMeEnabled = true,
|
),
|
||||||
),
|
viewModel.stateFlow.value,
|
||||||
viewModel.stateFlow.value,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -534,21 +528,19 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `SelectAuthMethod with other method should update the state`() = runTest {
|
fun `SelectAuthMethod with other method should update the state`() {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(
|
||||||
viewModel.trySendAction(
|
TwoFactorLoginAction.SelectAuthMethod(
|
||||||
TwoFactorLoginAction.SelectAuthMethod(
|
TwoFactorAuthMethod.AUTHENTICATOR_APP,
|
||||||
TwoFactorAuthMethod.AUTHENTICATOR_APP,
|
),
|
||||||
),
|
)
|
||||||
)
|
assertEquals(
|
||||||
assertEquals(
|
DEFAULT_STATE.copy(
|
||||||
DEFAULT_STATE.copy(
|
authMethod = TwoFactorAuthMethod.AUTHENTICATOR_APP,
|
||||||
authMethod = TwoFactorAuthMethod.AUTHENTICATOR_APP,
|
),
|
||||||
),
|
viewModel.stateFlow.value,
|
||||||
viewModel.stateFlow.value,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -569,8 +561,8 @@ class TwoFactorLoginViewModelTest : BaseViewModelTest() {
|
||||||
),
|
),
|
||||||
awaitItem(),
|
awaitItem(),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
|
|
|
@ -86,137 +86,130 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ConfirmExportVaultClicked correct password should call exportVaultDataToString`() =
|
fun `ConfirmExportVaultClicked correct password should call exportVaultDataToString`() {
|
||||||
runTest {
|
val password = "password"
|
||||||
val password = "password"
|
coEvery {
|
||||||
coEvery {
|
authRepository.validatePassword(
|
||||||
authRepository.validatePassword(
|
password = password,
|
||||||
password = password,
|
)
|
||||||
)
|
} returns ValidatePasswordResult.Success(isValid = true)
|
||||||
} returns ValidatePasswordResult.Success(isValid = true)
|
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
||||||
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
|
||||||
|
|
||||||
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
||||||
|
|
||||||
coVerify {
|
coVerify {
|
||||||
vaultRepository.exportVaultDataToString(any())
|
vaultRepository.exportVaultDataToString(any())
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ConfirmExportVaultClicked blank password should show an error`() = runTest {
|
fun `ConfirmExportVaultClicked blank password should show an error`() {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
||||||
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
assertEquals(
|
||||||
assertEquals(
|
DEFAULT_STATE.copy(
|
||||||
DEFAULT_STATE.copy(
|
dialogState = ExportVaultState.DialogState.Error(
|
||||||
dialogState = ExportVaultState.DialogState.Error(
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
message = R.string.validation_field_required.asText(
|
||||||
message = R.string.validation_field_required.asText(
|
R.string.master_password.asText(),
|
||||||
R.string.master_password.asText(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
),
|
||||||
)
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
|
|
||||||
viewModel.trySendAction(ExportVaultAction.DialogDismiss)
|
viewModel.trySendAction(ExportVaultAction.DialogDismiss)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE,
|
DEFAULT_STATE,
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `ConfirmExportVaultClicked blank file password should show an error when export type is JSON_ENCRYPTED`() =
|
fun `ConfirmExportVaultClicked blank file password should show an error when export type is JSON_ENCRYPTED`() {
|
||||||
runTest {
|
val password = "password"
|
||||||
val password = "password"
|
val viewModel = createViewModel()
|
||||||
val viewModel = createViewModel()
|
viewModel.trySendAction(
|
||||||
viewModel.trySendAction(
|
ExportVaultAction.ExportFormatOptionSelect(ExportVaultFormat.JSON_ENCRYPTED),
|
||||||
ExportVaultAction.ExportFormatOptionSelect(ExportVaultFormat.JSON_ENCRYPTED),
|
)
|
||||||
)
|
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
||||||
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
||||||
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
assertEquals(
|
||||||
assertEquals(
|
DEFAULT_STATE.copy(
|
||||||
DEFAULT_STATE.copy(
|
dialogState = ExportVaultState.DialogState.Error(
|
||||||
dialogState = ExportVaultState.DialogState.Error(
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
message = R.string.validation_field_required.asText(
|
||||||
message = R.string.validation_field_required.asText(
|
R.string.file_password.asText(),
|
||||||
R.string.file_password.asText(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
exportFormat = ExportVaultFormat.JSON_ENCRYPTED,
|
|
||||||
passwordInput = password,
|
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
exportFormat = ExportVaultFormat.JSON_ENCRYPTED,
|
||||||
)
|
passwordInput = password,
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
|
|
||||||
viewModel.trySendAction(ExportVaultAction.DialogDismiss)
|
viewModel.trySendAction(ExportVaultAction.DialogDismiss)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
exportFormat = ExportVaultFormat.JSON_ENCRYPTED,
|
exportFormat = ExportVaultFormat.JSON_ENCRYPTED,
|
||||||
passwordInput = password,
|
passwordInput = password,
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `ConfirmExportVaultClicked blank confirm file password should show an error when export type is JSON_ENCRYPTED`() =
|
fun `ConfirmExportVaultClicked blank confirm file password should show an error when export type is JSON_ENCRYPTED`() {
|
||||||
runTest {
|
val password = "password"
|
||||||
val password = "password"
|
coEvery {
|
||||||
coEvery {
|
authRepository.getPasswordStrength(
|
||||||
authRepository.getPasswordStrength(
|
email = EMAIL_ADDRESS,
|
||||||
email = EMAIL_ADDRESS,
|
password = password,
|
||||||
password = password,
|
|
||||||
)
|
|
||||||
} returns PasswordStrengthResult.Success(
|
|
||||||
passwordStrength = PasswordStrength.LEVEL_4,
|
|
||||||
)
|
)
|
||||||
val viewModel = createViewModel()
|
} returns PasswordStrengthResult.Success(
|
||||||
viewModel.trySendAction(
|
passwordStrength = PasswordStrength.LEVEL_4,
|
||||||
ExportVaultAction.ExportFormatOptionSelect(ExportVaultFormat.JSON_ENCRYPTED),
|
)
|
||||||
)
|
val viewModel = createViewModel()
|
||||||
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
viewModel.trySendAction(
|
||||||
viewModel.trySendAction(ExportVaultAction.FilePasswordInputChange(password))
|
ExportVaultAction.ExportFormatOptionSelect(ExportVaultFormat.JSON_ENCRYPTED),
|
||||||
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
)
|
||||||
assertEquals(
|
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
||||||
DEFAULT_STATE.copy(
|
viewModel.trySendAction(ExportVaultAction.FilePasswordInputChange(password))
|
||||||
dialogState = ExportVaultState.DialogState.Error(
|
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
assertEquals(
|
||||||
message = R.string.validation_field_required.asText(
|
DEFAULT_STATE.copy(
|
||||||
R.string.confirm_file_password.asText(),
|
dialogState = ExportVaultState.DialogState.Error(
|
||||||
),
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
|
message = R.string.validation_field_required.asText(
|
||||||
|
R.string.confirm_file_password.asText(),
|
||||||
),
|
),
|
||||||
exportFormat = ExportVaultFormat.JSON_ENCRYPTED,
|
|
||||||
filePasswordInput = password,
|
|
||||||
passwordInput = password,
|
|
||||||
passwordStrengthState = PasswordStrengthState.STRONG,
|
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
exportFormat = ExportVaultFormat.JSON_ENCRYPTED,
|
||||||
)
|
filePasswordInput = password,
|
||||||
|
passwordInput = password,
|
||||||
|
passwordStrengthState = PasswordStrengthState.STRONG,
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
|
|
||||||
viewModel.trySendAction(ExportVaultAction.DialogDismiss)
|
viewModel.trySendAction(ExportVaultAction.DialogDismiss)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
exportFormat = ExportVaultFormat.JSON_ENCRYPTED,
|
exportFormat = ExportVaultFormat.JSON_ENCRYPTED,
|
||||||
filePasswordInput = password,
|
filePasswordInput = password,
|
||||||
passwordInput = password,
|
passwordInput = password,
|
||||||
passwordStrengthState = PasswordStrengthState.STRONG,
|
passwordStrengthState = PasswordStrengthState.STRONG,
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ConfirmExportVaultClicked invalid password should show an error`() = runTest {
|
fun `ConfirmExportVaultClicked invalid password should show an error`() {
|
||||||
val password = "password"
|
val password = "password"
|
||||||
coEvery {
|
coEvery {
|
||||||
authRepository.validatePassword(
|
authRepository.validatePassword(
|
||||||
|
@ -225,21 +218,19 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
||||||
} returns ValidatePasswordResult.Success(isValid = false)
|
} returns ValidatePasswordResult.Success(isValid = false)
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
||||||
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
|
||||||
|
|
||||||
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
dialogState = ExportVaultState.DialogState.Error(
|
dialogState = ExportVaultState.DialogState.Error(
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
message = R.string.invalid_master_password.asText(),
|
message = R.string.invalid_master_password.asText(),
|
||||||
),
|
|
||||||
passwordInput = password,
|
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
passwordInput = password,
|
||||||
)
|
),
|
||||||
}
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
coVerify {
|
coVerify {
|
||||||
authRepository.validatePassword(
|
authRepository.validatePassword(
|
||||||
password = password,
|
password = password,
|
||||||
|
@ -248,7 +239,7 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ConfirmExportVaultClicked error checking password should show an error`() = runTest {
|
fun `ConfirmExportVaultClicked error checking password should show an error`() {
|
||||||
val password = "password"
|
val password = "password"
|
||||||
coEvery {
|
coEvery {
|
||||||
authRepository.validatePassword(
|
authRepository.validatePassword(
|
||||||
|
@ -257,40 +248,35 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
||||||
} returns ValidatePasswordResult.Error
|
} returns ValidatePasswordResult.Error
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
||||||
viewModel.trySendAction(ExportVaultAction.PasswordInputChanged(password))
|
|
||||||
|
|
||||||
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
viewModel.trySendAction(ExportVaultAction.ConfirmExportVaultClicked)
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
dialogState = ExportVaultState.DialogState.Error(
|
dialogState = ExportVaultState.DialogState.Error(
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
message = R.string.generic_error_message.asText(),
|
message = R.string.generic_error_message.asText(),
|
||||||
),
|
|
||||||
passwordInput = password,
|
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
passwordInput = password,
|
||||||
)
|
),
|
||||||
}
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ExportFormatOptionSelect should update the selected export format in the state`() =
|
fun `ExportFormatOptionSelect should update the selected export format in the state`() {
|
||||||
runTest {
|
val viewModel = createViewModel()
|
||||||
val viewModel = createViewModel()
|
viewModel.trySendAction(
|
||||||
viewModel.eventFlow.test {
|
ExportVaultAction.ExportFormatOptionSelect(ExportVaultFormat.CSV),
|
||||||
viewModel.trySendAction(
|
)
|
||||||
ExportVaultAction.ExportFormatOptionSelect(ExportVaultFormat.CSV),
|
|
||||||
)
|
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
exportFormat = ExportVaultFormat.CSV,
|
exportFormat = ExportVaultFormat.CSV,
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
viewModel.stateFlow.value,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ConfirmFilePasswordInputChanged should update the confirm password input in the state`() {
|
fun `ConfirmFilePasswordInputChanged should update the confirm password input in the state`() {
|
||||||
|
@ -348,26 +334,25 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ReceiveExportVaultDataToStringResult should update state to error if result is error`() =
|
fun `ReceiveExportVaultDataToStringResult should update state to error if result is error`() {
|
||||||
runTest {
|
val viewModel = createViewModel()
|
||||||
val viewModel = createViewModel()
|
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
ExportVaultAction.Internal.ReceiveExportVaultDataToStringResult(
|
ExportVaultAction.Internal.ReceiveExportVaultDataToStringResult(
|
||||||
result = ExportVaultDataResult.Error,
|
result = ExportVaultDataResult.Error,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
DEFAULT_STATE.copy(
|
DEFAULT_STATE.copy(
|
||||||
dialogState = ExportVaultState.DialogState.Error(
|
dialogState = ExportVaultState.DialogState.Error(
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
message = R.string.export_vault_failure.asText(),
|
message = R.string.export_vault_failure.asText(),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
viewModel.stateFlow.value,
|
),
|
||||||
)
|
viewModel.stateFlow.value,
|
||||||
}
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
|
@ -493,37 +478,36 @@ class ExportVaultViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ExportLocationReceive should update state to error if saving the data fails`() =
|
fun `ExportLocationReceive should update state to error if saving the data fails`() {
|
||||||
runTest {
|
val exportData = "TestExportVaultData"
|
||||||
val exportData = "TestExportVaultData"
|
val viewModel = createViewModel(
|
||||||
val viewModel = createViewModel(
|
DEFAULT_STATE.copy(
|
||||||
DEFAULT_STATE.copy(
|
exportData = exportData,
|
||||||
exportData = exportData,
|
),
|
||||||
),
|
)
|
||||||
)
|
val uri = mockk<Uri>()
|
||||||
val uri = mockk<Uri>()
|
coEvery {
|
||||||
coEvery {
|
fileManager.stringToUri(fileUri = any(), dataString = exportData)
|
||||||
fileManager.stringToUri(fileUri = any(), dataString = exportData)
|
} returns false
|
||||||
} returns false
|
|
||||||
|
|
||||||
viewModel.trySendAction(ExportVaultAction.ExportLocationReceive(fileUri = uri))
|
viewModel.trySendAction(ExportVaultAction.ExportLocationReceive(fileUri = uri))
|
||||||
|
|
||||||
coVerify {
|
coVerify {
|
||||||
fileManager.stringToUri(fileUri = any(), dataString = exportData)
|
fileManager.stringToUri(fileUri = any(), dataString = exportData)
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
DEFAULT_STATE.copy(
|
|
||||||
exportData = exportData,
|
|
||||||
dialogState = ExportVaultState.DialogState.Error(
|
|
||||||
title = R.string.an_error_has_occurred.asText(),
|
|
||||||
message = R.string.export_vault_failure.asText(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
viewModel.stateFlow.value,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
DEFAULT_STATE.copy(
|
||||||
|
exportData = exportData,
|
||||||
|
dialogState = ExportVaultState.DialogState.Error(
|
||||||
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
|
message = R.string.export_vault_failure.asText(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ExportLocationReceive should emit ShowToast on success`() = runTest {
|
fun `ExportLocationReceive should emit ShowToast on success`() = runTest {
|
||||||
val exportData = "TestExportVaultData"
|
val exportData = "TestExportVaultData"
|
||||||
|
|
Loading…
Reference in a new issue