@@ -37,6 +37,7 @@ import com.google.firebase.auth.FirebaseAuthInvalidUserException
3737import com.google.firebase.auth.FirebaseAuthUserCollisionException
3838import com.google.firebase.auth.FirebaseUser
3939import com.google.firebase.auth.GoogleAuthProvider
40+ import com.google.firebase.auth.SignInMethodQueryResult
4041import kotlinx.coroutines.CancellationException
4142import kotlinx.coroutines.flow.first
4243import kotlinx.coroutines.test.runTest
@@ -413,6 +414,156 @@ class EmailAuthProviderFirebaseAuthUITest {
413414 }
414415 }
415416
417+ @Test
418+ fun `signInWithEmailAndPassword - uses legacy provider recovery when configured` () = runTest {
419+ val invalidCredentialsException = FirebaseAuthInvalidCredentialsException (
420+ " ERROR_WRONG_PASSWORD" ,
421+ " Wrong password"
422+ )
423+ val signInTask = TaskCompletionSource <AuthResult >()
424+ signInTask.setException(invalidCredentialsException)
425+ `when `(mockFirebaseAuth.signInWithEmailAndPassword(" test@example.com" , " Pass@123" ))
426+ .thenReturn(signInTask.task)
427+
428+ val queryResult = mock(SignInMethodQueryResult ::class .java)
429+ `when `(queryResult.signInMethods).thenReturn(listOf (GoogleAuthProvider .PROVIDER_ID ))
430+ val fetchTask = TaskCompletionSource <SignInMethodQueryResult >()
431+ fetchTask.setResult(queryResult)
432+ `when `(mockFirebaseAuth.fetchSignInMethodsForEmail(" test@example.com" ))
433+ .thenReturn(fetchTask.task)
434+
435+ val instance = FirebaseAuthUI .create(firebaseApp, mockFirebaseAuth)
436+ val emailProvider = AuthProvider .Email (
437+ emailLinkActionCodeSettings = null ,
438+ passwordValidationRules = emptyList()
439+ )
440+ val config = authUIConfiguration {
441+ context = applicationContext
442+ providers {
443+ provider(emailProvider)
444+ provider(
445+ AuthProvider .Google (
446+ scopes = emptyList(),
447+ serverClientId = " test-client-id"
448+ )
449+ )
450+ }
451+ legacyFetchSignInWithEmail = true
452+ }
453+
454+ try {
455+ instance.signInWithEmailAndPassword(
456+ context = applicationContext,
457+ config = config,
458+ email = " test@example.com" ,
459+ password = " Pass@123"
460+ )
461+ assertThat(false ).isTrue()
462+ } catch (e: AuthException .DifferentSignInMethodRequiredException ) {
463+ assertThat(e.email).isEqualTo(" test@example.com" )
464+ assertThat(e.signInMethods).containsExactly(GoogleAuthProvider .PROVIDER_ID )
465+ assertThat(e.suggestedSignInMethod).isEqualTo(GoogleAuthProvider .PROVIDER_ID )
466+ assertThat(e.cause).isEqualTo(invalidCredentialsException)
467+ }
468+
469+ val currentState = instance.authStateFlow().first { it is AuthState .Error }
470+ val errorState = currentState as AuthState .Error
471+ assertThat(errorState.exception)
472+ .isInstanceOf(AuthException .DifferentSignInMethodRequiredException ::class .java)
473+ verify(mockFirebaseAuth).fetchSignInMethodsForEmail(" test@example.com" )
474+ }
475+
476+ @Test
477+ fun `signInWithEmailAndPassword - keeps invalid credentials when password sign in is available` () = runTest {
478+ val invalidCredentialsException = FirebaseAuthInvalidCredentialsException (
479+ " ERROR_WRONG_PASSWORD" ,
480+ " Wrong password"
481+ )
482+ val signInTask = TaskCompletionSource <AuthResult >()
483+ signInTask.setException(invalidCredentialsException)
484+ `when `(mockFirebaseAuth.signInWithEmailAndPassword(" test@example.com" , " Pass@123" ))
485+ .thenReturn(signInTask.task)
486+
487+ val queryResult = mock(SignInMethodQueryResult ::class .java)
488+ `when `(queryResult.signInMethods)
489+ .thenReturn(listOf (com.google.firebase.auth.EmailAuthProvider .EMAIL_PASSWORD_SIGN_IN_METHOD ))
490+ val fetchTask = TaskCompletionSource <SignInMethodQueryResult >()
491+ fetchTask.setResult(queryResult)
492+ `when `(mockFirebaseAuth.fetchSignInMethodsForEmail(" test@example.com" ))
493+ .thenReturn(fetchTask.task)
494+
495+ val instance = FirebaseAuthUI .create(firebaseApp, mockFirebaseAuth)
496+ val emailProvider = AuthProvider .Email (
497+ emailLinkActionCodeSettings = null ,
498+ passwordValidationRules = emptyList()
499+ )
500+ val config = authUIConfiguration {
501+ context = applicationContext
502+ providers {
503+ provider(emailProvider)
504+ }
505+ legacyFetchSignInWithEmail = true
506+ }
507+
508+ try {
509+ instance.signInWithEmailAndPassword(
510+ context = applicationContext,
511+ config = config,
512+ email = " test@example.com" ,
513+ password = " Pass@123"
514+ )
515+ assertThat(false ).isTrue()
516+ } catch (e: AuthException .InvalidCredentialsException ) {
517+ assertThat(e.cause).isEqualTo(invalidCredentialsException)
518+ }
519+
520+ verify(mockFirebaseAuth).fetchSignInMethodsForEmail(" test@example.com" )
521+ }
522+
523+ @Test
524+ fun `signInWithEmailAndPassword - does not use legacy provider recovery when disabled` () = runTest {
525+ val invalidCredentialsException = FirebaseAuthInvalidCredentialsException (
526+ " ERROR_WRONG_PASSWORD" ,
527+ " Wrong password"
528+ )
529+ val signInTask = TaskCompletionSource <AuthResult >()
530+ signInTask.setException(invalidCredentialsException)
531+ `when `(mockFirebaseAuth.signInWithEmailAndPassword(" test@example.com" , " Pass@123" ))
532+ .thenReturn(signInTask.task)
533+
534+ val instance = FirebaseAuthUI .create(firebaseApp, mockFirebaseAuth)
535+ val emailProvider = AuthProvider .Email (
536+ emailLinkActionCodeSettings = null ,
537+ passwordValidationRules = emptyList()
538+ )
539+ val config = authUIConfiguration {
540+ context = applicationContext
541+ providers {
542+ provider(emailProvider)
543+ provider(
544+ AuthProvider .Google (
545+ scopes = emptyList(),
546+ serverClientId = " test-client-id"
547+ )
548+ )
549+ }
550+ }
551+
552+ try {
553+ instance.signInWithEmailAndPassword(
554+ context = applicationContext,
555+ config = config,
556+ email = " test@example.com" ,
557+ password = " Pass@123"
558+ )
559+ assertThat(false ).isTrue()
560+ } catch (e: AuthException .InvalidCredentialsException ) {
561+ assertThat(e.cause).isEqualTo(invalidCredentialsException)
562+ }
563+
564+ verify(mockFirebaseAuth, never()).fetchSignInMethodsForEmail(anyString())
565+ }
566+
416567 @Test
417568 fun `signInWithEmailAndPassword - handles user not found` () = runTest {
418569 val userNotFoundException = FirebaseAuthInvalidUserException (
0 commit comments