Skip to content

Commit 84b914a

Browse files
committed
feat: add PasswordResetLinkSent state
1 parent ad1392d commit 84b914a

File tree

3 files changed

+44
-31
lines changed

3 files changed

+44
-31
lines changed

auth/src/main/java/com/firebase/ui/auth/compose/AuthState.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,15 @@ abstract class AuthState private constructor() {
263263
"AuthState.MergeConflict(pendingCredential=$pendingCredential)"
264264
}
265265

266+
/**
267+
* Password reset link has been sent to the user's email.
268+
*/
269+
class PasswordResetLinkSent : AuthState() {
270+
override fun equals(other: Any?): Boolean = other is PasswordResetLinkSent
271+
override fun hashCode(): Int = javaClass.hashCode()
272+
override fun toString(): String = "AuthState.PasswordResetLinkSent"
273+
}
274+
266275
companion object {
267276
/**
268277
* Creates an Idle state instance.

auth/src/main/java/com/firebase/ui/auth/compose/configuration/auth_provider/EmailAuthProvider+FirebaseAuthUI.kt

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -860,8 +860,9 @@ internal suspend fun FirebaseAuthUI.signInWithEmailLink(
860860
* **Flow:**
861861
* 1. Validate the email address exists in Firebase Auth
862862
* 2. Send password reset email to the user
863-
* 3. User clicks link in email to reset password
864-
* 4. User is redirected to Firebase-hosted password reset page (or custom URL if configured)
863+
* 3. Emit [AuthState.PasswordResetLinkSent] state
864+
* 4. User clicks link in email to reset password
865+
* 5. User is redirected to Firebase-hosted password reset page (or custom URL if configured)
865866
*
866867
* **Error Handling:**
867868
* - If the email doesn't exist: throws [AuthException.UserNotFoundException]
@@ -872,8 +873,6 @@ internal suspend fun FirebaseAuthUI.signInWithEmailLink(
872873
* @param actionCodeSettings Optional [ActionCodeSettings] to configure the password reset link.
873874
* Use this to customize the continue URL, dynamic link domain, and other settings.
874875
*
875-
* @return The email address that the reset link was sent to (useful for confirmation UI)
876-
*
877876
* @throws AuthException.UserNotFoundException if no account exists with this email
878877
* @throws AuthException.InvalidCredentialsException if the email format is invalid
879878
* @throws AuthException.NetworkException if a network error occurs
@@ -883,7 +882,7 @@ internal suspend fun FirebaseAuthUI.signInWithEmailLink(
883882
* **Example 1: Basic password reset**
884883
* ```kotlin
885884
* try {
886-
* val email = firebaseAuthUI.sendPasswordResetEmail(
885+
* firebaseAuthUI.sendPasswordResetEmail(
887886
* email = "[email protected]"
888887
* )
889888
* // Show success message: "Password reset email sent to $email"
@@ -906,7 +905,7 @@ internal suspend fun FirebaseAuthUI.signInWithEmailLink(
906905
* )
907906
* .build()
908907
*
909-
* val email = firebaseAuthUI.sendPasswordResetEmail(
908+
* firebaseAuthUI.sendPasswordResetEmail(
910909
* email = "[email protected]",
911910
* actionCodeSettings = actionCodeSettings
912911
* )
@@ -924,18 +923,11 @@ internal suspend fun FirebaseAuthUI.signInWithEmailLink(
924923
internal suspend fun FirebaseAuthUI.sendPasswordResetEmail(
925924
email: String,
926925
actionCodeSettings: ActionCodeSettings? = null
927-
): String {
926+
) {
928927
try {
929928
updateAuthState(AuthState.Loading("Sending password reset email..."))
930-
931-
if (actionCodeSettings != null) {
932-
auth.sendPasswordResetEmail(email, actionCodeSettings).await()
933-
} else {
934-
auth.sendPasswordResetEmail(email).await()
935-
}
936-
937-
updateAuthState(AuthState.Idle)
938-
return email
929+
auth.sendPasswordResetEmail(email, actionCodeSettings).await()
930+
updateAuthState(AuthState.PasswordResetLinkSent())
939931
} catch (e: CancellationException) {
940932
val cancelledException = AuthException.AuthCancelledException(
941933
message = "Send password reset email was cancelled",

auth/src/test/java/com/firebase/ui/auth/compose/configuration/auth_provider/EmailAuthProviderFirebaseAuthUITest.kt

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -618,18 +618,22 @@ class EmailAuthProviderFirebaseAuthUITest {
618618
fun `sendPasswordResetEmail - successfully sends reset email`() = runTest {
619619
val taskCompletionSource = TaskCompletionSource<Void>()
620620
taskCompletionSource.setResult(null)
621-
`when`(mockFirebaseAuth.sendPasswordResetEmail("[email protected]"))
622-
.thenReturn(taskCompletionSource.task)
621+
`when`(mockFirebaseAuth.sendPasswordResetEmail(
622+
ArgumentMatchers.eq("[email protected]"),
623+
ArgumentMatchers.isNull()
624+
)).thenReturn(taskCompletionSource.task)
623625

624626
val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
625627

626-
val result = instance.sendPasswordResetEmail("[email protected]")
628+
instance.sendPasswordResetEmail("[email protected]")
627629

628-
assertThat(result).isEqualTo("[email protected]")
629-
verify(mockFirebaseAuth).sendPasswordResetEmail("[email protected]")
630+
verify(mockFirebaseAuth).sendPasswordResetEmail(
631+
ArgumentMatchers.eq("[email protected]"),
632+
ArgumentMatchers.isNull()
633+
)
630634

631-
val finalState = instance.authStateFlow().first()
632-
assertThat(finalState is AuthState.Idle).isTrue()
635+
val finalState = instance.authStateFlow().first { it is AuthState.PasswordResetLinkSent }
636+
assertThat(finalState).isInstanceOf(AuthState.PasswordResetLinkSent::class.java)
633637
}
634638

635639
@Test
@@ -645,10 +649,12 @@ class EmailAuthProviderFirebaseAuthUITest {
645649

646650
val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
647651

648-
val result = instance.sendPasswordResetEmail("[email protected]", actionCodeSettings)
652+
instance.sendPasswordResetEmail("[email protected]", actionCodeSettings)
649653

650-
assertThat(result).isEqualTo("[email protected]")
651654
verify(mockFirebaseAuth).sendPasswordResetEmail("[email protected]", actionCodeSettings)
655+
656+
val finalState = instance.authStateFlow().first { it is AuthState.PasswordResetLinkSent }
657+
assertThat(finalState).isInstanceOf(AuthState.PasswordResetLinkSent::class.java)
652658
}
653659

654660
@Test
@@ -659,8 +665,10 @@ class EmailAuthProviderFirebaseAuthUITest {
659665
)
660666
val taskCompletionSource = TaskCompletionSource<Void>()
661667
taskCompletionSource.setException(userNotFoundException)
662-
`when`(mockFirebaseAuth.sendPasswordResetEmail("[email protected]"))
663-
.thenReturn(taskCompletionSource.task)
668+
`when`(mockFirebaseAuth.sendPasswordResetEmail(
669+
ArgumentMatchers.eq("[email protected]"),
670+
ArgumentMatchers.isNull()
671+
)).thenReturn(taskCompletionSource.task)
664672

665673
val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
666674

@@ -680,8 +688,10 @@ class EmailAuthProviderFirebaseAuthUITest {
680688
)
681689
val taskCompletionSource = TaskCompletionSource<Void>()
682690
taskCompletionSource.setException(invalidEmailException)
683-
`when`(mockFirebaseAuth.sendPasswordResetEmail("[email protected]"))
684-
.thenReturn(taskCompletionSource.task)
691+
`when`(mockFirebaseAuth.sendPasswordResetEmail(
692+
ArgumentMatchers.eq("[email protected]"),
693+
ArgumentMatchers.isNull()
694+
)).thenReturn(taskCompletionSource.task)
685695

686696
val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
687697

@@ -698,8 +708,10 @@ class EmailAuthProviderFirebaseAuthUITest {
698708
val cancellationException = CancellationException("Operation cancelled")
699709
val taskCompletionSource = TaskCompletionSource<Void>()
700710
taskCompletionSource.setException(cancellationException)
701-
`when`(mockFirebaseAuth.sendPasswordResetEmail("[email protected]"))
702-
.thenReturn(taskCompletionSource.task)
711+
`when`(mockFirebaseAuth.sendPasswordResetEmail(
712+
ArgumentMatchers.eq("[email protected]"),
713+
ArgumentMatchers.isNull()
714+
)).thenReturn(taskCompletionSource.task)
703715

704716
val instance = FirebaseAuthUI.create(firebaseApp, mockFirebaseAuth)
705717

0 commit comments

Comments
 (0)