From abb0460bbb93e07a7e6bb97d3f2f365c86e28f55 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 27 Feb 2025 21:33:28 +0100 Subject: [PATCH] change(invites) : add some tests and update some fakes --- .../AcceptDeclineInvitePresenterTest.kt | 84 +++++++++++++++++-- .../blockedusers/BlockedUsersPresenterTest.kt | 43 +++++----- .../impl/UserProfilePresenterTest.kt | 27 ++++-- .../libraries/matrix/test/FakeMatrixClient.kt | 24 ++---- 4 files changed, 128 insertions(+), 50 deletions(-) diff --git a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt index 8f068b8e93..870d3bba09 100644 --- a/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt +++ b/features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt @@ -63,7 +63,7 @@ class AcceptDeclineInvitePresenterTest { ) } awaitItem().also { state -> - assertThat(state.declineAction).isEqualTo(ConfirmingDeclineInvite(inviteData)) + assertThat(state.declineAction).isEqualTo(ConfirmingDeclineInvite(inviteData, false)) state.eventSink( InternalAcceptDeclineInviteEvents.CancelDeclineInvite ) @@ -93,9 +93,9 @@ class AcceptDeclineInvitePresenterTest { ) } awaitItem().also { state -> - assertThat(state.declineAction).isEqualTo(ConfirmingDeclineInvite(inviteData)) + assertThat(state.declineAction).isEqualTo(ConfirmingDeclineInvite(inviteData, false)) state.eventSink( - InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite() + InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite ) } assertThat(awaitItem().declineAction.isLoading()).isTrue() @@ -141,9 +141,9 @@ class AcceptDeclineInvitePresenterTest { ) } awaitItem().also { state -> - assertThat(state.declineAction).isEqualTo(ConfirmingDeclineInvite(inviteData)) + assertThat(state.declineAction).isEqualTo(ConfirmingDeclineInvite(inviteData, false)) state.eventSink( - InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite() + InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite ) } assertThat(awaitItem().declineAction.isLoading()).isTrue() @@ -158,6 +158,80 @@ class AcceptDeclineInvitePresenterTest { .with(value(A_SESSION_ID), value(A_ROOM_ID)) } + @Test + fun `present - declining invite with block success flow`() = runTest { + val clearMembershipNotificationForRoomLambda = lambdaRecorder { _, _ -> + Result.success(Unit) + } + val fakeNotificationCleaner = FakeNotificationCleaner( + clearMembershipNotificationForRoomLambda = clearMembershipNotificationForRoomLambda + ) + val declineInviteSuccess = lambdaRecorder { -> Result.success(Unit) } + val ignoreUserSuccess = lambdaRecorder { _: UserId -> Result.success(Unit) } + val client = FakeMatrixClient( + getRoomPreviewResult = { _, _ -> + Result.success(FakeRoomPreview(declineInviteResult = declineInviteSuccess)) + }, + ignoreUserResult = ignoreUserSuccess + ) + val presenter = createAcceptDeclineInvitePresenter( + client = client, + notificationCleaner = fakeNotificationCleaner, + ) + presenter.test { + val inviteData = anInviteData() + awaitItem().also { state -> + state.eventSink( + AcceptDeclineInviteEvents.DeclineInvite(inviteData, blockUser = true) + ) + } + awaitItem().also { state -> + assertThat(state.declineAction).isEqualTo(ConfirmingDeclineInvite(inviteData, true)) + state.eventSink( + InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite + ) + } + assertThat(awaitItem().declineAction.isLoading()).isTrue() + awaitItem().also { state -> + assertThat(state.declineAction).isInstanceOf(AsyncAction.Success::class.java) + } + cancelAndConsumeRemainingEvents() + } + declineInviteSuccess.assertions().isCalledOnce() + ignoreUserSuccess.assertions().isCalledOnce().with(value(A_USER_ID)) + clearMembershipNotificationForRoomLambda.assertions() + .isCalledOnce() + .with(value(A_SESSION_ID), value(A_ROOM_ID)) + } + + @Test + fun `present - declining invite with block error flow`() = runTest { + val declineInviteFailure = lambdaRecorder { -> + Result.failure(RuntimeException("Failed to leave room")) + } + val client = FakeMatrixClient( + getRoomPreviewResult = { _, _ -> + Result.success(FakeRoomPreview(declineInviteResult = declineInviteFailure)) + } + ) + val presenter = createAcceptDeclineInvitePresenter(client = client) + presenter.test { + val inviteData = anInviteData() + awaitItem().also { state -> + state.eventSink( + AcceptDeclineInviteEvents.DeclineInvite(inviteData, blockUser = true) + ) + } + awaitItem().also { state -> + assertThat(state.declineAction).isEqualTo(ConfirmingDeclineInvite(inviteData, true)) + state.eventSink( + InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite + ) + } + assertThat(awaitItem().declineAction.isLoading()).isTrue() + } + } + @Test fun `present - accepting invite error flow`() = runTest { val joinRoomFailure = lambdaRecorder { roomIdOrAlias: RoomIdOrAlias, _: List, _: JoinedRoom.Trigger -> diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/blockedusers/BlockedUsersPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/blockedusers/BlockedUsersPresenterTest.kt index 5e5f658580..bb68063797 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/blockedusers/BlockedUsersPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/blockedusers/BlockedUsersPresenterTest.kt @@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_ID_2 import io.element.android.libraries.matrix.test.FakeMatrixClient import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest import org.junit.Test @@ -40,9 +41,9 @@ class BlockedUsersPresenterTest { @Test fun `present - initial state with blocked users`() = runTest { - val matrixClient = FakeMatrixClient().apply { - ignoredUsersFlow.value = persistentListOf(A_USER_ID) - } + val matrixClient = FakeMatrixClient( + ignoredUsersFlow = MutableStateFlow(persistentListOf(A_USER_ID)) + ) val presenter = aBlockedUsersPresenter(matrixClient = matrixClient) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -56,9 +57,10 @@ class BlockedUsersPresenterTest { @Test fun `present - blocked users list updates with new emissions`() = runTest { - val matrixClient = FakeMatrixClient().apply { - ignoredUsersFlow.value = persistentListOf(A_USER_ID) - } + val ignoredUsersFlow = MutableStateFlow(persistentListOf(A_USER_ID)) + val matrixClient = FakeMatrixClient( + ignoredUsersFlow = ignoredUsersFlow + ) val presenter = aBlockedUsersPresenter(matrixClient = matrixClient) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -66,7 +68,7 @@ class BlockedUsersPresenterTest { with(awaitItem()) { assertThat(blockedUsers).isEqualTo(listOf(MatrixUser(A_USER_ID))) } - matrixClient.ignoredUsersFlow.value = persistentListOf(A_USER_ID, A_USER_ID_2) + ignoredUsersFlow.value = persistentListOf(A_USER_ID, A_USER_ID_2) skipItems(1) with(awaitItem()) { assertThat(blockedUsers).isEqualTo(listOf(MatrixUser(A_USER_ID), MatrixUser(A_USER_ID_2))) @@ -77,8 +79,9 @@ class BlockedUsersPresenterTest { @Test fun `present - blocked users list with data`() = runTest { val alice = MatrixUser(A_USER_ID, displayName = "Alice", avatarUrl = "aliceAvatar") - val matrixClient = FakeMatrixClient().apply { - ignoredUsersFlow.value = persistentListOf(A_USER_ID, A_USER_ID_2) + val matrixClient = FakeMatrixClient( + ignoredUsersFlow = MutableStateFlow(persistentListOf(A_USER_ID, A_USER_ID_2)) + ).apply { givenGetProfileResult(A_USER_ID, Result.success(alice)) givenGetProfileResult(A_USER_ID_2, Result.failure(AN_EXCEPTION)) } @@ -103,9 +106,9 @@ class BlockedUsersPresenterTest { @Test fun `present - unblock user`() = runTest { - val matrixClient = FakeMatrixClient().apply { - ignoredUsersFlow.value = persistentListOf(A_USER_ID) - } + val matrixClient = FakeMatrixClient( + ignoredUsersFlow = MutableStateFlow(persistentListOf(A_USER_ID)) + ) val presenter = aBlockedUsersPresenter(matrixClient = matrixClient) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -125,10 +128,10 @@ class BlockedUsersPresenterTest { @Test fun `present - unblock user handles failure`() = runTest { - val matrixClient = FakeMatrixClient().apply { - ignoredUsersFlow.value = persistentListOf(A_USER_ID) - givenUnignoreUserResult(Result.failure(IllegalStateException("User not banned"))) - } + val matrixClient = FakeMatrixClient( + unIgnoreUserResult = { Result.failure(IllegalStateException("User not banned")) }, + ignoredUsersFlow = MutableStateFlow(persistentListOf(A_USER_ID)) + ) val presenter = aBlockedUsersPresenter(matrixClient = matrixClient) moleculeFlow(RecompositionMode.Immediate) { presenter.present() @@ -147,10 +150,10 @@ class BlockedUsersPresenterTest { @Test fun `present - unblock user then cancel`() = runTest { - val matrixClient = FakeMatrixClient().apply { - ignoredUsersFlow.value = persistentListOf(A_USER_ID) - givenUnignoreUserResult(Result.failure(IllegalStateException("User not banned"))) - } + val matrixClient = FakeMatrixClient( + unIgnoreUserResult = { Result.failure(IllegalStateException("User not banned")) }, + ignoredUsersFlow = MutableStateFlow(persistentListOf(A_USER_ID)) + ) val presenter = aBlockedUsersPresenter(matrixClient = matrixClient) moleculeFlow(RecompositionMode.Immediate) { presenter.present() diff --git a/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt b/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt index 41626737cc..98140fdd00 100644 --- a/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt +++ b/features/userprofile/impl/src/test/kotlin/io/element/android/features/userprofile/impl/UserProfilePresenterTest.kt @@ -40,7 +40,11 @@ import io.element.android.tests.testutils.lambda.any import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.test +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.persistentListOf import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test @@ -169,7 +173,8 @@ class UserProfilePresenterTest { @Test fun `present - BlockUser and UnblockUser without confirmation change the 'blocked' state`() = runTest { - val client = createFakeMatrixClient() + val ignoredUsersFlow = MutableStateFlow(persistentListOf()) + val client = createFakeMatrixClient(ignoredUsersFlow = ignoredUsersFlow) val presenter = createUserProfilePresenter( client = client, userId = A_USER_ID @@ -178,20 +183,21 @@ class UserProfilePresenterTest { val initialState = awaitFirstItem() initialState.eventSink(UserProfileEvents.BlockUser(needsConfirmation = false)) assertThat(awaitItem().isBlocked.isLoading()).isTrue() - client.emitIgnoreUserList(listOf(A_USER_ID)) + ignoredUsersFlow.emit(persistentListOf(A_USER_ID)) assertThat(awaitItem().isBlocked.dataOrNull()).isTrue() initialState.eventSink(UserProfileEvents.UnblockUser(needsConfirmation = false)) assertThat(awaitItem().isBlocked.isLoading()).isTrue() - client.emitIgnoreUserList(listOf()) + ignoredUsersFlow.emit(persistentListOf()) assertThat(awaitItem().isBlocked.dataOrNull()).isFalse() } } @Test fun `present - BlockUser with error`() = runTest { - val matrixClient = createFakeMatrixClient() - matrixClient.givenIgnoreUserResult(Result.failure(A_THROWABLE)) + val matrixClient = createFakeMatrixClient( + ignoreUserResult = { Result.failure(A_THROWABLE) } + ) val presenter = createUserProfilePresenter(client = matrixClient) presenter.test { val initialState = awaitFirstItem() @@ -207,8 +213,9 @@ class UserProfilePresenterTest { @Test fun `present - UnblockUser with error`() = runTest { - val matrixClient = createFakeMatrixClient() - matrixClient.givenUnignoreUserResult(Result.failure(A_THROWABLE)) + val matrixClient = createFakeMatrixClient( + unIgnoreUserResult = { Result.failure(A_THROWABLE) } + ) val presenter = createUserProfilePresenter(client = matrixClient) presenter.test { val initialState = awaitFirstItem() @@ -374,10 +381,16 @@ class UserProfilePresenterTest { private fun createFakeMatrixClient( isUserVerified: Boolean = false, + ignoreUserResult: (UserId) -> Result = { Result.success(Unit) }, + unIgnoreUserResult: (UserId) -> Result = { Result.success(Unit) }, + ignoredUsersFlow: StateFlow> = MutableStateFlow(persistentListOf()) ) = FakeMatrixClient( encryptionService = FakeEncryptionService( isUserVerifiedResult = { Result.success(isUserVerified) } ), + ignoreUserResult = ignoreUserResult, + unIgnoreUserResult = unIgnoreUserResult, + ignoredUsersFlow = ignoredUsersFlow ) private fun createUserProfilePresenter( diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt index 5f37394020..0433e49efc 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt @@ -85,7 +85,10 @@ class FakeMatrixClient( private val canDeactivateAccountResult: () -> Boolean = { lambdaError() }, private val deactivateAccountResult: (String, Boolean) -> Result = { _, _ -> lambdaError() }, private val currentSlidingSyncVersionLambda: () -> Result = { lambdaError() }, - private val availableSlidingSyncVersionsLambda: () -> Result> = { lambdaError() } + private val availableSlidingSyncVersionsLambda: () -> Result> = { lambdaError() }, + private val ignoreUserResult: (UserId) -> Result = { lambdaError() }, + private var unIgnoreUserResult: (UserId)-> Result = {Result.success(Unit)}, + override val ignoredUsersFlow: StateFlow> = MutableStateFlow(persistentListOf()), ) : MatrixClient { var setDisplayNameCalled: Boolean = false private set @@ -96,10 +99,7 @@ class FakeMatrixClient( private val _userProfile: MutableStateFlow = MutableStateFlow(MatrixUser(sessionId, userDisplayName, userAvatarUrl)) override val userProfile: StateFlow = _userProfile - override val ignoredUsersFlow: MutableStateFlow> = MutableStateFlow(persistentListOf()) - private var ignoreUserResult: Result = Result.success(Unit) - private var unignoreUserResult: Result = Result.success(Unit) private var createRoomResult: Result = Result.success(A_ROOM_ID) private var createDmResult: Result = Result.success(A_ROOM_ID) private var findDmResult: RoomId? = A_ROOM_ID @@ -137,11 +137,11 @@ class FakeMatrixClient( } override suspend fun ignoreUser(userId: UserId): Result = simulateLongTask { - return ignoreUserResult + return ignoreUserResult(userId) } override suspend fun unignoreUser(userId: UserId): Result = simulateLongTask { - return unignoreUserResult + return unIgnoreUserResult(userId) } override suspend fun createRoom(createRoomParams: CreateRoomParameters): Result = simulateLongTask { @@ -239,10 +239,6 @@ class FakeMatrixClient( return RoomMembershipObserver() } - suspend fun emitIgnoreUserList(users: List) { - ignoredUsersFlow.emit(users.toImmutableList()) - } - // Mocks fun givenCreateRoomResult(result: Result) { @@ -253,14 +249,6 @@ class FakeMatrixClient( createDmResult = result } - fun givenIgnoreUserResult(result: Result) { - ignoreUserResult = result - } - - fun givenUnignoreUserResult(result: Result) { - unignoreUserResult = result - } - fun givenFindDmResult(result: RoomId?) { findDmResult = result }