From 9b4b9e9140f559216197b0696f32455c52340af7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 15 Jun 2023 10:57:05 +0200 Subject: [PATCH] Introduce `simulateLongTask` to ensure that the Presenter State `Loading` is visible. Also do some cleanup on the tests. --- .../ConfigureRoomPresenterTests.kt | 4 +- .../impl/root/CreateRoomRootPresenterTests.kt | 7 ++- .../impl/InviteListPresenterTests.kt | 21 +------- .../impl/LogoutPreferencePresenterTest.kt | 7 ++- .../messages/MessagesPresenterTest.kt | 11 ++-- .../AttachmentsPreviewPresenterTest.kt | 4 -- .../messages/media/FakeLocalMediaActions.kt | 11 ++-- .../media/viewer/MediaViewerPresenterTest.kt | 10 ++-- .../roomdetails/RoomDetailsPresenterTests.kt | 7 +-- .../edit/RoomDetailsEditPresenterTest.kt | 25 ++++++---- .../invite/RoomInviteMembersPresenterTest.kt | 50 +++++++++++-------- .../members/RoomMemberListPresenterTests.kt | 7 ++- .../RoomMemberDetailsPresenterTests.kt | 18 +++---- .../impl/DefaultInviteStateDataSourceTest.kt | 4 +- .../roomlist/impl/RoomListPresenterTests.kt | 20 +++----- .../libraries/matrix/test/FakeMatrixClient.kt | 1 - .../android/libraries/matrix/test/TestData.kt | 2 - .../test/auth/FakeAuthenticationService.kt | 22 ++++---- .../matrix/test/media/FakeMediaLoader.kt | 18 +++---- .../matrix/test/room/FakeMatrixRoom.kt | 49 ++++++++---------- libraries/mediaupload/test/build.gradle.kts | 1 + .../mediaupload/test/FakeMediaPreProcessor.kt | 5 +- .../android/samples/minimal/RoomListScreen.kt | 2 +- .../android/tests/testutils/LongTask.kt | 28 +++++++++++ .../testutils/TestCoroutineDispatchers.kt | 15 +++--- 25 files changed, 169 insertions(+), 180 deletions(-) create mode 100644 tests/testutils/src/main/kotlin/io/element/android/tests/testutils/LongTask.kt diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt index 7f36b9e2b9..736fca9cb4 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/configureroom/ConfigureRoomPresenterTests.kt @@ -21,7 +21,6 @@ import app.cash.molecule.RecompositionClock import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth.assertThat -import io.element.android.libraries.matrix.ui.media.AvatarAction import io.element.android.features.createroom.impl.CreateRoomConfig import io.element.android.features.createroom.impl.CreateRoomDataStore import io.element.android.features.createroom.impl.userlist.UserListDataStore @@ -33,6 +32,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_NAME import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.matrix.ui.components.aMatrixUser +import io.element.android.libraries.matrix.ui.media.AvatarAction import io.element.android.libraries.mediapickers.test.FakePickerProvider import io.element.android.libraries.mediaupload.api.MediaUploadInfo import io.element.android.libraries.mediaupload.test.FakeMediaPreProcessor @@ -226,6 +226,7 @@ class ConfigureRoomPresenterTests { val initialState = awaitItem() initialState.eventSink(ConfigureRoomEvents.CreateRoom(initialState.config)) + assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Loading::class.java) val stateAfterCreateRoom = awaitItem() assertThat(stateAfterCreateRoom.createRoomAction).isInstanceOf(Async.Failure::class.java) @@ -234,7 +235,6 @@ class ConfigureRoomPresenterTests { assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Uninitialized::class.java) assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Loading::class.java) assertThat(awaitItem().createRoomAction).isInstanceOf(Async.Success::class.java) - } } diff --git a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt index 8d9819eeae..0d0fdcce44 100644 --- a/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt +++ b/features/createroom/impl/src/test/kotlin/io/element/android/features/createroom/impl/root/CreateRoomRootPresenterTests.kt @@ -49,7 +49,12 @@ class CreateRoomRootPresenterTests { fakeUserListPresenter = FakeUserListPresenter() fakeMatrixClient = FakeMatrixClient() userRepository = FakeUserRepository() - presenter = CreateRoomRootPresenter(FakeUserListPresenterFactory(fakeUserListPresenter), userRepository, UserListDataStore(), fakeMatrixClient) + presenter = CreateRoomRootPresenter( + presenterFactory = FakeUserListPresenterFactory(fakeUserListPresenter), + userRepository = userRepository, + userListDataStore = UserListDataStore(), + matrixClient = fakeMatrixClient + ) } @Test diff --git a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt index 462faa405f..cf4f1058e5 100644 --- a/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt +++ b/features/invitelist/impl/src/test/kotlin/io/element/android/features/invitelist/impl/InviteListPresenterTests.kt @@ -32,12 +32,11 @@ import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_ID_2 import io.element.android.libraries.matrix.test.A_ROOM_NAME -import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.FakeMatrixClient -import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.matrix.test.room.FakeRoomSummaryDataSource +import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import kotlinx.coroutines.test.runTest import org.junit.Test @@ -48,7 +47,6 @@ class InviteListPresenterTests { val invitesDataSource = FakeRoomSummaryDataSource() val presenter = InviteListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ), FakeSeenInvitesStore(), @@ -73,7 +71,6 @@ class InviteListPresenterTests { val invitesDataSource = FakeRoomSummaryDataSource().withDirectChatInvitation() val presenter = InviteListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ), FakeSeenInvitesStore(), @@ -100,10 +97,8 @@ class InviteListPresenterTests { @Test fun `present - includes sender details for room invites`() = runTest { val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() - val presenter = InviteListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ), FakeSeenInvitesStore(), @@ -128,10 +123,8 @@ class InviteListPresenterTests { @Test fun `present - shows confirm dialog for declining direct chat invites`() = runTest { val invitesDataSource = FakeRoomSummaryDataSource().withDirectChatInvitation() - val presenter = InviteListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ), FakeSeenInvitesStore(), @@ -154,10 +147,8 @@ class InviteListPresenterTests { @Test fun `present - shows confirm dialog for declining room invites`() = runTest { val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() - val presenter = InviteListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ), FakeSeenInvitesStore(), @@ -180,10 +171,8 @@ class InviteListPresenterTests { @Test fun `present - hides confirm dialog when cancelling`() = runTest { val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() - val presenter = InviteListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ), FakeSeenInvitesStore(), @@ -207,7 +196,6 @@ class InviteListPresenterTests { fun `present - declines invite after confirming`() = runTest { val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val client = FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ) val room = FakeMatrixRoom() @@ -234,7 +222,6 @@ class InviteListPresenterTests { fun `present - declines invite after confirming and sets state on error`() = runTest { val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val client = FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ) val room = FakeMatrixRoom() @@ -266,7 +253,6 @@ class InviteListPresenterTests { fun `present - dismisses declining error state`() = runTest { val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val client = FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ) val room = FakeMatrixRoom() @@ -299,7 +285,6 @@ class InviteListPresenterTests { fun `present - accepts invites and sets state on success`() = runTest { val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val client = FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ) val room = FakeMatrixRoom() @@ -323,7 +308,6 @@ class InviteListPresenterTests { fun `present - accepts invites and sets state on error`() = runTest { val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val client = FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ) val room = FakeMatrixRoom() @@ -349,7 +333,6 @@ class InviteListPresenterTests { fun `present - dismisses accepting error state`() = runTest { val invitesDataSource = FakeRoomSummaryDataSource().withRoomInvitation() val client = FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ) val room = FakeMatrixRoom() @@ -379,7 +362,6 @@ class InviteListPresenterTests { val store = FakeSeenInvitesStore() val presenter = InviteListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ), store, @@ -416,7 +398,6 @@ class InviteListPresenterTests { store.publishRoomIds(setOf(A_ROOM_ID)) val presenter = InviteListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, invitesDataSource = invitesDataSource, ), store, diff --git a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPreferencePresenterTest.kt b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPreferencePresenterTest.kt index 7a3556389f..bed33006d6 100644 --- a/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPreferencePresenterTest.kt +++ b/features/logout/impl/src/test/kotlin/io/element/android/features/logout/impl/LogoutPreferencePresenterTest.kt @@ -23,7 +23,6 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.logout.api.LogoutPreferenceEvents import io.element.android.features.logout.api.LogoutPreferenceState import io.element.android.libraries.architecture.Async -import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_THROWABLE import io.element.android.libraries.matrix.test.FakeMatrixClient import kotlinx.coroutines.test.runTest @@ -33,7 +32,7 @@ class LogoutPreferencePresenterTest { @Test fun `present - initial state`() = runTest { val presenter = DefaultLogoutPreferencePresenter( - FakeMatrixClient(A_SESSION_ID), + FakeMatrixClient(), ) moleculeFlow(RecompositionClock.Immediate) { presenter.present() @@ -46,7 +45,7 @@ class LogoutPreferencePresenterTest { @Test fun `present - logout`() = runTest { val presenter = DefaultLogoutPreferencePresenter( - FakeMatrixClient(A_SESSION_ID), + FakeMatrixClient(), ) moleculeFlow(RecompositionClock.Immediate) { presenter.present() @@ -62,7 +61,7 @@ class LogoutPreferencePresenterTest { @Test fun `present - logout with error`() = runTest { - val matrixClient = FakeMatrixClient(A_SESSION_ID) + val matrixClient = FakeMatrixClient() val presenter = DefaultLogoutPreferencePresenter( matrixClient, ) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt index 1ced503920..a31e4e10a5 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/MessagesPresenterTest.kt @@ -35,6 +35,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt import io.element.android.features.messages.media.FakeLocalMediaFactory import io.element.android.features.messages.utils.messagesummary.FakeMessageSummaryFormatter import io.element.android.features.networkmonitor.test.FakeNetworkMonitor +import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildType import io.element.android.libraries.core.mimetype.MimeTypes @@ -53,7 +54,6 @@ import io.element.android.libraries.textcomposer.MessageComposerMode import io.element.android.tests.testutils.testCoroutineDispatchers import io.mockk.mockk import kotlinx.coroutines.test.TestScope -import kotlinx.coroutines.test.advanceUntilIdle import kotlinx.coroutines.test.runTest import org.junit.Test @@ -75,8 +75,9 @@ class MessagesPresenterTest { @Test fun `present - handle sending a reaction`() = runTest { + val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) val room = FakeMatrixRoom() - val presenter = createMessagePresenter(matrixRoom = room) + val presenter = createMessagePresenter(matrixRoom = room, coroutineDispatchers = coroutineDispatchers) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -254,8 +255,9 @@ class MessagesPresenterTest { @Test fun `present - handle action redact`() = runTest { + val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) val matrixRoom = FakeMatrixRoom() - val presenter = createMessagePresenter(matrixRoom) + val presenter = createMessagePresenter(matrixRoom = matrixRoom, coroutineDispatchers = coroutineDispatchers) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -293,6 +295,7 @@ class MessagesPresenterTest { } private fun TestScope.createMessagePresenter( + coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(), matrixRoom: MatrixRoom = FakeMatrixRoom() ): MessagesPresenter { val messageComposerPresenter = MessageComposerPresenter( @@ -330,7 +333,7 @@ class MessagesPresenterTest { networkMonitor = FakeNetworkMonitor(), snackbarDispatcher = SnackbarDispatcher(), messageSummaryFormatter = FakeMessageSummaryFormatter(), - dispatchers = testCoroutineDispatchers(), + dispatchers = coroutineDispatchers, ) } } diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/attachments/AttachmentsPreviewPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/attachments/AttachmentsPreviewPresenterTest.kt index 3789c36146..18f5ae8da3 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/attachments/AttachmentsPreviewPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/attachments/AttachmentsPreviewPresenterTest.kt @@ -19,7 +19,6 @@ package io.element.android.features.messages.attachments import android.net.Uri -import androidx.media3.common.MimeTypes import app.cash.molecule.RecompositionClock import app.cash.molecule.moleculeFlow import app.cash.turbine.test @@ -31,7 +30,6 @@ import io.element.android.features.messages.impl.attachments.preview.Attachments import io.element.android.features.messages.impl.media.local.LocalMedia import io.element.android.libraries.architecture.Async import io.element.android.libraries.matrix.api.room.MatrixRoom -import io.element.android.libraries.matrix.test.FAKE_DELAY_IN_MS import io.element.android.libraries.matrix.test.room.FakeMatrixRoom import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.api.MediaSender @@ -58,7 +56,6 @@ class AttachmentsPreviewPresenterTest { initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) val loadingState = awaitItem() assertThat(loadingState.sendActionState).isEqualTo(Async.Loading()) - testScheduler.advanceTimeBy(FAKE_DELAY_IN_MS) val successState = awaitItem() assertThat(successState.sendActionState).isEqualTo(Async.Success(Unit)) assertThat(room.sendMediaCount).isEqualTo(1) @@ -79,7 +76,6 @@ class AttachmentsPreviewPresenterTest { initialState.eventSink(AttachmentsPreviewEvents.SendAttachment) val loadingState = awaitItem() assertThat(loadingState.sendActionState).isEqualTo(Async.Loading()) - testScheduler.advanceTimeBy(FAKE_DELAY_IN_MS) val failureState = awaitItem() assertThat(failureState.sendActionState).isEqualTo(Async.Failure(failure)) assertThat(room.sendMediaCount).isEqualTo(0) diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/FakeLocalMediaActions.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/FakeLocalMediaActions.kt index 25a62e439a..5bdef5f9b1 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/FakeLocalMediaActions.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/FakeLocalMediaActions.kt @@ -19,10 +19,9 @@ package io.element.android.features.messages.media import androidx.compose.runtime.Composable import io.element.android.features.messages.impl.media.local.LocalMedia import io.element.android.features.messages.impl.media.local.LocalMediaActions -import io.element.android.libraries.core.coroutine.CoroutineDispatchers -import kotlinx.coroutines.withContext +import io.element.android.tests.testutils.simulateLongTask -class FakeLocalMediaActions(private val coroutineDispatchers: CoroutineDispatchers) : LocalMediaActions { +class FakeLocalMediaActions : LocalMediaActions { var shouldFail = false @@ -31,7 +30,7 @@ class FakeLocalMediaActions(private val coroutineDispatchers: CoroutineDispatche //NOOP } - override suspend fun saveOnDisk(localMedia: LocalMedia): Result = withContext(coroutineDispatchers.io) { + override suspend fun saveOnDisk(localMedia: LocalMedia): Result = simulateLongTask { if (shouldFail) { Result.failure(RuntimeException()) } else { @@ -39,7 +38,7 @@ class FakeLocalMediaActions(private val coroutineDispatchers: CoroutineDispatche } } - override suspend fun share(localMedia: LocalMedia): Result = withContext(coroutineDispatchers.io) { + override suspend fun share(localMedia: LocalMedia): Result = simulateLongTask { if (shouldFail) { Result.failure(RuntimeException()) } else { @@ -47,7 +46,7 @@ class FakeLocalMediaActions(private val coroutineDispatchers: CoroutineDispatche } } - override suspend fun open(localMedia: LocalMedia): Result = withContext(coroutineDispatchers.io) { + override suspend fun open(localMedia: LocalMedia): Result = simulateLongTask { if (shouldFail) { Result.failure(RuntimeException()) } else { diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/viewer/MediaViewerPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/viewer/MediaViewerPresenterTest.kt index 31cddffb95..8a6025d3bd 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/viewer/MediaViewerPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/media/viewer/MediaViewerPresenterTest.kt @@ -33,7 +33,6 @@ import io.element.android.libraries.architecture.Async import io.element.android.libraries.designsystem.utils.SnackbarDispatcher import io.element.android.libraries.matrix.test.media.FakeMediaLoader import io.element.android.libraries.matrix.test.media.aMediaSource -import io.element.android.tests.testutils.testCoroutineDispatchers import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest @@ -48,9 +47,8 @@ class MediaViewerPresenterTest { @Test fun `present - download media success scenario`() = runTest { - val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = false) val mediaLoader = FakeMediaLoader() - val mediaActions = FakeLocalMediaActions(coroutineDispatchers) + val mediaActions = FakeLocalMediaActions() val presenter = aMediaViewerPresenter(mediaLoader, mediaActions) moleculeFlow(RecompositionClock.Immediate) { presenter.present() @@ -69,9 +67,8 @@ class MediaViewerPresenterTest { @Test fun `present - check all actions `() = runTest { - val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = false) val mediaLoader = FakeMediaLoader() - val mediaActions = FakeLocalMediaActions(coroutineDispatchers) + val mediaActions = FakeLocalMediaActions() val presenter = aMediaViewerPresenter(mediaLoader, mediaActions) moleculeFlow(RecompositionClock.Immediate) { presenter.present() @@ -118,9 +115,8 @@ class MediaViewerPresenterTest { @Test fun `present - download media failure then retry with success scenario`() = runTest { - val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = false) val mediaLoader = FakeMediaLoader() - val mediaActions = FakeLocalMediaActions(coroutineDispatchers) + val mediaActions = FakeLocalMediaActions() val presenter = aMediaViewerPresenter(mediaLoader, mediaActions) moleculeFlow(RecompositionClock.Immediate) { presenter.present() diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt index 43f1667730..f85942c3ee 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/RoomDetailsPresenterTests.kt @@ -27,7 +27,6 @@ import io.element.android.features.roomdetails.impl.RoomTopicState import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.libraries.matrix.api.core.RoomId -import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState @@ -48,7 +47,7 @@ class RoomDetailsPresenterTests { private fun aRoomDetailsPresenter(room: MatrixRoom): RoomDetailsPresenter { val roomMemberDetailsPresenterFactory = object : RoomMemberDetailsPresenter.Factory { override fun create(roomMemberId: UserId): RoomMemberDetailsPresenter { - return RoomMemberDetailsPresenter(aMatrixClient(), room, roomMemberId) + return RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMemberId) } } return RoomDetailsPresenter(room, roomMemberDetailsPresenterFactory, LeaveRoomPresenterFake()) @@ -250,10 +249,6 @@ class RoomDetailsPresenterTests { } } -fun aMatrixClient( - sessionId: SessionId = A_SESSION_ID, -) = FakeMatrixClient(sessionId = sessionId) - fun aMatrixRoom( roomId: RoomId = A_ROOM_ID, name: String? = A_ROOM_NAME, diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditPresenterTest.kt index c1d098dab5..df80f40e9b 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/edit/RoomDetailsEditPresenterTest.kt @@ -105,7 +105,8 @@ class RoomDetailsEditPresenterTest { val room = aMatrixRoom(avatarUrl = AN_AVATAR_URL).apply { givenCanSendStateResult(StateEventType.ROOM_NAME, Result.success(true)) givenCanSendStateResult(StateEventType.ROOM_AVATAR, Result.success(false)) - givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.failure(Throwable("Oops"))) } + givenCanSendStateResult(StateEventType.ROOM_TOPIC, Result.failure(Throwable("Oops"))) + } val presenter = aRoomDetailsEditPresenter(room) moleculeFlow(RecompositionClock.Immediate) { @@ -381,7 +382,7 @@ class RoomDetailsEditPresenterTest { initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("New topic")) initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.Remove)) initialState.eventSink(RoomDetailsEditEvents.Save) - + skipItems(5) assertThat(room.newName).isEqualTo("New name") assertThat(room.newTopic).isEqualTo("New topic") assertThat(room.newAvatarData).isNull() @@ -476,7 +477,7 @@ class RoomDetailsEditPresenterTest { initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto)) initialState.eventSink(RoomDetailsEditEvents.Save) - skipItems(2) + skipItems(3) assertThat(room.newName).isNull() assertThat(room.newTopic).isNull() @@ -501,7 +502,7 @@ class RoomDetailsEditPresenterTest { initialState.eventSink(RoomDetailsEditEvents.HandleAvatarAction(AvatarAction.ChoosePhoto)) initialState.eventSink(RoomDetailsEditEvents.Save) - skipItems(1) + skipItems(2) assertThat(room.newName).isNull() assertThat(room.newTopic).isNull() @@ -567,7 +568,7 @@ class RoomDetailsEditPresenterTest { initialState.eventSink(RoomDetailsEditEvents.UpdateRoomTopic("foo")) initialState.eventSink(RoomDetailsEditEvents.Save) - skipItems(1) + skipItems(2) assertThat(awaitItem().saveAction).isInstanceOf(Async.Failure::class.java) @@ -588,6 +589,7 @@ class RoomDetailsEditPresenterTest { initialState.eventSink(RoomDetailsEditEvents.Save) skipItems(1) + assertThat(awaitItem().saveAction).isInstanceOf(Async.Loading::class.java) assertThat(awaitItem().saveAction).isInstanceOf(Async.Failure::class.java) } } @@ -599,14 +601,17 @@ class RoomDetailsEditPresenterTest { } fakePickerProvider.givenResult(anotherAvatarUri) - fakeMediaPreProcessor.givenResult(Result.success(MediaUploadInfo.AnyFile( - file = processedFile, - info = mockk(), - ))) + fakeMediaPreProcessor.givenResult( + Result.success( + MediaUploadInfo.AnyFile( + file = processedFile, + info = mockk(), + ) + ) + ) } companion object { private const val ANOTHER_AVATAR_URL = "example://camera/foo.jpg" } - } diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt index 495e639baf..8600cefeac 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/impl/invite/RoomInviteMembersPresenterTest.kt @@ -93,9 +93,8 @@ internal class RoomInviteMembersPresenterTest { val presenter = RoomInviteMembersPresenter( userRepository = repository, roomMemberListDataSource = createDataSource(FakeMatrixRoom()), - coroutineDispatchers = testCoroutineDispatchers() + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) - moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -120,9 +119,8 @@ internal class RoomInviteMembersPresenterTest { val presenter = RoomInviteMembersPresenter( userRepository = repository, roomMemberListDataSource = createDataSource(FakeMatrixRoom()), - coroutineDispatchers = testCoroutineDispatchers() + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) - moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -157,17 +155,24 @@ internal class RoomInviteMembersPresenterTest { val invitedUser = userList[1] val repository = FakeUserRepository() + val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) val presenter = RoomInviteMembersPresenter( userRepository = repository, - roomMemberListDataSource = createDataSource(FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(listOf( - aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), - aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), - ))) - }), - coroutineDispatchers = testCoroutineDispatchers() + roomMemberListDataSource = createDataSource( + matrixRoom = FakeMatrixRoom().apply { + givenRoomMembersState( + MatrixRoomMembersState.Ready( + listOf( + aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), + aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), + ) + ) + ) + }, + coroutineDispatchers = coroutineDispatchers, + ), + coroutineDispatchers = coroutineDispatchers ) - moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -215,12 +220,16 @@ internal class RoomInviteMembersPresenterTest { val presenter = RoomInviteMembersPresenter( userRepository = repository, roomMemberListDataSource = createDataSource(FakeMatrixRoom().apply { - givenRoomMembersState(MatrixRoomMembersState.Ready(listOf( - aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), - aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), - ))) + givenRoomMembersState( + MatrixRoomMembersState.Ready( + listOf( + aRoomMember(userId = joinedUser.userId, membership = RoomMembershipState.JOIN), + aRoomMember(userId = invitedUser.userId, membership = RoomMembershipState.INVITE), + ) + ) + ) }), - coroutineDispatchers = testCoroutineDispatchers() + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) moleculeFlow(RecompositionClock.Immediate) { @@ -287,9 +296,8 @@ internal class RoomInviteMembersPresenterTest { val presenter = RoomInviteMembersPresenter( userRepository = repository, roomMemberListDataSource = createDataSource(FakeMatrixRoom()), - coroutineDispatchers = testCoroutineDispatchers() + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) - moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -323,16 +331,14 @@ internal class RoomInviteMembersPresenterTest { } } - @Test fun `present - toggling a user updates existing search results`() = runTest { val repository = FakeUserRepository() val presenter = RoomInviteMembersPresenter( userRepository = repository, roomMemberListDataSource = createDataSource(FakeMatrixRoom()), - coroutineDispatchers = testCoroutineDispatchers() + coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true) ) - moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt index b9b52b29f8..01f60847f8 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/RoomMemberListPresenterTests.kt @@ -20,7 +20,6 @@ import app.cash.molecule.RecompositionClock import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth -import io.element.android.features.roomdetails.aMatrixRoom import io.element.android.features.roomdetails.impl.members.RoomMemberListDataSource import io.element.android.features.roomdetails.impl.members.RoomMemberListEvents import io.element.android.features.roomdetails.impl.members.RoomMemberListPresenter @@ -167,7 +166,7 @@ class RoomMemberListPresenterTests { @ExperimentalCoroutinesApi private fun TestScope.createDataSource( - matrixRoom: MatrixRoom = aMatrixRoom().apply { + matrixRoom: MatrixRoom = FakeMatrixRoom().apply { givenRoomMembersState(MatrixRoomMembersState.Ready(aRoomMemberList())) }, coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers() @@ -175,7 +174,7 @@ private fun TestScope.createDataSource( @ExperimentalCoroutinesApi private fun TestScope.createPresenter( + coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true), matrixRoom: MatrixRoom = FakeMatrixRoom(), - roomMemberListDataSource: RoomMemberListDataSource = createDataSource(), - coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers() + roomMemberListDataSource: RoomMemberListDataSource = createDataSource(coroutineDispatchers = coroutineDispatchers), ) = RoomMemberListPresenter(matrixRoom, roomMemberListDataSource, coroutineDispatchers) diff --git a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt index 294b689ea9..912f354c89 100644 --- a/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt +++ b/features/roomdetails/impl/src/test/kotlin/io/element/android/features/roomdetails/members/details/RoomMemberDetailsPresenterTests.kt @@ -20,13 +20,13 @@ import app.cash.molecule.RecompositionClock import app.cash.molecule.moleculeFlow import app.cash.turbine.test import com.google.common.truth.Truth -import io.element.android.features.roomdetails.aMatrixClient import io.element.android.features.roomdetails.aMatrixRoom import io.element.android.features.roomdetails.impl.members.aRoomMember import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsEvents import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsState import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState +import io.element.android.libraries.matrix.test.FakeMatrixClient import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runTest import org.junit.Test @@ -34,8 +34,6 @@ import org.junit.Test @ExperimentalCoroutinesApi class RoomMemberDetailsPresenterTests { - private val matrixClient = aMatrixClient() - @Test fun `present - returns the room member's data, then updates it if needed`() = runTest { val roomMember = aRoomMember(displayName = "Alice") @@ -44,7 +42,7 @@ class RoomMemberDetailsPresenterTests { givenUserAvatarUrlResult(Result.success("A custom avatar")) givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember))) } - val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) + val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -53,7 +51,7 @@ class RoomMemberDetailsPresenterTests { Truth.assertThat(initialState.userName).isEqualTo(roomMember.displayName) Truth.assertThat(initialState.avatarUrl).isEqualTo(roomMember.avatarUrl) Truth.assertThat(initialState.isBlocked).isEqualTo(roomMember.isIgnored) - + skipItems(1) val loadedState = awaitItem() Truth.assertThat(loadedState.userName).isEqualTo("A custom name") Truth.assertThat(loadedState.avatarUrl).isEqualTo("A custom avatar") @@ -68,7 +66,7 @@ class RoomMemberDetailsPresenterTests { givenUserAvatarUrlResult(Result.failure(Throwable())) givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember))) } - val presenter = RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) + val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -88,7 +86,7 @@ class RoomMemberDetailsPresenterTests { givenUserAvatarUrlResult(Result.success(null)) givenRoomMembersState(MatrixRoomMembersState.Ready(listOf(roomMember))) } - val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) + val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -104,7 +102,7 @@ class RoomMemberDetailsPresenterTests { fun `present - BlockUser needing confirmation displays confirmation dialog`() = runTest { val room = aMatrixRoom() val roomMember = aRoomMember() - val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) + val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -125,7 +123,7 @@ class RoomMemberDetailsPresenterTests { fun `present - BlockUser and UnblockUser without confirmation change the 'blocked' state`() = runTest { val room = aMatrixRoom() val roomMember = aRoomMember() - val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) + val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { @@ -142,7 +140,7 @@ class RoomMemberDetailsPresenterTests { fun `present - UnblockUser needing confirmation displays confirmation dialog`() = runTest { val room = aMatrixRoom() val roomMember = aRoomMember() - val presenter =RoomMemberDetailsPresenter(matrixClient, room, roomMember.userId) + val presenter = RoomMemberDetailsPresenter(FakeMatrixClient(), room, roomMember.userId) moleculeFlow(RecompositionClock.Immediate) { presenter.present() }.test { diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/DefaultInviteStateDataSourceTest.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/DefaultInviteStateDataSourceTest.kt index 040a5b5b50..389aee1e92 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/DefaultInviteStateDataSourceTest.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/DefaultInviteStateDataSourceTest.kt @@ -69,7 +69,7 @@ internal class DefaultInviteStateDataSourceTest { val client = FakeMatrixClient(invitesDataSource = matrixDataSource) val seenStore = FakeSeenInvitesStore() seenStore.publishRoomIds(setOf(A_ROOM_ID)) - val dataSource = DefaultInviteStateDataSource(client, seenStore, testCoroutineDispatchers()) + val dataSource = DefaultInviteStateDataSource(client, seenStore, testCoroutineDispatchers(useUnconfinedTestDispatcher = true)) moleculeFlow(RecompositionClock.Immediate) { dataSource.inviteState() @@ -86,7 +86,7 @@ internal class DefaultInviteStateDataSourceTest { val client = FakeMatrixClient(invitesDataSource = matrixDataSource) val seenStore = FakeSeenInvitesStore() seenStore.publishRoomIds(setOf(A_ROOM_ID)) - val dataSource = DefaultInviteStateDataSource(client, seenStore, testCoroutineDispatchers()) + val dataSource = DefaultInviteStateDataSource(client, seenStore, testCoroutineDispatchers(useUnconfinedTestDispatcher = true)) moleculeFlow(RecompositionClock.Immediate) { dataSource.inviteState() diff --git a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt index fe76d9837b..37623b4f28 100644 --- a/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt +++ b/features/roomlist/impl/src/test/kotlin/io/element/android/features/roomlist/impl/RoomListPresenterTests.kt @@ -35,7 +35,6 @@ import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_ROOM_NAME -import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.A_USER_ID import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.FakeMatrixClient @@ -51,7 +50,7 @@ class RoomListPresenterTests { @Test fun `present - should start with no user and then load user with success`() = runTest { val presenter = RoomListPresenter( - FakeMatrixClient(A_SESSION_ID), + FakeMatrixClient(), createDateFormatter(), FakeRoomLastMessageFormatter(), FakeSessionVerificationService(), @@ -77,7 +76,6 @@ class RoomListPresenterTests { fun `present - should start with no user and then load user with error`() = runTest { val presenter = RoomListPresenter( FakeMatrixClient( - A_SESSION_ID, userDisplayName = Result.failure(AN_EXCEPTION), userAvatarURLString = Result.failure(AN_EXCEPTION), ), @@ -102,7 +100,7 @@ class RoomListPresenterTests { @Test fun `present - should filter room with success`() = runTest { val presenter = RoomListPresenter( - FakeMatrixClient(A_SESSION_ID), + FakeMatrixClient(), createDateFormatter(), FakeRoomLastMessageFormatter(), FakeSessionVerificationService(), @@ -130,7 +128,6 @@ class RoomListPresenterTests { val roomSummaryDataSource = FakeRoomSummaryDataSource() val presenter = RoomListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, roomSummaryDataSource = roomSummaryDataSource ), createDateFormatter(), @@ -163,7 +160,6 @@ class RoomListPresenterTests { val roomSummaryDataSource = FakeRoomSummaryDataSource() val presenter = RoomListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, roomSummaryDataSource = roomSummaryDataSource ), createDateFormatter(), @@ -202,7 +198,6 @@ class RoomListPresenterTests { val roomSummaryDataSource = FakeRoomSummaryDataSource() val presenter = RoomListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, roomSummaryDataSource = roomSummaryDataSource ), createDateFormatter(), @@ -251,7 +246,6 @@ class RoomListPresenterTests { val roomSummaryDataSource = FakeRoomSummaryDataSource() val presenter = RoomListPresenter( FakeMatrixClient( - sessionId = A_SESSION_ID, roomSummaryDataSource = roomSummaryDataSource ), createDateFormatter(), @@ -280,9 +274,7 @@ class RoomListPresenterTests { fun `present - sets invite state`() = runTest { val inviteStateFlow = MutableStateFlow(InvitesState.NoInvites) val presenter = RoomListPresenter( - FakeMatrixClient( - sessionId = A_SESSION_ID, - ), + FakeMatrixClient(), createDateFormatter(), FakeRoomLastMessageFormatter(), FakeSessionVerificationService(), @@ -312,7 +304,7 @@ class RoomListPresenterTests { @Test fun `present - show context menu`() = runTest { val presenter = RoomListPresenter( - FakeMatrixClient(A_SESSION_ID), + FakeMatrixClient(), createDateFormatter(), FakeRoomLastMessageFormatter(), FakeSessionVerificationService(), @@ -339,7 +331,7 @@ class RoomListPresenterTests { @Test fun `present - hide context menu`() = runTest { val presenter = RoomListPresenter( - FakeMatrixClient(A_SESSION_ID), + FakeMatrixClient(), createDateFormatter(), FakeRoomLastMessageFormatter(), FakeSessionVerificationService(), @@ -371,7 +363,7 @@ class RoomListPresenterTests { fun `present - leave room calls into leave room presenter`() = runTest { val leaveRoomPresenter = LeaveRoomPresenterFake() val presenter = RoomListPresenter( - FakeMatrixClient(A_SESSION_ID), + FakeMatrixClient(), createDateFormatter(), FakeRoomLastMessageFormatter(), FakeSessionVerificationService(), 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 aaaac28ba7..85c3555844 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 @@ -16,7 +16,6 @@ package io.element.android.libraries.matrix.test -import io.element.android.libraries.core.coroutine.CoroutineDispatchers import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.SessionId diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt index 7e54d8e851..5b5ecc4510 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/TestData.kt @@ -54,8 +54,6 @@ const val AN_AVATAR_URL = "mxc://data" const val A_FAILURE_REASON = "There has been a failure" -const val FAKE_DELAY_IN_MS = 100L - val A_THROWABLE = Throwable(A_FAILURE_REASON) val AN_EXCEPTION = Exception(A_FAILURE_REASON) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt index 2b34a158a4..816bfc572a 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/auth/FakeAuthenticationService.kt @@ -22,8 +22,7 @@ import io.element.android.libraries.matrix.api.auth.MatrixHomeServerDetails import io.element.android.libraries.matrix.api.auth.OidcDetails import io.element.android.libraries.matrix.api.core.SessionId import io.element.android.libraries.matrix.test.A_USER_ID -import io.element.android.libraries.matrix.test.FAKE_DELAY_IN_MS -import kotlinx.coroutines.delay +import io.element.android.tests.testutils.simulateLongTask import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -58,27 +57,24 @@ class FakeAuthenticationService : MatrixAuthenticationService { this.homeserver.value = homeserver } - override suspend fun setHomeserver(homeserver: String): Result { - delay(FAKE_DELAY_IN_MS) - return changeServerError?.let { Result.failure(it) } ?: Result.success(Unit) + override suspend fun setHomeserver(homeserver: String): Result = simulateLongTask { + changeServerError?.let { Result.failure(it) } ?: Result.success(Unit) } - override suspend fun login(username: String, password: String): Result { - delay(FAKE_DELAY_IN_MS) - return loginError?.let { Result.failure(it) } ?: Result.success(A_USER_ID) + override suspend fun login(username: String, password: String): Result = simulateLongTask { + loginError?.let { Result.failure(it) } ?: Result.success(A_USER_ID) } - override suspend fun getOidcUrl(): Result { - return oidcError?.let { Result.failure(it) } ?: Result.success(A_OIDC_DATA) + override suspend fun getOidcUrl(): Result = simulateLongTask { + oidcError?.let { Result.failure(it) } ?: Result.success(A_OIDC_DATA) } override suspend fun cancelOidcLogin(): Result { return oidcCancelError?.let { Result.failure(it) } ?: Result.success(Unit) } - override suspend fun loginWithOidc(callbackUrl: String): Result { - delay(FAKE_DELAY_IN_MS) - return loginError?.let { Result.failure(it) } ?: Result.success(A_USER_ID) + override suspend fun loginWithOidc(callbackUrl: String): Result = simulateLongTask { + loginError?.let { Result.failure(it) } ?: Result.success(A_USER_ID) } fun givenOidcError(throwable: Throwable?) { diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/media/FakeMediaLoader.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/media/FakeMediaLoader.kt index f351ace464..9ef0413a3a 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/media/FakeMediaLoader.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/media/FakeMediaLoader.kt @@ -19,34 +19,30 @@ package io.element.android.libraries.matrix.test.media import io.element.android.libraries.matrix.api.media.MatrixMediaLoader import io.element.android.libraries.matrix.api.media.MediaFile import io.element.android.libraries.matrix.api.media.MediaSource -import io.element.android.libraries.matrix.test.FAKE_DELAY_IN_MS -import kotlinx.coroutines.delay +import io.element.android.tests.testutils.simulateLongTask class FakeMediaLoader : MatrixMediaLoader { var shouldFail = false - override suspend fun loadMediaContent(source: MediaSource): Result { - delay(FAKE_DELAY_IN_MS) - return if (shouldFail) { + override suspend fun loadMediaContent(source: MediaSource): Result = simulateLongTask { + if (shouldFail) { Result.failure(RuntimeException()) } else { Result.success(ByteArray(0)) } } - override suspend fun loadMediaThumbnail(source: MediaSource, width: Long, height: Long): Result { - delay(FAKE_DELAY_IN_MS) - return if (shouldFail) { + override suspend fun loadMediaThumbnail(source: MediaSource, width: Long, height: Long): Result = simulateLongTask { + if (shouldFail) { Result.failure(RuntimeException()) } else { Result.success(ByteArray(0)) } } - override suspend fun downloadMediaFile(source: MediaSource, mimeType: String?, body: String?): Result { - delay(FAKE_DELAY_IN_MS) - return if (shouldFail) { + override suspend fun downloadMediaFile(source: MediaSource, mimeType: String?, body: String?): Result = simulateLongTask { + if (shouldFail) { Result.failure(RuntimeException()) } else { Result.success(FakeMediaFile("")) diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt index 1199d94ac4..fd9f9e3a4c 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt @@ -30,9 +30,8 @@ import io.element.android.libraries.matrix.api.room.StateEventType import io.element.android.libraries.matrix.api.timeline.MatrixTimeline import io.element.android.libraries.matrix.test.A_ROOM_ID import io.element.android.libraries.matrix.test.A_SESSION_ID -import io.element.android.libraries.matrix.test.FAKE_DELAY_IN_MS import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline -import kotlinx.coroutines.delay +import io.element.android.tests.testutils.simulateLongTask import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.emptyFlow @@ -103,8 +102,8 @@ class FakeMatrixRoom( override val membersStateFlow: MutableStateFlow = MutableStateFlow(MatrixRoomMembersState.Unknown) - override suspend fun updateMembers(): Result { - return updateMembersResult + override suspend fun updateMembers(): Result = simulateLongTask { + updateMembersResult } override fun syncUpdateFlow(): Flow { @@ -115,17 +114,16 @@ class FakeMatrixRoom( return matrixTimeline } - override suspend fun userDisplayName(userId: UserId): Result { - return userDisplayNameResult + override suspend fun userDisplayName(userId: UserId): Result = simulateLongTask { + userDisplayNameResult } - override suspend fun userAvatarUrl(userId: UserId): Result { - return userAvatarUrlResult + override suspend fun userAvatarUrl(userId: UserId): Result = simulateLongTask { + userAvatarUrlResult } - override suspend fun sendMessage(message: String): Result { - delay(FAKE_DELAY_IN_MS) - return Result.success(Unit) + override suspend fun sendMessage(message: String): Result = simulateLongTask { + Result.success(Unit) } override suspend fun sendReaction(emoji: String, eventId: EventId): Result { @@ -138,7 +136,6 @@ class FakeMatrixRoom( override suspend fun editMessage(originalEventId: EventId, message: String): Result { editMessageParameter = message - delay(FAKE_DELAY_IN_MS) return Result.success(Unit) } @@ -147,7 +144,6 @@ class FakeMatrixRoom( override suspend fun replyMessage(eventId: EventId, message: String): Result { replyMessageParameter = message - delay(FAKE_DELAY_IN_MS) return Result.success(Unit) } @@ -156,11 +152,11 @@ class FakeMatrixRoom( override suspend fun redactEvent(eventId: EventId, reason: String?): Result { redactEventEventIdParam = eventId - delay(FAKE_DELAY_IN_MS) return Result.success(Unit) } override suspend fun leave(): Result = leaveRoomError?.let { Result.failure(it) } ?: Result.success(Unit) + override suspend fun acceptInvitation(): Result { isInviteAccepted = true return acceptInviteResult @@ -171,9 +167,9 @@ class FakeMatrixRoom( return rejectInviteResult } - override suspend fun inviteUserById(id: UserId): Result { + override suspend fun inviteUserById(id: UserId): Result = simulateLongTask { invitedUserId = id - return inviteUserResult + inviteUserResult } override suspend fun canInvite(): Result { @@ -192,31 +188,30 @@ class FakeMatrixRoom( override suspend fun sendFile(file: File, fileInfo: FileInfo): Result = fakeSendMedia() - private suspend fun fakeSendMedia(): Result { - delay(FAKE_DELAY_IN_MS) - return sendMediaResult.onSuccess { + private suspend fun fakeSendMedia(): Result = simulateLongTask { + sendMediaResult.onSuccess { sendMediaCount++ } } - override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result { + override suspend fun updateAvatar(mimeType: String, data: ByteArray): Result = simulateLongTask { newAvatarData = data - return updateAvatarResult + updateAvatarResult } - override suspend fun removeAvatar(): Result { + override suspend fun removeAvatar(): Result = simulateLongTask { removedAvatar = true - return removeAvatarResult + removeAvatarResult } - override suspend fun setName(name: String): Result { + override suspend fun setName(name: String): Result = simulateLongTask { newName = name - return setNameResult + setNameResult } - override suspend fun setTopic(topic: String): Result { + override suspend fun setTopic(topic: String): Result = simulateLongTask { newTopic = topic - return setTopicResult + setTopicResult } override fun close() = Unit diff --git a/libraries/mediaupload/test/build.gradle.kts b/libraries/mediaupload/test/build.gradle.kts index 535ba51ac4..956afffbe0 100644 --- a/libraries/mediaupload/test/build.gradle.kts +++ b/libraries/mediaupload/test/build.gradle.kts @@ -24,4 +24,5 @@ android { dependencies { api(projects.libraries.mediaupload.api) + implementation(projects.tests.testutils) } diff --git a/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt b/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt index c4ab8d57b1..0cc7803578 100644 --- a/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt +++ b/libraries/mediaupload/test/src/main/kotlin/io/element/android/libraries/mediaupload/test/FakeMediaPreProcessor.kt @@ -20,6 +20,7 @@ import android.net.Uri import io.element.android.libraries.matrix.api.media.FileInfo import io.element.android.libraries.mediaupload.api.MediaPreProcessor import io.element.android.libraries.mediaupload.api.MediaUploadInfo +import io.element.android.tests.testutils.simulateLongTask import java.io.File class FakeMediaPreProcessor : MediaPreProcessor { @@ -41,7 +42,9 @@ class FakeMediaPreProcessor : MediaPreProcessor { mimeType: String, deleteOriginal: Boolean, compressIfPossible: Boolean - ): Result = result + ): Result = simulateLongTask { + result + } fun givenResult(value: Result) { this.result = value diff --git a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt index d6cc2e2e31..e4cb389d94 100644 --- a/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt +++ b/samples/minimal/src/main/kotlin/io/element/android/samples/minimal/RoomListScreen.kt @@ -71,7 +71,7 @@ class RoomListScreen( networkMonitor = NetworkMonitorImpl(context), snackbarDispatcher = SnackbarDispatcher(), inviteStateDataSource = DefaultInviteStateDataSource(matrixClient, DefaultSeenInvitesStore(context), coroutineDispatchers), - leaveRoomPresenter = LeaveRoomPresenterImpl(matrixClient, RoomMembershipObserver() ,coroutineDispatchers) + leaveRoomPresenter = LeaveRoomPresenterImpl(matrixClient, RoomMembershipObserver(), coroutineDispatchers) ) @Composable diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/LongTask.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/LongTask.kt new file mode 100644 index 0000000000..154877efe9 --- /dev/null +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/LongTask.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.element.android.tests.testutils + +import kotlinx.coroutines.delay + +/** + * Workaround for https://github.com/cashapp/molecule/issues/249. + * This functions should be removed/deprecated right after we find a proper fix. + */ +suspend inline fun simulateLongTask(lambda: () -> T): T { + delay(1) + return lambda() +} diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/TestCoroutineDispatchers.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/TestCoroutineDispatchers.kt index 786d8f8cd2..b8376ddf6f 100644 --- a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/TestCoroutineDispatchers.kt +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/TestCoroutineDispatchers.kt @@ -31,19 +31,18 @@ import kotlinx.coroutines.test.UnconfinedTestDispatcher * If false, use [StandardTestDispatcher] for all dispatchers. */ fun TestScope.testCoroutineDispatchers( - useUnconfinedTestDispatcher: Boolean = true, + useUnconfinedTestDispatcher: Boolean = false, ): CoroutineDispatchers = when (useUnconfinedTestDispatcher) { - false -> CoroutineDispatchers( - io = StandardTestDispatcher(testScheduler), - computation = StandardTestDispatcher(testScheduler), - main = StandardTestDispatcher(testScheduler), - diffUpdateDispatcher = StandardTestDispatcher(testScheduler), - ) - true -> CoroutineDispatchers( io = UnconfinedTestDispatcher(testScheduler), computation = UnconfinedTestDispatcher(testScheduler), main = UnconfinedTestDispatcher(testScheduler), diffUpdateDispatcher = UnconfinedTestDispatcher(testScheduler), ) + false -> CoroutineDispatchers( + io = StandardTestDispatcher(testScheduler), + computation = StandardTestDispatcher(testScheduler), + main = StandardTestDispatcher(testScheduler), + diffUpdateDispatcher = StandardTestDispatcher(testScheduler), + ) }