Skip to content

Commit c7cc486

Browse files
test: write tests for legacyFetchSignInWithEmail
1 parent 96506d9 commit c7cc486

3 files changed

Lines changed: 196 additions & 1 deletion

File tree

auth/src/test/java/com/firebase/ui/auth/configuration/AuthUIConfigurationTest.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class AuthUIConfigurationTest {
8888
assertThat(config.isNewEmailAccountsAllowed).isTrue()
8989
assertThat(config.isDisplayNameRequired).isTrue()
9090
assertThat(config.isProviderChoiceAlwaysShown).isFalse()
91+
assertThat(config.legacyFetchSignInWithEmail).isFalse()
9192
}
9293

9394
@Test
@@ -129,6 +130,7 @@ class AuthUIConfigurationTest {
129130
isNewEmailAccountsAllowed = false
130131
isDisplayNameRequired = false
131132
isProviderChoiceAlwaysShown = true
133+
legacyFetchSignInWithEmail = true
132134
}
133135

134136
assertThat(config.context).isEqualTo(applicationContext)
@@ -147,6 +149,7 @@ class AuthUIConfigurationTest {
147149
assertThat(config.isNewEmailAccountsAllowed).isFalse()
148150
assertThat(config.isDisplayNameRequired).isFalse()
149151
assertThat(config.isProviderChoiceAlwaysShown).isTrue()
152+
assertThat(config.legacyFetchSignInWithEmail).isTrue()
150153
}
151154

152155
@Test
@@ -465,6 +468,7 @@ class AuthUIConfigurationTest {
465468
"isNewEmailAccountsAllowed",
466469
"isDisplayNameRequired",
467470
"isProviderChoiceAlwaysShown",
471+
"legacyFetchSignInWithEmail",
468472
"transitions"
469473
)
470474

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

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import com.google.firebase.auth.FirebaseAuthInvalidUserException
3737
import com.google.firebase.auth.FirebaseAuthUserCollisionException
3838
import com.google.firebase.auth.FirebaseUser
3939
import com.google.firebase.auth.GoogleAuthProvider
40+
import com.google.firebase.auth.SignInMethodQueryResult
4041
import kotlinx.coroutines.CancellationException
4142
import kotlinx.coroutines.flow.first
4243
import 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(

auth/src/test/java/com/firebase/ui/auth/ui/components/ErrorRecoveryDialogLogicTest.kt

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package com.firebase.ui.auth.ui.components
33
import com.firebase.ui.auth.AuthException
44
import com.firebase.ui.auth.configuration.string_provider.AuthUIStringProvider
55
import com.google.common.truth.Truth
6+
import com.google.firebase.auth.EmailAuthProvider
7+
import com.google.firebase.auth.GoogleAuthProvider
68
import org.junit.Test
79
import org.junit.runner.RunWith
810
import org.mockito.Mockito
@@ -20,6 +22,8 @@ class ErrorRecoveryDialogLogicTest {
2022
Mockito.`when`(retryAction).thenReturn("Try again")
2123
Mockito.`when`(continueText).thenReturn("Continue")
2224
Mockito.`when`(signInDefault).thenReturn("Sign in")
25+
Mockito.`when`(continueWithGoogle).thenReturn("Continue with Google")
26+
Mockito.`when`(signInWithEmailLink).thenReturn("Sign in with email link")
2327
Mockito.`when`(networkErrorRecoveryMessage).thenReturn("Network error, check your internet connection.")
2428
Mockito.`when`(invalidCredentialsRecoveryMessage).thenReturn("Incorrect password.")
2529
Mockito.`when`(userNotFoundRecoveryMessage).thenReturn("That email address doesn't match an existing account")
@@ -216,6 +220,34 @@ class ErrorRecoveryDialogLogicTest {
216220
Truth.assertThat(actionText).isEqualTo("Continue")
217221
}
218222

223+
@Test
224+
fun `getRecoveryActionText returns provider specific action for DifferentSignInMethodRequiredException`() {
225+
val error = AuthException.DifferentSignInMethodRequiredException(
226+
message = "Use a different sign-in method",
227+
email = "test@example.com",
228+
signInMethods = listOf(GoogleAuthProvider.PROVIDER_ID),
229+
suggestedSignInMethod = GoogleAuthProvider.PROVIDER_ID
230+
)
231+
232+
val actionText = getRecoveryActionText(error, mockStringProvider)
233+
234+
Truth.assertThat(actionText).isEqualTo("Continue with Google")
235+
}
236+
237+
@Test
238+
fun `getRecoveryActionText returns email link action for DifferentSignInMethodRequiredException`() {
239+
val error = AuthException.DifferentSignInMethodRequiredException(
240+
message = "Use a different sign-in method",
241+
email = "test@example.com",
242+
signInMethods = listOf(EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD),
243+
suggestedSignInMethod = EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD
244+
)
245+
246+
val actionText = getRecoveryActionText(error, mockStringProvider)
247+
248+
Truth.assertThat(actionText).isEqualTo("Sign in with email link")
249+
}
250+
219251
@Test
220252
fun `getRecoveryActionText returns continue for MfaRequiredException`() {
221253
// Arrange
@@ -302,6 +334,8 @@ class ErrorRecoveryDialogLogicTest {
302334
is AuthException.TooManyRequestsException -> stringProvider.tooManyRequestsRecoveryMessage
303335
is AuthException.MfaRequiredException -> stringProvider.mfaRequiredRecoveryMessage
304336
is AuthException.AccountLinkingRequiredException -> stringProvider.accountLinkingRequiredRecoveryMessage
337+
is AuthException.DifferentSignInMethodRequiredException ->
338+
error.message ?: stringProvider.accountLinkingRequiredRecoveryMessage
305339
is AuthException.AuthCancelledException -> stringProvider.authCancelledRecoveryMessage
306340
is AuthException.UnknownException -> stringProvider.unknownErrorRecoveryMessage
307341
else -> stringProvider.unknownErrorRecoveryMessage
@@ -313,6 +347,11 @@ class ErrorRecoveryDialogLogicTest {
313347
is AuthException.AuthCancelledException -> stringProvider.continueText
314348
is AuthException.EmailAlreadyInUseException -> stringProvider.signInDefault
315349
is AuthException.AccountLinkingRequiredException -> stringProvider.continueText
350+
is AuthException.DifferentSignInMethodRequiredException -> when (error.suggestedSignInMethod) {
351+
GoogleAuthProvider.PROVIDER_ID -> stringProvider.continueWithGoogle
352+
EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD -> stringProvider.signInWithEmailLink
353+
else -> stringProvider.continueText
354+
}
316355
is AuthException.MfaRequiredException -> stringProvider.continueText
317356
is AuthException.NetworkException,
318357
is AuthException.InvalidCredentialsException,
@@ -334,9 +373,10 @@ class ErrorRecoveryDialogLogicTest {
334373
is AuthException.TooManyRequestsException -> false
335374
is AuthException.MfaRequiredException -> true
336375
is AuthException.AccountLinkingRequiredException -> true
376+
is AuthException.DifferentSignInMethodRequiredException -> true
337377
is AuthException.AuthCancelledException -> true
338378
is AuthException.UnknownException -> true
339379
else -> true
340380
}
341381
}
342-
}
382+
}

0 commit comments

Comments
 (0)