adding test around editing error flow and reducing initial test state setup boilerplate

This commit is contained in:
Adam Brown 2022-04-14 11:05:02 +01:00
parent c9e0868917
commit 5001be9f21
2 changed files with 60 additions and 30 deletions

View File

@ -73,7 +73,6 @@ class OnboardingViewModelTest {
private val fakeUri = FakeUri()
private val fakeContext = FakeContext()
private val initialState = OnboardingViewState()
private val fakeSession = FakeSession()
private val fakeUriFilenameResolver = FakeUriFilenameResolver()
private val fakeActiveSessionHolder = FakeActiveSessionHolder(fakeSession)
@ -85,11 +84,12 @@ class OnboardingViewModelTest {
private val fakeStartAuthenticationFlowUseCase = FakeStartAuthenticationFlowUseCase()
private val fakeHomeServerHistoryService = FakeHomeServerHistoryService()
lateinit var viewModel: OnboardingViewModel
private var initialState = OnboardingViewState()
private lateinit var viewModel: OnboardingViewModel
@Before
fun setUp() {
viewModel = createViewModel()
viewModelWith(initialState)
}
@Test
@ -105,8 +105,7 @@ class OnboardingViewModelTest {
@Test
fun `given supports changing display name, when handling PersonalizeProfile, then emits contents choose display name`() = runTest {
val initialState = initialState.copy(personalizationState = PersonalizationState(supportsChangingDisplayName = true, supportsChangingProfilePicture = false))
viewModel = createViewModel(initialState)
viewModelWith(initialState.copy(personalizationState = PersonalizationState(supportsChangingDisplayName = true, supportsChangingProfilePicture = false)))
val test = viewModel.test()
viewModel.handle(OnboardingAction.PersonalizeProfile)
@ -118,8 +117,7 @@ class OnboardingViewModelTest {
@Test
fun `given only supports changing profile picture, when handling PersonalizeProfile, then emits contents choose profile picture`() = runTest {
val initialState = initialState.copy(personalizationState = PersonalizationState(supportsChangingDisplayName = false, supportsChangingProfilePicture = true))
viewModel = createViewModel(initialState)
viewModelWith(initialState.copy(personalizationState = PersonalizationState(supportsChangingDisplayName = false, supportsChangingProfilePicture = true)))
val test = viewModel.test()
viewModel.handle(OnboardingAction.PersonalizeProfile)
@ -131,8 +129,7 @@ class OnboardingViewModelTest {
@Test
fun `given has sign in with matrix id sign mode, when handling login or register action, then logs in directly`() = runTest {
val initialState = initialState.copy(signMode = SignMode.SignInWithMatrixId)
viewModel = createViewModel(initialState)
viewModelWith(initialState.copy(signMode = SignMode.SignInWithMatrixId))
fakeDirectLoginUseCase.givenSuccessResult(A_LOGIN_OR_REGISTER_ACTION, config = null, result = fakeSession)
givenInitialisesSession(fakeSession)
val test = viewModel.test()
@ -151,8 +148,7 @@ class OnboardingViewModelTest {
@Test
fun `given has sign in with matrix id sign mode, when handling login or register action fails, then emits error`() = runTest {
val initialState = initialState.copy(signMode = SignMode.SignInWithMatrixId)
viewModel = createViewModel(initialState)
viewModelWith(initialState.copy(signMode = SignMode.SignInWithMatrixId))
fakeDirectLoginUseCase.givenFailureResult(A_LOGIN_OR_REGISTER_ACTION, config = null, cause = AN_ERROR)
givenInitialisesSession(fakeSession)
val test = viewModel.test()
@ -235,11 +231,13 @@ class OnboardingViewModelTest {
}
@Test
fun `given when editing homeserver, then updates selected homeserver state and emits edited event`() = runTest {
val test = viewModel.test()
fun `given in the sign up flow, when editing homeserver, then updates selected homeserver state and emits edited event`() = runTest {
viewModelWith(initialState.copy(onboardingFlow = OnboardingFlow.SignUp))
fakeHomeServerConnectionConfigFactory.givenConfigFor(A_HOMESERVER_URL, A_HOMESERVER_CONFIG)
fakeStartAuthenticationFlowUseCase.givenResult(A_HOMESERVER_CONFIG, StartAuthenticationResult(false, SELECTED_HOMESERVER_STATE))
fakeStartAuthenticationFlowUseCase.givenResult(A_HOMESERVER_CONFIG, StartAuthenticationResult(isHomeserverOutdated = false, SELECTED_HOMESERVER_STATE))
givenRegistrationResultFor(RegisterAction.StartRegistration, RegistrationResult.FlowResponse(AN_IGNORED_FLOW_RESULT))
fakeHomeServerHistoryService.expectUrlToBeAdded(A_HOMESERVER_CONFIG.homeServerUri.toString())
val test = viewModel.test()
viewModel.handle(OnboardingAction.HomeServerChange.EditHomeServer(A_HOMESERVER_URL))
@ -247,12 +245,35 @@ class OnboardingViewModelTest {
.assertStatesChanges(
initialState,
{ copy(isLoading = true) },
{ copy(isLoading = false, selectedHomeserver = SELECTED_HOMESERVER_STATE) },
{ copy(selectedHomeserver = SELECTED_HOMESERVER_STATE) },
{ copy(isLoading = false) }
)
.assertEvents(OnboardingViewEvents.OnHomeserverEdited)
.finish()
}
@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))
fakeHomeServerConnectionConfigFactory.givenConfigFor(A_HOMESERVER_URL, A_HOMESERVER_CONFIG)
fakeStartAuthenticationFlowUseCase.givenResult(A_HOMESERVER_CONFIG, StartAuthenticationResult(isHomeserverOutdated = false, SELECTED_HOMESERVER_STATE))
givenRegistrationActionErrors(RegisterAction.StartRegistration, AN_ERROR)
fakeHomeServerHistoryService.expectUrlToBeAdded(A_HOMESERVER_CONFIG.homeServerUri.toString())
val test = viewModel.test()
viewModel.handle(OnboardingAction.HomeServerChange.EditHomeServer(A_HOMESERVER_URL))
test
.assertStatesChanges(
initialState,
{ copy(isLoading = true) },
{ copy(isLoading = false) }
)
.assertEvents(OnboardingViewEvents.Failure(AN_ERROR))
.finish()
}
@Test
fun `given personalisation enabled, when registering account, then updates state and emits account created event`() = runTest {
fakeVectorFeatures.givenPersonalisationEnabled()
@ -292,14 +313,13 @@ class OnboardingViewModelTest {
@Test
fun `given changing profile picture is supported, when updating display name, then updates upstream user display name and moves to choose profile picture`() = runTest {
val personalisedInitialState = initialState.copy(personalizationState = PersonalizationState(supportsChangingProfilePicture = true))
viewModel = createViewModel(personalisedInitialState)
viewModelWith(initialState.copy(personalizationState = PersonalizationState(supportsChangingProfilePicture = true)))
val test = viewModel.test()
viewModel.handle(OnboardingAction.UpdateDisplayName(A_DISPLAY_NAME))
test
.assertStatesChanges(personalisedInitialState, expectedSuccessfulDisplayNameUpdateStates())
.assertStatesChanges(initialState, expectedSuccessfulDisplayNameUpdateStates())
.assertEvents(OnboardingViewEvents.OnChooseProfilePicture)
.finish()
fakeSession.fakeProfileService.verifyUpdatedName(fakeSession.myUserId, A_DISPLAY_NAME)
@ -307,14 +327,13 @@ class OnboardingViewModelTest {
@Test
fun `given changing profile picture is not supported, when updating display name, then updates upstream user display name and completes personalization`() = runTest {
val personalisedInitialState = initialState.copy(personalizationState = PersonalizationState(supportsChangingProfilePicture = false))
viewModel = createViewModel(personalisedInitialState)
viewModelWith(initialState.copy(personalizationState = PersonalizationState(supportsChangingProfilePicture = false)))
val test = viewModel.test()
viewModel.handle(OnboardingAction.UpdateDisplayName(A_DISPLAY_NAME))
test
.assertStatesChanges(personalisedInitialState, expectedSuccessfulDisplayNameUpdateStates())
.assertStatesChanges(initialState, expectedSuccessfulDisplayNameUpdateStates())
.assertEvents(OnboardingViewEvents.OnPersonalizationComplete)
.finish()
fakeSession.fakeProfileService.verifyUpdatedName(fakeSession.myUserId, A_DISPLAY_NAME)
@ -354,14 +373,13 @@ class OnboardingViewModelTest {
@Test
fun `given a selected picture, when handling save selected profile picture, then updates upstream avatar and completes personalization`() = runTest {
val initialStateWithPicture = givenPictureSelected(fakeUri.instance, A_PICTURE_FILENAME)
viewModel = createViewModel(initialStateWithPicture)
viewModelWith(givenPictureSelected(fakeUri.instance, A_PICTURE_FILENAME))
val test = viewModel.test()
viewModel.handle(OnboardingAction.SaveSelectedProfilePicture)
test
.assertStates(expectedProfilePictureSuccessStates(initialStateWithPicture))
.assertStates(expectedProfilePictureSuccessStates(initialState))
.assertEvents(OnboardingViewEvents.OnPersonalizationComplete)
.finish()
fakeSession.fakeProfileService.verifyAvatarUpdated(fakeSession.myUserId, fakeUri.instance, A_PICTURE_FILENAME)
@ -370,14 +388,13 @@ class OnboardingViewModelTest {
@Test
fun `given upstream update avatar fails, when saving selected profile picture, then emits failure event`() = runTest {
fakeSession.fakeProfileService.givenUpdateAvatarErrors(AN_ERROR)
val initialStateWithPicture = givenPictureSelected(fakeUri.instance, A_PICTURE_FILENAME)
viewModel = createViewModel(initialStateWithPicture)
viewModelWith(givenPictureSelected(fakeUri.instance, A_PICTURE_FILENAME))
val test = viewModel.test()
viewModel.handle(OnboardingAction.SaveSelectedProfilePicture)
test
.assertStates(expectedProfilePictureFailureStates(initialStateWithPicture))
.assertStates(expectedProfilePictureFailureStates(initialState))
.assertEvents(OnboardingViewEvents.Failure(AN_ERROR))
.finish()
}
@ -406,8 +423,8 @@ class OnboardingViewModelTest {
.finish()
}
private fun createViewModel(state: OnboardingViewState = initialState): OnboardingViewModel {
return OnboardingViewModel(
private fun viewModelWith(state: OnboardingViewState) {
OnboardingViewModel(
state,
fakeContext.instance,
fakeAuthenticationService,
@ -423,7 +440,10 @@ class OnboardingViewModelTest {
fakeDirectLoginUseCase.instance,
fakeStartAuthenticationFlowUseCase.instance,
FakeVectorOverrides()
)
).also {
viewModel = it
initialState = state
}
}
private fun givenPictureSelected(fileUri: Uri, filename: String): OnboardingViewState {
@ -481,6 +501,12 @@ class OnboardingViewModelTest {
fakeAuthenticationService.givenRegistrationWizard(registrationWizard)
fakeRegisterActionHandler.givenResultsFor(registrationWizard, results)
}
private fun givenRegistrationActionErrors(action: RegisterAction, cause: Throwable) {
val registrationWizard = FakeRegistrationWizard()
fakeAuthenticationService.givenRegistrationWizard(registrationWizard)
fakeRegisterActionHandler.givenThrowsFor(registrationWizard, action, cause)
}
}
private fun HomeServerCapabilities.toPersonalisationState() = PersonalizationState(

View File

@ -33,4 +33,8 @@ class FakeRegisterActionHandler {
result.first { it.first == actionArg }.second
}
}
fun givenThrowsFor(wizard: RegistrationWizard, action: RegisterAction, cause: Throwable) {
coEvery { instance.handleRegisterAction(wizard, action) } throws cause
}
}