@@ -21,6 +21,9 @@ import com.amplifyframework.auth.AuthUserAttributeKey.email
2121import com.amplifyframework.auth.AuthUserAttributeKey.emailVerified
2222import com.amplifyframework.auth.MFAType
2323import com.amplifyframework.auth.exceptions.UnknownException
24+ import com.amplifyframework.auth.result.AuthResetPasswordResult
25+ import com.amplifyframework.auth.result.step.AuthNextResetPasswordStep
26+ import com.amplifyframework.auth.result.step.AuthResetPasswordStep
2427import com.amplifyframework.auth.result.step.AuthSignInStep
2528import com.amplifyframework.ui.authenticator.auth.VerificationMechanism
2629import com.amplifyframework.ui.authenticator.enums.AuthenticatorStep
@@ -353,6 +356,125 @@ class AuthenticatorViewModelTest {
353356 }
354357
355358// endregion
359+ // region password reset tests
360+
361+ @Test
362+ fun `Sign in with temporary password requires password reset` () = runTest {
363+ coEvery { authProvider.fetchAuthSession() } returns Success (mockAuthSession(isSignedIn = false ))
364+ coEvery { authProvider.signIn(any(), any()) } returns Success (
365+ mockSignInResult(
366+ signInStep = AuthSignInStep .RESET_PASSWORD
367+ )
368+ )
369+
370+ viewModel.start(mockAuthenticatorConfiguration(initialStep = AuthenticatorStep .SignIn ))
371+
372+ viewModel.signIn(" username" , " password" )
373+ viewModel.currentStep shouldBe AuthenticatorStep .PasswordReset
374+ }
375+
376+ @Test
377+ fun `Password reset returns a result of DONE, state should be sign in` () = runTest {
378+ coEvery { authProvider.fetchAuthSession() } returns Success (mockAuthSession(isSignedIn = false ))
379+ coEvery { authProvider.resetPassword(any()) } returns Success (
380+ AuthResetPasswordResult (
381+ true ,
382+ AuthNextResetPasswordStep (AuthResetPasswordStep .DONE , emptyMap(), null )
383+ )
384+ )
385+ viewModel.start(mockAuthenticatorConfiguration(initialStep = AuthenticatorStep .PasswordReset ))
386+
387+ viewModel.resetPassword(" username" )
388+ viewModel.currentStep shouldBe AuthenticatorStep .SignIn
389+ }
390+
391+ @Test
392+ fun `Password reset fails with an error, state should stay in PasswordReset` () = runTest {
393+ coEvery { authProvider.fetchAuthSession() } returns Success (mockAuthSession(isSignedIn = false ))
394+ coEvery { authProvider.resetPassword(any()) } returns Error (
395+ mockk<UnknownException > {
396+ every { cause } returns mockk<HttpException > {
397+ every { cause } returns mockk<UnknownHostException >()
398+ }
399+ }
400+ )
401+ viewModel.start(mockAuthenticatorConfiguration(initialStep = AuthenticatorStep .PasswordReset ))
402+
403+ viewModel.resetPassword(" username" )
404+ viewModel.currentStep shouldBe AuthenticatorStep .PasswordReset
405+ }
406+
407+ @Test
408+ fun `Password reset confirmation succeeds, sign in succeeds, state should be signed in` () = runTest {
409+ coEvery { authProvider.fetchAuthSession() } returns Success (mockAuthSession(isSignedIn = false ))
410+ coEvery { authProvider.resetPassword(any()) } returns Success (
411+ AuthResetPasswordResult (
412+ true ,
413+ AuthNextResetPasswordStep (AuthResetPasswordStep .CONFIRM_RESET_PASSWORD_WITH_CODE , emptyMap(), null )
414+ )
415+ )
416+
417+ coEvery { authProvider.confirmResetPassword(any(), any(), any()) } returns Success (Unit )
418+ coEvery { authProvider.signIn(any(), any()) } returns Success (mockSignInResult())
419+
420+ viewModel.start(mockAuthenticatorConfiguration(initialStep = AuthenticatorStep .PasswordReset ))
421+
422+ viewModel.resetPassword(" username" )
423+ viewModel.confirmResetPassword(" username" , " password" , " code" )
424+ viewModel.currentStep shouldBe AuthenticatorStep .SignedIn
425+ }
426+
427+ @Test
428+ fun `Password reset confirmation fails, state should stay in PasswordResetConfirm` () = runTest {
429+ coEvery { authProvider.fetchAuthSession() } returns Success (mockAuthSession(isSignedIn = false ))
430+ coEvery { authProvider.resetPassword(any()) } returns Success (
431+ AuthResetPasswordResult (
432+ true ,
433+ AuthNextResetPasswordStep (AuthResetPasswordStep .CONFIRM_RESET_PASSWORD_WITH_CODE , emptyMap(), null )
434+ )
435+ )
436+
437+ coEvery { authProvider.confirmResetPassword(any(), any(), any()) } returns Error (
438+ mockk<UnknownException > {
439+ every { cause } returns mockk<HttpException > {
440+ every { cause } returns mockk<UnknownHostException >()
441+ }
442+ }
443+ )
444+
445+ viewModel.start(mockAuthenticatorConfiguration(initialStep = AuthenticatorStep .PasswordReset ))
446+
447+ viewModel.resetPassword(" username" )
448+ viewModel.confirmResetPassword(" username" , " password" , " code" )
449+ viewModel.currentStep shouldBe AuthenticatorStep .PasswordResetConfirm
450+ }
451+
452+ @Test
453+ fun `Password reset confirmation succeeds, sign in fails, state should be sign in` () = runTest {
454+ coEvery { authProvider.fetchAuthSession() } returns Success (mockAuthSession(isSignedIn = false ))
455+ coEvery { authProvider.resetPassword(any()) } returns Success (
456+ AuthResetPasswordResult (
457+ true ,
458+ AuthNextResetPasswordStep (AuthResetPasswordStep .CONFIRM_RESET_PASSWORD_WITH_CODE , emptyMap(), null )
459+ )
460+ )
461+
462+ coEvery { authProvider.confirmResetPassword(any(), any(), any()) } returns Success (Unit )
463+ coEvery { authProvider.signIn(any(), any()) } returns Error (
464+ mockk<UnknownException > {
465+ every { cause } returns mockk<HttpException > {
466+ every { cause } returns mockk<UnknownHostException >()
467+ }
468+ }
469+ )
470+
471+ viewModel.start(mockAuthenticatorConfiguration(initialStep = AuthenticatorStep .PasswordReset ))
472+
473+ viewModel.resetPassword(" username" )
474+ viewModel.confirmResetPassword(" username" , " password" , " code" )
475+ viewModel.currentStep shouldBe AuthenticatorStep .SignIn
476+ }
477+ // endregion
356478// region helpers
357479 private val AuthenticatorViewModel .currentStep: AuthenticatorStep
358480 get() = stepState.value.step
0 commit comments