Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions source/ui/src/main/java/com/clerk/ui/auth/AuthStartViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import com.clerk.api.credentials.shouldFallbackToOAuthFromGoogleOneTap
import com.clerk.api.credentials.shouldSuppressAutomaticCredentialFlowError
import com.clerk.api.credentials.shouldSuppressCredentialFlowError
import com.clerk.api.log.ClerkLog
import com.clerk.api.network.model.error.ClerkErrorResponse
import com.clerk.api.network.serialization.ClerkResult
import com.clerk.api.network.serialization.errorMessage
import com.clerk.api.network.serialization.onFailure
Expand Down Expand Up @@ -180,14 +179,13 @@ internal class AuthStartViewModel(private val ioDispatcher: CoroutineDispatcher
SignIn.create(SignIn.CreateParams.Strategy.Identifier(identifier = resolvedIdentifier))
.onSuccess { signIn -> handleSignInSuccess(signIn, transferable) }
.onFailure {
if (withSignUp && it.error is ClerkErrorResponse) {
val matchingCodes = listOf(FORM_IDENTIFIER_NOT_FOUND, INVITATION_ACCOUNT_NOT_EXISTS)
val hasMatchingError = it.error?.errors?.any { it.code in matchingCodes } ?: false
if (hasMatchingError) {
signUp(isPhoneNumberFieldActive, identifier, phoneNumber, unsafeMetadata)
} else {
_state.value = AuthState.Error(it.errorMessage)
}
val matchingCodes = listOf(FORM_IDENTIFIER_NOT_FOUND, INVITATION_ACCOUNT_NOT_EXISTS)
val shouldSignUp =
withSignUp && it.error?.errors?.any { error -> error.code in matchingCodes } == true
if (shouldSignUp) {
signUp(isPhoneNumberFieldActive, identifier, phoneNumber, unsafeMetadata)
} else {
_state.value = AuthState.Error(it.errorMessage)
}
}
}
Expand Down
47 changes: 47 additions & 0 deletions source/ui/src/test/java/com/clerk/ui/auth/AuthViewModelTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,53 @@ class AuthViewModelTest {
}
}

@Test
fun startAuthWithSignInModeShouldSurfaceApiFailure() = runTest {
mockkObject(SignIn.Companion)
coEvery { SignIn.create(any<SignIn.CreateParams.Strategy>()) } returns
ClerkResult.apiFailure(
ClerkErrorResponse(errors = listOf(ClerkError(longMessage = "Couldn't find your account.")))
)

viewModel.state.test {
assertEquals(AuthStartViewModel.AuthState.Idle, awaitItem())

viewModel.startAuth(
authMode = AuthMode.SignIn,
isPhoneNumberFieldActive = false,
phoneNumber = "",
identifier = "test@example.com",
)

assertEquals(AuthStartViewModel.AuthState.Loading, awaitItem())
assertEquals(AuthStartViewModel.AuthState.Error("Couldn't find your account."), awaitItem())
}
}

@Test
fun startAuthWithSignInModeShouldSurfaceUnknownFailure() = runTest {
mockkObject(SignIn.Companion)
coEvery { SignIn.create(any<SignIn.CreateParams.Strategy>()) } returns
ClerkResult.unknownFailure(IllegalStateException("Network unavailable"))

viewModel.state.test {
assertEquals(AuthStartViewModel.AuthState.Idle, awaitItem())

viewModel.startAuth(
authMode = AuthMode.SignIn,
isPhoneNumberFieldActive = false,
phoneNumber = "",
identifier = "test@example.com",
)

assertEquals(AuthStartViewModel.AuthState.Loading, awaitItem())
assertEquals(
AuthStartViewModel.AuthState.Error("Error occurred with unknown message."),
awaitItem(),
)
}
}

@Test
fun automaticPasskeySignInUsesPasskeyStrategy() = runTest {
val signIn = SignIn(id = "sign_in_123")
Expand Down