handling the reset password completion step within the view model and emitting view events to move the flow forwards

This commit is contained in:
Adam Brown 2022-06-08 09:51:11 +01:00
parent 47cedfb522
commit 16481df0f7
7 changed files with 53 additions and 18 deletions

View File

@ -47,10 +47,11 @@ sealed class OnboardingViewEvents : VectorViewEvents {
object OnHomeserverEdited : OnboardingViewEvents()
data class OnSignModeSelected(val signMode: SignMode) : OnboardingViewEvents()
object OnForgetPasswordClicked : OnboardingViewEvents()
data class OnResetPasswordSendThreePidDone(val email: String) : OnboardingViewEvents()
object OnResetPasswordMailConfirmationSuccess : OnboardingViewEvents()
data class OnResetPasswordEmailConfirmationSent(val email: String) : OnboardingViewEvents()
object OpenResetPasswordComplete : OnboardingViewEvents()
object OnResetPasswordBreakerConfirmed : OnboardingViewEvents()
object OnResetPasswordMailConfirmationSuccessDone : OnboardingViewEvents()
object OnResetPasswordComplete : OnboardingViewEvents()
data class OnSendEmailSuccess(val email: String) : OnboardingViewEvents()
data class OnSendMsisdnSuccess(val msisdn: String) : OnboardingViewEvents()

View File

@ -443,7 +443,7 @@ class OnboardingViewModel @AssistedInject constructor(
private fun handleResetPassword(action: OnboardingAction.ResetPassword) {
startResetPasswordFlow(action.email) {
setState { copy(isLoading = false, resetState = createResetState(action, selectedHomeserver)) }
_viewEvents.post(OnboardingViewEvents.OnResetPasswordSendThreePidDone(action.email))
_viewEvents.post(OnboardingViewEvents.OnResetPasswordEmailConfirmationSent(action.email))
}
}
@ -506,7 +506,11 @@ class OnboardingViewModel @AssistedInject constructor(
runCatching { loginWizard.resetPasswordMailConfirmed(newPassword, logoutAllDevices = logoutAllDevices) }.fold(
onSuccess = {
setState { copy(isLoading = false, resetState = ResetState()) }
_viewEvents.post(OnboardingViewEvents.OnResetPasswordMailConfirmationSuccess)
val nextEvent = when {
vectorFeatures.isOnboardingCombinedLoginEnabled() -> OnboardingViewEvents.OnResetPasswordComplete
else -> OnboardingViewEvents.OpenResetPasswordComplete
}
_viewEvents.post(nextEvent)
},
onFailure = {
setState { copy(isLoading = false) }

View File

@ -41,7 +41,7 @@ class FtueAuthResetPasswordSuccessFragment @Inject constructor() : AbstractFtueA
}
private fun submit() {
viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnResetPasswordMailConfirmationSuccessDone))
viewModel.handle(OnboardingAction.PostViewEvent(OnboardingViewEvents.OnResetPasswordComplete))
}
override fun resetViewModel() {

View File

@ -29,7 +29,6 @@ import androidx.fragment.app.FragmentTransaction
import com.airbnb.mvrx.withState
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import im.vector.app.R
import im.vector.app.core.extensions.POP_BACK_STACK_EXCLUSIVE
import im.vector.app.core.extensions.addFragment
import im.vector.app.core.extensions.addFragmentToBackstack
import im.vector.app.core.extensions.popBackstack
@ -166,7 +165,7 @@ class FtueAuthVariant(
vectorFeatures.isOnboardingCombinedLoginEnabled() -> addLoginStageFragmentToBackstack(FtueAuthResetPasswordEmailEntryFragment::class.java)
else -> addLoginStageFragmentToBackstack(FtueAuthResetPasswordFragment::class.java)
}
is OnboardingViewEvents.OnResetPasswordSendThreePidDone -> {
is OnboardingViewEvents.OnResetPasswordEmailConfirmationSent -> {
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE)
when {
vectorFeatures.isOnboardingCombinedLoginEnabled() -> addLoginStageFragmentToBackstack(
@ -187,12 +186,11 @@ class FtueAuthVariant(
option = commonOption
)
}
is OnboardingViewEvents.OnResetPasswordMailConfirmationSuccess -> {
is OnboardingViewEvents.OpenResetPasswordComplete -> {
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE)
addLoginStageFragmentToBackstack(FtueAuthResetPasswordSuccessFragment::class.java)
}
is OnboardingViewEvents.OnResetPasswordMailConfirmationSuccessDone -> {
// Go back to the login fragment
OnboardingViewEvents.OnResetPasswordComplete -> {
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, FragmentManager.POP_BACK_STACK_INCLUSIVE)
}
is OnboardingViewEvents.OnSendEmailSuccess -> {

View File

@ -478,7 +478,7 @@ class OnboardingViewModelTest {
}
@Test
fun `given can successfully reset password, when resetting password, then emits reset done event`() = runTest {
fun `given can successfully start password reset, when resetting password, then emits confirmation email sent`() = runTest {
viewModelWith(initialState.copy(selectedHomeserver = SELECTED_HOMESERVER_STATE_SUPPORTED_LOGOUT_DEVICES))
val test = viewModel.test()
fakeLoginWizard.givenResetPasswordSuccess(AN_EMAIL)
@ -495,12 +495,12 @@ class OnboardingViewModelTest {
copy(isLoading = false, resetState = resetState)
}
)
.assertEvents(OnboardingViewEvents.OnResetPasswordSendThreePidDone(AN_EMAIL))
.assertEvents(OnboardingViewEvents.OnResetPasswordEmailConfirmationSent(AN_EMAIL))
.finish()
}
@Test
fun `given reset state, when resending reset password email, then emits reset success`() = runTest {
fun `given reset state, when resending reset password email, then triggers reset password and emits nothing`() = runTest {
viewModelWith(initialState.copy(resetState = ResetState(AN_EMAIL, A_PASSWORD)))
val test = viewModel.test()
fakeLoginWizard.givenResetPasswordSuccess(AN_EMAIL)
@ -516,12 +516,14 @@ class OnboardingViewModelTest {
)
.assertNoEvents()
.finish()
fakeLoginWizard.verifyResetPassword(AN_EMAIL)
}
@Test
fun `given can successfully confirm reset password, when confirm reset password, then emits reset success`() = runTest {
fun `given can successfully confirm reset password, when confirm reset password, then opens reset password complete`() = runTest {
viewModelWith(initialState.copy(resetState = ResetState(AN_EMAIL, A_PASSWORD)))
val test = viewModel.test()
fakeVectorFeatures.givenCombinedLoginDisabled()
fakeLoginWizard.givenConfirmResetPasswordSuccess(A_PASSWORD)
fakeAuthenticationService.givenLoginWizard(fakeLoginWizard)
@ -533,10 +535,31 @@ class OnboardingViewModelTest {
{ copy(isLoading = true) },
{ copy(isLoading = false, resetState = ResetState()) }
)
.assertEvents(OnboardingViewEvents.OnResetPasswordMailConfirmationSuccess)
.assertEvents(OnboardingViewEvents.OpenResetPasswordComplete)
.finish()
}
@Test
fun `given can successfully confirm reset password, when confirm reset password, then emits reset password complete`() = runTest {
viewModelWith(initialState.copy(resetState = ResetState(AN_EMAIL, A_PASSWORD)))
val test = viewModel.test()
fakeVectorFeatures.givenCombinedLoginEnabled()
fakeLoginWizard.givenConfirmResetPasswordSuccess(A_PASSWORD)
fakeAuthenticationService.givenLoginWizard(fakeLoginWizard)
viewModel.handle(OnboardingAction.ResetPasswordMailConfirmed)
test
.assertStatesChanges(
initialState,
{ copy(isLoading = true) },
{ copy(isLoading = false, resetState = ResetState()) }
)
.assertEvents(OnboardingViewEvents.OnResetPasswordComplete)
.finish()
}
private fun viewModelWith(state: OnboardingViewState) {
OnboardingViewModel(
state,

View File

@ -17,6 +17,7 @@
package im.vector.app.test.fakes
import io.mockk.coJustRun
import io.mockk.coVerify
import io.mockk.mockk
import org.matrix.android.sdk.api.auth.login.LoginWizard
@ -29,4 +30,8 @@ class FakeLoginWizard : LoginWizard by mockk() {
fun givenConfirmResetPasswordSuccess(password: String) {
coJustRun { resetPasswordMailConfirmed(password) }
}
fun verifyResetPassword(email: String) {
coVerify { resetPassword(email) }
}
}

View File

@ -27,7 +27,11 @@ class FakeVectorFeatures : VectorFeatures by spyk<DefaultVectorFeatures>() {
every { isOnboardingPersonalizeEnabled() } returns true
}
fun givenCombinedRegisterEnabled() {
every { isOnboardingCombinedRegisterEnabled() } returns true
fun givenCombinedLoginEnabled() {
every { isOnboardingCombinedLoginEnabled() } returns true
}
fun givenCombinedLoginDisabled() {
every { isOnboardingCombinedLoginEnabled() } returns false
}
}