diff --git a/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt b/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt index 6868bf0dae..fa617cbc9a 100644 --- a/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/onboarding/OnboardingViewModelTest.kt @@ -33,6 +33,7 @@ import im.vector.app.test.fakes.FakeHomeServerConnectionConfigFactory import im.vector.app.test.fakes.FakeHomeServerHistoryService import im.vector.app.test.fakes.FakeLoginWizard import im.vector.app.test.fakes.FakeRegistrationActionHandler +import im.vector.app.test.fakes.FakeRegistrationWizard import im.vector.app.test.fakes.FakeSession import im.vector.app.test.fakes.FakeStartAuthenticationFlowUseCase import im.vector.app.test.fakes.FakeStringProvider @@ -41,6 +42,7 @@ import im.vector.app.test.fakes.FakeUriFilenameResolver import im.vector.app.test.fakes.FakeVectorFeatures import im.vector.app.test.fakes.FakeVectorOverrides import im.vector.app.test.fakes.toTestString +import im.vector.app.test.fixtures.a401ServerError import im.vector.app.test.fixtures.aBuildMeta import im.vector.app.test.fixtures.aHomeServerCapabilities import im.vector.app.test.test @@ -50,11 +52,13 @@ import org.junit.Rule import org.junit.Test import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.registration.Stage +import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities private const val A_DISPLAY_NAME = "a display name" private const val A_PICTURE_FILENAME = "a-picture.png" +private val A_SERVER_ERROR = a401ServerError() private val AN_ERROR = RuntimeException("an error!") private val A_LOADABLE_REGISTER_ACTION = RegisterAction.StartRegistration private val A_NON_LOADABLE_REGISTER_ACTION = RegisterAction.CheckIfEmailHasBeenValidated(delayMillis = -1L) @@ -64,7 +68,7 @@ private val ANY_CONTINUING_REGISTRATION_RESULT = RegistrationActionHandler.Resul private val A_DIRECT_LOGIN = OnboardingAction.AuthenticateAction.LoginDirect("@a-user:id.org", "a-password", "a-device-name") private const val A_HOMESERVER_URL = "https://edited-homeserver.org" private val A_HOMESERVER_CONFIG = HomeServerConnectionConfig(FakeUri().instance) -private val SELECTED_HOMESERVER_STATE = SelectedHomeserverState(preferredLoginMode = LoginMode.Password) +private val SELECTED_HOMESERVER_STATE = SelectedHomeserverState(preferredLoginMode = LoginMode.Password, userFacingUrl = A_HOMESERVER_URL) private val SELECTED_HOMESERVER_STATE_SUPPORTED_LOGOUT_DEVICES = SelectedHomeserverState(isLogoutDevicesSupported = true) private const val AN_EMAIL = "hello@example.com" private const val A_PASSWORD = "a-password" @@ -323,6 +327,93 @@ class OnboardingViewModelTest { .finish() } + @Test + fun `given available username, when a register username is entered, then emits available registration state`() = runTest { + viewModelWith(initialRegistrationState(A_HOMESERVER_URL)) + val onlyUsername = "a-username" + givenUserNameIsAvailable(onlyUsername) + val test = viewModel.test() + + viewModel.handle(OnboardingAction.UserNameEnteredAction.Registration(onlyUsername)) + + test + .assertStatesChanges( + initialState, + { copy(registrationState = availableRegistrationState(onlyUsername, A_HOMESERVER_URL)) } + ) + .assertNoEvents() + .finish() + } + + @Test + fun `given unavailable username, when a register username is entered, then emits availability error`() = runTest { + viewModelWith(initialRegistrationState(A_HOMESERVER_URL)) + val onlyUsername = "a-username" + givenUserNameIsUnavailable(onlyUsername, A_SERVER_ERROR) + val test = viewModel.test() + + viewModel.handle(OnboardingAction.UserNameEnteredAction.Registration(onlyUsername)) + + test + .assertState(initialState) + .assertEvents(OnboardingViewEvents.Failure(A_SERVER_ERROR)) + .finish() + } + + @Test + fun `given available full matrix id, when a register username is entered, then changes homeserver and emits available registration state`() = runTest { + viewModelWith(initialRegistrationState("ignored-url")) + givenCanSuccessfullyUpdateHomeserver(A_HOMESERVER_URL, SELECTED_HOMESERVER_STATE) + val userName = "a-user" + val fullMatrixId = "@$userName:${A_HOMESERVER_URL.removePrefix("https://")}" + givenUserNameIsAvailable(userName) + val test = viewModel.test() + + viewModel.handle(OnboardingAction.UserNameEnteredAction.Registration(fullMatrixId)) + + test + .assertStatesChanges( + initialState, + { copy(isLoading = true) }, + { copy(selectedHomeserver = SELECTED_HOMESERVER_STATE) }, + { copy(registrationState = availableRegistrationState(userName, A_HOMESERVER_URL)) }, + { copy(isLoading = false) }, + ) + .assertEvents(OnboardingViewEvents.OnHomeserverEdited) + .finish() + } + + @Test + fun `given unavailable full matrix id, when a register username is entered, then emits availability error`() = runTest { + viewModelWith(initialRegistrationState("ignored-url")) + givenCanSuccessfullyUpdateHomeserver(A_HOMESERVER_URL, SELECTED_HOMESERVER_STATE) + val userName = "a-user" + val fullMatrixId = "@$userName:${A_HOMESERVER_URL.removePrefix("https://")}" + givenUserNameIsUnavailable(userName, A_SERVER_ERROR) + val test = viewModel.test() + + viewModel.handle(OnboardingAction.UserNameEnteredAction.Registration(fullMatrixId)) + + test + .assertStatesChanges( + initialState, + { copy(isLoading = true) }, + { copy(selectedHomeserver = SELECTED_HOMESERVER_STATE) }, + { copy(isLoading = false) }, + ) + .assertEvents(OnboardingViewEvents.OnHomeserverEdited, OnboardingViewEvents.Failure(A_SERVER_ERROR)) + .finish() + } + + private fun availableRegistrationState(userName: String, homeServerUrl: String) = RegistrationState( + isUserNameAvailable = true, + selectedMatrixId = "@$userName:${homeServerUrl.removePrefix("https://")}" + ) + + private fun initialRegistrationState(homeServerUrl: String) = initialState.copy( + onboardingFlow = OnboardingFlow.SignUp, selectedHomeserver = SelectedHomeserverState(userFacingUrl = homeServerUrl) + ) + @Test fun `given in the sign up flow, when editing homeserver errors, then does not update the selected homeserver state and emits error`() = runTest { viewModelWith(initialState.copy(onboardingFlow = OnboardingFlow.SignUp)) @@ -639,6 +730,14 @@ class OnboardingViewModelTest { givenRegistrationResultFor(RegisterAction.StartRegistration, RegistrationActionHandler.Result.Error(error)) fakeHomeServerHistoryService.expectUrlToBeAdded(A_HOMESERVER_CONFIG.homeServerUri.toString()) } + + private fun givenUserNameIsAvailable(userName: String) { + fakeAuthenticationService.givenRegistrationWizard(FakeRegistrationWizard().also { it.givenUserNameIsAvailable(userName) }) + } + + private fun givenUserNameIsUnavailable(userName: String, failure: Failure.ServerError) { + fakeAuthenticationService.givenRegistrationWizard(FakeRegistrationWizard().also { it.givenUserNameIsUnavailable(userName, failure) }) + } } private fun HomeServerCapabilities.toPersonalisationState() = PersonalizationState( diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeRegistrationWizard.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeRegistrationWizard.kt index 55a40faaac..e0b4586931 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeRegistrationWizard.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeRegistrationWizard.kt @@ -20,8 +20,10 @@ import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk import org.matrix.android.sdk.api.auth.registration.RegisterThreePid +import org.matrix.android.sdk.api.auth.registration.RegistrationAvailability import org.matrix.android.sdk.api.auth.registration.RegistrationResult import org.matrix.android.sdk.api.auth.registration.RegistrationWizard +import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.Session class FakeRegistrationWizard : RegistrationWizard by mockk(relaxed = false) { @@ -43,6 +45,14 @@ class FakeRegistrationWizard : RegistrationWizard by mockk(relaxed = false) { } } + fun givenUserNameIsAvailable(userName: String) { + coEvery { registrationAvailable(userName) } returns RegistrationAvailability.Available + } + + fun givenUserNameIsUnavailable(userName: String, failure: Failure.ServerError) { + coEvery { registrationAvailable(userName) } returns RegistrationAvailability.NotAvailable(failure) + } + fun verifyCheckedEmailedVerification(times: Int) { coVerify(exactly = times) { checkIfEmailHasBeenValidated(any()) } }