mirror of
https://github.com/bitwarden/android.git
synced 2024-11-22 01:16:02 +03:00
BIT-193 Implement password length validation on create account (#96)
This commit is contained in:
parent
cf628bce3f
commit
a95a07f313
5 changed files with 189 additions and 14 deletions
|
@ -21,9 +21,11 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import com.x8bit.bitwarden.R
|
import com.x8bit.bitwarden.R
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.ConfirmPasswordInputChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.ConfirmPasswordInputChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.EmailInputChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.EmailInputChange
|
||||||
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.ErrorDialogDismiss
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordHintChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordHintChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordInputChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordInputChange
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
|
||||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledButton
|
import com.x8bit.bitwarden.ui.platform.components.BitwardenFilledButton
|
||||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenPasswordField
|
import com.x8bit.bitwarden.ui.platform.components.BitwardenPasswordField
|
||||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextButtonTopAppBar
|
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextButtonTopAppBar
|
||||||
|
@ -48,6 +50,10 @@ fun CreateAccountScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BitwardenBasicDialog(
|
||||||
|
visibilityState = state.errorDialogState,
|
||||||
|
onDismissRequest = remember(viewModel) { { viewModel.trySendAction(ErrorDialogDismiss) } },
|
||||||
|
)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -65,7 +71,7 @@ fun CreateAccountScreen(
|
||||||
onButtonClick = remember(viewModel) {
|
onButtonClick = remember(viewModel) {
|
||||||
{ viewModel.trySendAction(CreateAccountAction.SubmitClick) }
|
{ viewModel.trySendAction(CreateAccountAction.SubmitClick) }
|
||||||
},
|
},
|
||||||
isButtonEnabled = state.isSubmitEnabled,
|
isButtonEnabled = true,
|
||||||
)
|
)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(horizontal = 16.dp),
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
@ -104,7 +110,7 @@ fun CreateAccountScreen(
|
||||||
BitwardenFilledButton(
|
BitwardenFilledButton(
|
||||||
label = stringResource(id = R.string.submit),
|
label = stringResource(id = R.string.submit),
|
||||||
onClick = remember { { viewModel.trySendAction(CreateAccountAction.SubmitClick) } },
|
onClick = remember { { viewModel.trySendAction(CreateAccountAction.SubmitClick) } },
|
||||||
isEnabled = state.isSubmitEnabled,
|
isEnabled = true,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,15 @@ package com.x8bit.bitwarden.ui.auth.feature.createaccount
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.x8bit.bitwarden.R
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.ConfirmPasswordInputChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.ConfirmPasswordInputChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.EmailInputChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.EmailInputChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordHintChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordHintChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordInputChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordInputChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.SubmitClick
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.SubmitClick
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||||
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.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
@ -17,6 +20,7 @@ import kotlinx.parcelize.Parcelize
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private const val KEY_STATE = "state"
|
private const val KEY_STATE = "state"
|
||||||
|
private const val MIN_PASSWORD_LENGTH = 12
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Models logic for the create account screen.
|
* Models logic for the create account screen.
|
||||||
|
@ -31,7 +35,7 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
passwordInput = "",
|
passwordInput = "",
|
||||||
confirmPasswordInput = "",
|
confirmPasswordInput = "",
|
||||||
passwordHintInput = "",
|
passwordHintInput = "",
|
||||||
isSubmitEnabled = false,
|
errorDialogState = BasicDialogState.Hidden,
|
||||||
),
|
),
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -50,6 +54,13 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
is PasswordHintChange -> handlePasswordHintChanged(action)
|
is PasswordHintChange -> handlePasswordHintChanged(action)
|
||||||
is PasswordInputChange -> handlePasswordInputChanged(action)
|
is PasswordInputChange -> handlePasswordInputChanged(action)
|
||||||
is CreateAccountAction.CloseClick -> handleCloseClick()
|
is CreateAccountAction.CloseClick -> handleCloseClick()
|
||||||
|
is CreateAccountAction.ErrorDialogDismiss -> handleDialogDismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleDialogDismiss() {
|
||||||
|
mutableStateFlow.update {
|
||||||
|
it.copy(errorDialogState = BasicDialogState.Hidden)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,9 +84,19 @@ class CreateAccountViewModel @Inject constructor(
|
||||||
mutableStateFlow.update { it.copy(confirmPasswordInput = action.input) }
|
mutableStateFlow.update { it.copy(confirmPasswordInput = action.input) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSubmitClick() {
|
private fun handleSubmitClick() = when {
|
||||||
|
mutableStateFlow.value.passwordInput.length < MIN_PASSWORD_LENGTH -> {
|
||||||
|
val dialog = BasicDialogState.Shown(
|
||||||
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
|
message = R.string.master_password_length_val_message_x.asText(MIN_PASSWORD_LENGTH),
|
||||||
|
)
|
||||||
|
mutableStateFlow.update { it.copy(errorDialogState = dialog) }
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
sendEvent(CreateAccountEvent.ShowToast("TODO: Handle Submit Click"))
|
sendEvent(CreateAccountEvent.ShowToast("TODO: Handle Submit Click"))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -87,7 +108,7 @@ data class CreateAccountState(
|
||||||
val passwordInput: String,
|
val passwordInput: String,
|
||||||
val confirmPasswordInput: String,
|
val confirmPasswordInput: String,
|
||||||
val passwordHintInput: String,
|
val passwordHintInput: String,
|
||||||
val isSubmitEnabled: Boolean,
|
val errorDialogState: BasicDialogState,
|
||||||
) : Parcelable
|
) : Parcelable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,4 +160,9 @@ sealed class CreateAccountAction {
|
||||||
* Password hint input changed.
|
* Password hint input changed.
|
||||||
*/
|
*/
|
||||||
data class PasswordHintChange(val input: String) : CreateAccountAction()
|
data class PasswordHintChange(val input: String) : CreateAccountAction()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User dismissed the error dialog.
|
||||||
|
*/
|
||||||
|
data object ErrorDialogDismiss : CreateAccountAction()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.components
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import com.x8bit.bitwarden.R
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a Bitwarden-styled dialog that is hidden or shown based on [visibilityState].
|
||||||
|
*
|
||||||
|
* @param visibilityState the [BasicDialogState] used to populate the dialog.
|
||||||
|
* @param onDismissRequest called when the user has requested to dismiss the dialog, whether by
|
||||||
|
* tapping "OK", tapping outside the dialog, or pressing the back button.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun BitwardenBasicDialog(
|
||||||
|
visibilityState: BasicDialogState,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
): Unit = when (visibilityState) {
|
||||||
|
BasicDialogState.Hidden -> Unit
|
||||||
|
is BasicDialogState.Shown -> {
|
||||||
|
AlertDialog(
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
confirmButton = {
|
||||||
|
BitwardenTextButton(
|
||||||
|
label = stringResource(id = R.string.ok),
|
||||||
|
onClick = onDismissRequest,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = visibilityState.title(),
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
text = visibilityState.message(),
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models display of a [BitwardenBasicDialog].
|
||||||
|
*/
|
||||||
|
sealed class BasicDialogState : Parcelable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the dialog.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data object Hidden : BasicDialogState()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the dialog with the given values.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class Shown(
|
||||||
|
val title: Text,
|
||||||
|
val message: Text,
|
||||||
|
) : BasicDialogState()
|
||||||
|
}
|
|
@ -1,5 +1,9 @@
|
||||||
package com.x8bit.bitwarden.ui.auth.feature.createaccount
|
package com.x8bit.bitwarden.ui.auth.feature.createaccount
|
||||||
|
|
||||||
|
import androidx.compose.ui.test.assertIsDisplayed
|
||||||
|
import androidx.compose.ui.test.filterToOne
|
||||||
|
import androidx.compose.ui.test.hasAnyAncestor
|
||||||
|
import androidx.compose.ui.test.isDialog
|
||||||
import androidx.compose.ui.test.onAllNodesWithText
|
import androidx.compose.ui.test.onAllNodesWithText
|
||||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
|
@ -12,6 +16,8 @@ import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.Pas
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordInputChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordInputChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.SubmitClick
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.SubmitClick
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
|
@ -25,7 +31,7 @@ class CreateAccountScreenTest : BaseComposeTest() {
|
||||||
@Test
|
@Test
|
||||||
fun `app bar submit click should send SubmitClick action`() {
|
fun `app bar submit click should send SubmitClick action`() {
|
||||||
val viewModel = mockk<CreateAccountViewModel>(relaxed = true) {
|
val viewModel = mockk<CreateAccountViewModel>(relaxed = true) {
|
||||||
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE.copy(isSubmitEnabled = true))
|
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
|
||||||
every { eventFlow } returns emptyFlow()
|
every { eventFlow } returns emptyFlow()
|
||||||
every { trySendAction(SubmitClick) } returns Unit
|
every { trySendAction(SubmitClick) } returns Unit
|
||||||
}
|
}
|
||||||
|
@ -39,7 +45,7 @@ class CreateAccountScreenTest : BaseComposeTest() {
|
||||||
@Test
|
@Test
|
||||||
fun `bottom button submit click should send SubmitClick action`() {
|
fun `bottom button submit click should send SubmitClick action`() {
|
||||||
val viewModel = mockk<CreateAccountViewModel>(relaxed = true) {
|
val viewModel = mockk<CreateAccountViewModel>(relaxed = true) {
|
||||||
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE.copy(isSubmitEnabled = true))
|
every { stateFlow } returns MutableStateFlow(DEFAULT_STATE)
|
||||||
every { eventFlow } returns emptyFlow()
|
every { eventFlow } returns emptyFlow()
|
||||||
every { trySendAction(SubmitClick) } returns Unit
|
every { trySendAction(SubmitClick) } returns Unit
|
||||||
}
|
}
|
||||||
|
@ -136,6 +142,50 @@ class CreateAccountScreenTest : BaseComposeTest() {
|
||||||
verify { viewModel.trySendAction(PasswordHintChange(TEST_INPUT)) }
|
verify { viewModel.trySendAction(PasswordHintChange(TEST_INPUT)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `clicking OK on the error dialog should send ErrorDialogDismiss action`() {
|
||||||
|
val viewModel = mockk<CreateAccountViewModel>(relaxed = true) {
|
||||||
|
every { stateFlow } returns MutableStateFlow(
|
||||||
|
DEFAULT_STATE.copy(
|
||||||
|
errorDialogState = BasicDialogState.Shown(
|
||||||
|
title = "title".asText(),
|
||||||
|
message = "message".asText(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
every { eventFlow } returns emptyFlow()
|
||||||
|
every { trySendAction(CreateAccountAction.ErrorDialogDismiss) } returns Unit
|
||||||
|
}
|
||||||
|
composeTestRule.setContent {
|
||||||
|
CreateAccountScreen(onNavigateBack = {}, viewModel = viewModel)
|
||||||
|
}
|
||||||
|
composeTestRule
|
||||||
|
.onAllNodesWithText("Ok")
|
||||||
|
.filterToOne(hasAnyAncestor(isDialog()))
|
||||||
|
.performClick()
|
||||||
|
verify { viewModel.trySendAction(CreateAccountAction.ErrorDialogDismiss) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `when BasicDialogState is Shown should show dialog`() {
|
||||||
|
val viewModel = mockk<CreateAccountViewModel>(relaxed = true) {
|
||||||
|
every { stateFlow } returns MutableStateFlow(
|
||||||
|
DEFAULT_STATE.copy(
|
||||||
|
errorDialogState = BasicDialogState.Shown(
|
||||||
|
title = "title".asText(),
|
||||||
|
message = "message".asText(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
every { eventFlow } returns emptyFlow()
|
||||||
|
every { trySendAction(CreateAccountAction.ErrorDialogDismiss) } returns Unit
|
||||||
|
}
|
||||||
|
composeTestRule.setContent {
|
||||||
|
CreateAccountScreen(onNavigateBack = {}, viewModel = viewModel)
|
||||||
|
}
|
||||||
|
composeTestRule.onNode(isDialog()).assertIsDisplayed()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TEST_INPUT = "input"
|
private const val TEST_INPUT = "input"
|
||||||
private val DEFAULT_STATE = CreateAccountState(
|
private val DEFAULT_STATE = CreateAccountState(
|
||||||
|
@ -143,7 +193,7 @@ class CreateAccountScreenTest : BaseComposeTest() {
|
||||||
passwordInput = "",
|
passwordInput = "",
|
||||||
confirmPasswordInput = "",
|
confirmPasswordInput = "",
|
||||||
passwordHintInput = "",
|
passwordHintInput = "",
|
||||||
isSubmitEnabled = false,
|
errorDialogState = BasicDialogState.Hidden,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,15 @@ package com.x8bit.bitwarden.ui.auth.feature.createaccount
|
||||||
|
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
|
import com.x8bit.bitwarden.R
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.CloseClick
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.CloseClick
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.ConfirmPasswordInputChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.ConfirmPasswordInputChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.EmailInputChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.EmailInputChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordHintChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordHintChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordInputChange
|
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.PasswordInputChange
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.createaccount.CreateAccountAction.SubmitClick
|
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
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 kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
@ -28,7 +30,7 @@ class CreateAccountViewModelTest : BaseViewModelTest() {
|
||||||
passwordInput = "password",
|
passwordInput = "password",
|
||||||
confirmPasswordInput = "confirmPassword",
|
confirmPasswordInput = "confirmPassword",
|
||||||
passwordHintInput = "hint",
|
passwordHintInput = "hint",
|
||||||
isSubmitEnabled = false,
|
errorDialogState = BasicDialogState.Hidden,
|
||||||
)
|
)
|
||||||
val handle = SavedStateHandle(mapOf("state" to savedState))
|
val handle = SavedStateHandle(mapOf("state" to savedState))
|
||||||
val viewModel = CreateAccountViewModel(handle)
|
val viewModel = CreateAccountViewModel(handle)
|
||||||
|
@ -36,10 +38,29 @@ class CreateAccountViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `SubmitClick should emit ShowToast`() = runTest {
|
fun `SubmitClick with password below 12 chars should show password length dialog`() = runTest {
|
||||||
val viewModel = CreateAccountViewModel(SavedStateHandle())
|
val viewModel = CreateAccountViewModel(SavedStateHandle())
|
||||||
|
val input = "abcdefghikl"
|
||||||
|
viewModel.trySendAction(PasswordInputChange("abcdefghikl"))
|
||||||
|
val expectedState = DEFAULT_STATE.copy(
|
||||||
|
passwordInput = input,
|
||||||
|
errorDialogState = BasicDialogState.Shown(
|
||||||
|
title = R.string.an_error_has_occurred.asText(),
|
||||||
|
message = R.string.master_password_length_val_message_x.asText(12),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
viewModel.actionChannel.trySend(CreateAccountAction.SubmitClick)
|
||||||
|
viewModel.stateFlow.test {
|
||||||
|
assertEquals(expectedState, awaitItem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `SubmitClick with long enough password emit ShowToast`() = runTest {
|
||||||
|
val viewModel = CreateAccountViewModel(SavedStateHandle())
|
||||||
|
viewModel.trySendAction(PasswordInputChange("longenoughpassword"))
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.actionChannel.trySend(SubmitClick)
|
viewModel.actionChannel.trySend(CreateAccountAction.SubmitClick)
|
||||||
assert(awaitItem() is CreateAccountEvent.ShowToast)
|
assert(awaitItem() is CreateAccountEvent.ShowToast)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +116,7 @@ class CreateAccountViewModelTest : BaseViewModelTest() {
|
||||||
emailInput = "",
|
emailInput = "",
|
||||||
confirmPasswordInput = "",
|
confirmPasswordInput = "",
|
||||||
passwordHintInput = "",
|
passwordHintInput = "",
|
||||||
isSubmitEnabled = false,
|
errorDialogState = BasicDialogState.Hidden,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue