From c86154d120b0a7e84cf48bdd217a2e7565d04fb6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 27 May 2025 16:31:05 +0200 Subject: [PATCH] Hide Element Call entry point if Element Call service is not available. (#4783) * Hide Element Call entry point if Element Call service is not available. * No need to preview the case RoomCallState.Unavailable * Hide start call action from user profile if Element Call is not available. * Add mising `use` and cover the problem by a test. * Update screenshots * Update enterprise submodule ref. * Ensure `enterpriseService.isElementCallAvailable()` is not called several times. And fix unit tests on CI --------- Co-authored-by: ElementBot --- enterprise | 2 +- .../enterprise/api/EnterpriseService.kt | 2 + .../impl/DefaultEnterpriseService.kt | 2 + .../enterprise/test/FakeEnterpriseService.kt | 5 ++ .../impl/timeline/components/CallMenuItem.kt | 3 + .../components/TimelineItemCallNotifyView.kt | 11 +-- .../features/roomcall/api/RoomCallState.kt | 3 + .../roomcall/api/RoomCallStateProvider.kt | 1 + features/roomcall/impl/build.gradle.kts | 2 + .../roomcall/impl/RoomCallStatePresenter.kt | 7 ++ .../impl/RoomCallStatePresenterTest.kt | 78 ++++++++++++------- features/userprofile/impl/build.gradle.kts | 2 + .../impl/root/UserProfilePresenter.kt | 22 ++++-- .../impl/UserProfilePresenterTest.kt | 35 +++++++-- .../matrix/test/room/FakeBaseRoom.kt | 10 ++- ...eline.components_CallMenuItem_Day_5_en.png | 3 + ...ine.components_CallMenuItem_Night_5_en.png | 3 + 17 files changed, 146 insertions(+), 45 deletions(-) create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_CallMenuItem_Day_5_en.png create mode 100644 tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_CallMenuItem_Night_5_en.png diff --git a/enterprise b/enterprise index d3dffc97bf..4a07c862a2 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit d3dffc97bf8b39386ace2db7d857bbff05c73c18 +Subproject commit 4a07c862a23a9fd1418eabf132cf9d6b25ea4927 diff --git a/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt b/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt index 4e2a3cc1f2..d15586038b 100644 --- a/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt +++ b/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt @@ -16,6 +16,8 @@ interface EnterpriseService { fun defaultHomeserverList(): List suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String): Boolean + suspend fun isElementCallAvailable(): Boolean + fun semanticColorsLight(): SemanticColors fun semanticColorsDark(): SemanticColors diff --git a/features/enterprise/impl/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt b/features/enterprise/impl/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt index 7f4f4b387b..3b0995c81e 100644 --- a/features/enterprise/impl/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt +++ b/features/enterprise/impl/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt @@ -25,6 +25,8 @@ class DefaultEnterpriseService @Inject constructor() : EnterpriseService { override fun defaultHomeserverList(): List = emptyList() override suspend fun isAllowedToConnectToHomeserver(homeserverUrl: String) = true + override suspend fun isElementCallAvailable(): Boolean = true + override fun semanticColorsLight(): SemanticColors = compoundColorsLight override fun semanticColorsDark(): SemanticColors = compoundColorsDark diff --git a/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt b/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt index 14195e1243..bc90c77ada 100644 --- a/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt +++ b/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt @@ -18,6 +18,7 @@ class FakeEnterpriseService( private val isEnterpriseUserResult: (SessionId) -> Boolean = { lambdaError() }, private val defaultHomeserverListResult: () -> List = { emptyList() }, private val isAllowedToConnectToHomeserverResult: (String) -> Boolean = { lambdaError() }, + private val isElementCallAvailableResult: () -> Boolean = { lambdaError() }, private val semanticColorsLightResult: () -> SemanticColors = { lambdaError() }, private val semanticColorsDarkResult: () -> SemanticColors = { lambdaError() }, private val firebasePushGatewayResult: () -> String? = { lambdaError() }, @@ -35,6 +36,10 @@ class FakeEnterpriseService( isAllowedToConnectToHomeserverResult(homeserverUrl) } + override suspend fun isElementCallAvailable(): Boolean = simulateLongTask { + isElementCallAvailableResult() + } + override fun semanticColorsLight(): SemanticColors { return semanticColorsLightResult() } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/CallMenuItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/CallMenuItem.kt index 098421f177..4bbccabc53 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/CallMenuItem.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/CallMenuItem.kt @@ -38,6 +38,9 @@ internal fun CallMenuItem( modifier: Modifier = Modifier, ) { when (roomCallState) { + RoomCallState.Unavailable -> { + Box(modifier) + } is RoomCallState.StandBy -> { StandByCallMenuItem( roomCallState = roomCallState, diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt index 41d9fa111b..1386a5a666 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemCallNotifyView.kt @@ -103,10 +103,12 @@ internal fun TimelineItemCallNotifyView( @PreviewsDayNight @Composable -internal fun TimelineItemCallNotifyViewPreview() { - ElementPreview { - Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) { - RoomCallStateProvider().values.forEach { roomCallState -> +internal fun TimelineItemCallNotifyViewPreview() = ElementPreview { + Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) { + RoomCallStateProvider() + .values + .filter { it !is RoomCallState.Unavailable } + .forEach { roomCallState -> TimelineItemCallNotifyView( event = aTimelineItemEvent(content = TimelineItemCallNotifyContent()), roomCallState = roomCallState, @@ -114,6 +116,5 @@ internal fun TimelineItemCallNotifyViewPreview() { onJoinCallClick = {}, ) } - } } } diff --git a/features/roomcall/api/src/main/kotlin/io/element/android/features/roomcall/api/RoomCallState.kt b/features/roomcall/api/src/main/kotlin/io/element/android/features/roomcall/api/RoomCallState.kt index 13db67f447..725915b91a 100644 --- a/features/roomcall/api/src/main/kotlin/io/element/android/features/roomcall/api/RoomCallState.kt +++ b/features/roomcall/api/src/main/kotlin/io/element/android/features/roomcall/api/RoomCallState.kt @@ -13,6 +13,8 @@ import io.element.android.features.roomcall.api.RoomCallState.StandBy @Immutable sealed interface RoomCallState { + data object Unavailable : RoomCallState + data class StandBy( val canStartCall: Boolean, ) : RoomCallState @@ -25,6 +27,7 @@ sealed interface RoomCallState { } fun RoomCallState.hasPermissionToJoin() = when (this) { + RoomCallState.Unavailable -> false is StandBy -> canStartCall is OnGoing -> canJoinCall } diff --git a/features/roomcall/api/src/main/kotlin/io/element/android/features/roomcall/api/RoomCallStateProvider.kt b/features/roomcall/api/src/main/kotlin/io/element/android/features/roomcall/api/RoomCallStateProvider.kt index cd83a06616..de3bc4ade8 100644 --- a/features/roomcall/api/src/main/kotlin/io/element/android/features/roomcall/api/RoomCallStateProvider.kt +++ b/features/roomcall/api/src/main/kotlin/io/element/android/features/roomcall/api/RoomCallStateProvider.kt @@ -16,6 +16,7 @@ open class RoomCallStateProvider : PreviewParameterProvider { anOngoingCallState(), anOngoingCallState(canJoinCall = false), anOngoingCallState(canJoinCall = true, isUserInTheCall = true), + RoomCallState.Unavailable, ) } diff --git a/features/roomcall/impl/build.gradle.kts b/features/roomcall/impl/build.gradle.kts index d4ed1e1fd4..0ec555bfb5 100644 --- a/features/roomcall/impl/build.gradle.kts +++ b/features/roomcall/impl/build.gradle.kts @@ -21,6 +21,7 @@ dependencies { api(projects.features.roomcall.api) implementation(libs.kotlinx.collections.immutable) implementation(projects.features.call.api) + implementation(projects.features.enterprise.api) implementation(projects.libraries.architecture) implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrixui) @@ -32,6 +33,7 @@ dependencies { testImplementation(libs.test.turbine) testImplementation(projects.libraries.matrix.test) testImplementation(projects.features.call.test) + testImplementation(projects.features.enterprise.test) testImplementation(projects.tests.testutils) testImplementation(libs.androidx.compose.ui.test.junit) testReleaseImplementation(libs.androidx.compose.ui.test.manifest) diff --git a/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt b/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt index 6df9f8103b..dbcf39766b 100644 --- a/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt +++ b/features/roomcall/impl/src/main/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenter.kt @@ -11,9 +11,11 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue +import androidx.compose.runtime.produceState import androidx.compose.runtime.remember import io.element.android.features.call.api.CurrentCall import io.element.android.features.call.api.CurrentCallService +import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.roomcall.api.RoomCallState import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.matrix.api.room.JoinedRoom @@ -23,9 +25,13 @@ import javax.inject.Inject class RoomCallStatePresenter @Inject constructor( private val room: JoinedRoom, private val currentCallService: CurrentCallService, + private val enterpriseService: EnterpriseService, ) : Presenter { @Composable override fun present(): RoomCallState { + val isAvailable by produceState(false) { + value = enterpriseService.isElementCallAvailable() + } val roomInfo by room.roomInfoFlow.collectAsState() val syncUpdateFlow = room.syncUpdateFlow.collectAsState() val canJoinCall by room.canCall(updateKey = syncUpdateFlow.value) @@ -41,6 +47,7 @@ class RoomCallStatePresenter @Inject constructor( } } val callState = when { + isAvailable.not() -> RoomCallState.Unavailable roomInfo.hasRoomCall -> RoomCallState.OnGoing( canJoinCall = canJoinCall, isUserInTheCall = isUserInTheCall, diff --git a/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt b/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt index 9f99b9b1af..437a495934 100644 --- a/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt +++ b/features/roomcall/impl/src/test/kotlin/io/element/android/features/roomcall/impl/RoomCallStatePresenterTest.kt @@ -11,6 +11,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.call.api.CurrentCall import io.element.android.features.call.api.CurrentCallService import io.element.android.features.call.test.FakeCurrentCallService +import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.roomcall.api.RoomCallState import io.element.android.libraries.matrix.api.room.JoinedRoom import io.element.android.libraries.matrix.test.room.FakeBaseRoom @@ -25,12 +26,13 @@ class RoomCallStatePresenterTest { @Test fun `present - initial state`() = runTest { val room = FakeJoinedRoom( - baseRoom = FakeBaseRoom( + baseRoom = FakeBaseRoom( canUserJoinCallResult = { Result.success(false) }, ) ) val presenter = createRoomCallStatePresenter(joinedRoom = room) presenter.test { + skipItems(1) val initialState = awaitItem() assertThat(initialState).isEqualTo( RoomCallState.StandBy( @@ -40,10 +42,29 @@ class RoomCallStatePresenterTest { } } + @Test + fun `present - element call not available`() = runTest { + val room = FakeJoinedRoom( + baseRoom = FakeBaseRoom( + canUserJoinCallResult = { Result.success(false) }, + ) + ) + val presenter = createRoomCallStatePresenter( + joinedRoom = room, + isElementCallAvailable = false, + ) + presenter.test { + val initialState = awaitItem() + assertThat(initialState).isEqualTo( + RoomCallState.Unavailable + ) + } + } + @Test fun `present - initial state - user can join call`() = runTest { val room = FakeJoinedRoom( - baseRoom = FakeBaseRoom( + baseRoom = FakeBaseRoom( canUserJoinCallResult = { Result.success(true) }, ) ) @@ -69,6 +90,7 @@ class RoomCallStatePresenterTest { ) val presenter = createRoomCallStatePresenter(joinedRoom = room) presenter.test { + skipItems(1) assertThat(awaitItem()).isEqualTo( RoomCallState.OnGoing( canJoinCall = false, @@ -83,15 +105,15 @@ class RoomCallStatePresenterTest { fun `present - user has joined the call on another session`() = runTest { val room = FakeJoinedRoom( baseRoom = FakeBaseRoom( - canUserJoinCallResult = { Result.success(true) }, - ).apply { - givenRoomInfo( - aRoomInfo( - hasRoomCall = true, - activeRoomCallParticipants = listOf(sessionId), + canUserJoinCallResult = { Result.success(true) }, + ).apply { + givenRoomInfo( + aRoomInfo( + hasRoomCall = true, + activeRoomCallParticipants = listOf(sessionId), + ) ) - ) - } + } ) val presenter = createRoomCallStatePresenter(joinedRoom = room) presenter.test { @@ -110,15 +132,15 @@ class RoomCallStatePresenterTest { fun `present - user has joined the call locally`() = runTest { val room = FakeJoinedRoom( baseRoom = FakeBaseRoom( - canUserJoinCallResult = { Result.success(true) }, - ).apply { - givenRoomInfo( - aRoomInfo( - hasRoomCall = true, - activeRoomCallParticipants = listOf(sessionId), + canUserJoinCallResult = { Result.success(true) }, + ).apply { + givenRoomInfo( + aRoomInfo( + hasRoomCall = true, + activeRoomCallParticipants = listOf(sessionId), + ) ) - ) - } + } ) val presenter = createRoomCallStatePresenter( joinedRoom = room, @@ -140,15 +162,15 @@ class RoomCallStatePresenterTest { fun `present - user leaves the call`() = runTest { val room = FakeJoinedRoom( baseRoom = FakeBaseRoom( - canUserJoinCallResult = { Result.success(true) }, - ).apply { - givenRoomInfo( - aRoomInfo( - hasRoomCall = true, - activeRoomCallParticipants = listOf(sessionId), + canUserJoinCallResult = { Result.success(true) }, + ).apply { + givenRoomInfo( + aRoomInfo( + hasRoomCall = true, + activeRoomCallParticipants = listOf(sessionId), + ) ) - ) - } + } ) val currentCall = MutableStateFlow(CurrentCall.RoomCall(room.roomId)) val currentCallService = FakeCurrentCallService(currentCall = currentCall) @@ -203,10 +225,14 @@ class RoomCallStatePresenterTest { private fun createRoomCallStatePresenter( joinedRoom: JoinedRoom, currentCallService: CurrentCallService = FakeCurrentCallService(), + isElementCallAvailable: Boolean = true, ): RoomCallStatePresenter { return RoomCallStatePresenter( room = joinedRoom, currentCallService = currentCallService, + enterpriseService = FakeEnterpriseService( + isElementCallAvailableResult = { isElementCallAvailable }, + ), ) } } diff --git a/features/userprofile/impl/build.gradle.kts b/features/userprofile/impl/build.gradle.kts index 70769c986d..4242efcb98 100644 --- a/features/userprofile/impl/build.gradle.kts +++ b/features/userprofile/impl/build.gradle.kts @@ -33,6 +33,7 @@ dependencies { implementation(projects.libraries.androidutils) implementation(projects.libraries.mediaviewer.api) implementation(projects.features.call.api) + implementation(projects.features.enterprise.api) implementation(projects.features.verifysession.api) api(projects.features.userprofile.api) api(projects.features.userprofile.shared) @@ -49,6 +50,7 @@ dependencies { testImplementation(libs.test.robolectric) testImplementation(projects.libraries.matrix.test) testImplementation(projects.features.createroom.test) + testImplementation(projects.features.enterprise.test) testImplementation(projects.tests.testutils) testImplementation(libs.androidx.compose.ui.test.junit) testReleaseImplementation(libs.androidx.compose.ui.test.manifest) diff --git a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt index c098177529..237c57fecf 100644 --- a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt +++ b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/root/UserProfilePresenter.kt @@ -21,6 +21,7 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import io.element.android.features.createroom.api.StartDMAction +import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileState.ConfirmationDialog @@ -44,6 +45,7 @@ class UserProfilePresenter @AssistedInject constructor( @Assisted private val userId: UserId, private val client: MatrixClient, private val startDMAction: StartDMAction, + private val enterpriseService: EnterpriseService, ) : Presenter { @AssistedFactory interface Factory { @@ -59,11 +61,21 @@ class UserProfilePresenter @AssistedInject constructor( @Composable private fun getCanCall(roomId: RoomId?): State { - return produceState(initialValue = false, roomId) { - value = if (client.isMe(userId)) { - false - } else { - roomId?.let { client.getRoom(it)?.canUserJoinCall(client.sessionId)?.getOrNull() == true }.orFalse() + val isElementCallAvailable by produceState(initialValue = false, roomId) { + value = enterpriseService.isElementCallAvailable() + } + + return produceState(initialValue = false, isElementCallAvailable, roomId) { + value = when { + isElementCallAvailable.not() -> false + client.isMe(userId) -> false + else -> + roomId + ?.let { client.getRoom(it) } + ?.use { room -> + room.canUserJoinCall(client.sessionId).getOrNull() + } + .orFalse() } } } 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 76464b973c..d0369da660 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 @@ -16,6 +16,7 @@ import com.google.common.truth.Truth.assertThat import io.element.android.features.createroom.api.ConfirmingStartDmWithMatrixUser import io.element.android.features.createroom.api.StartDMAction import io.element.android.features.createroom.test.FakeStartDMAction +import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.userprofile.api.UserProfileEvents import io.element.android.features.userprofile.api.UserProfileState import io.element.android.features.userprofile.api.UserProfileVerificationState @@ -37,7 +38,6 @@ import io.element.android.libraries.matrix.test.encryption.FakeEncryptionService import io.element.android.libraries.matrix.test.room.FakeBaseRoom import io.element.android.libraries.matrix.ui.components.aMatrixUser import io.element.android.tests.testutils.WarmUpRule -import io.element.android.tests.testutils.awaitLastSequentialItem import io.element.android.tests.testutils.lambda.any import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value @@ -81,6 +81,8 @@ class UserProfilePresenterTest { fun `present - canCall is true when all the conditions are met`() { testCanCall( expectedResult = true, + skipItems = 3, + checkThatRoomIsDestroyed = true, ) } @@ -116,11 +118,22 @@ class UserProfilePresenterTest { ) } + @Test + fun `present - canCall is false when call is not available`() { + testCanCall( + isElementCallAvailable = false, + expectedResult = false, + ) + } + private fun testCanCall( + isElementCallAvailable: Boolean = true, canUserJoinCallResult: Result = Result.success(true), dmRoom: RoomId? = A_ROOM_ID, canFindRoom: Boolean = true, expectedResult: Boolean, + skipItems: Int = 1, + checkThatRoomIsDestroyed: Boolean = false, ) = runTest { val room = FakeBaseRoom( canUserJoinCallResult = { canUserJoinCallResult }, @@ -134,11 +147,15 @@ class UserProfilePresenterTest { val presenter = createUserProfilePresenter( userId = A_USER_ID_2, client = client, + isElementCallAvailable = isElementCallAvailable, ) presenter.test { - val initialState = awaitLastSequentialItem() + val initialState = awaitFirstItem(skipItems) assertThat(initialState.canCall).isEqualTo(expectedResult) } + if (checkThatRoomIsDestroyed) { + room.assertDestroyed() + } } @Test @@ -202,7 +219,7 @@ class UserProfilePresenterTest { ) val presenter = createUserProfilePresenter(client = matrixClient) presenter.test { - val initialState = awaitFirstItem() + val initialState = awaitFirstItem(count = 2) initialState.eventSink(UserProfileEvents.BlockUser(needsConfirmation = false)) assertThat(awaitItem().isBlocked.isLoading()).isTrue() val errorState = awaitItem() @@ -220,7 +237,7 @@ class UserProfilePresenterTest { ) val presenter = createUserProfilePresenter(client = matrixClient) presenter.test { - val initialState = awaitFirstItem() + val initialState = awaitFirstItem(count = 2) initialState.eventSink(UserProfileEvents.UnblockUser(needsConfirmation = false)) assertThat(awaitItem().isBlocked.isLoading()).isTrue() val errorState = awaitItem() @@ -363,8 +380,8 @@ class UserProfilePresenterTest { } } - private suspend fun ReceiveTurbine.awaitFirstItem(): T { - skipItems(1) + private suspend fun ReceiveTurbine.awaitFirstItem(count: Int = 1): T { + skipItems(count) return awaitItem() } @@ -387,12 +404,16 @@ class UserProfilePresenterTest { private fun createUserProfilePresenter( client: MatrixClient = createFakeMatrixClient(), userId: UserId = UserId("@alice:server.org"), - startDMAction: StartDMAction = FakeStartDMAction() + startDMAction: StartDMAction = FakeStartDMAction(), + isElementCallAvailable: Boolean = true, ): UserProfilePresenter { return UserProfilePresenter( userId = userId, client = client, startDMAction = startDMAction, + enterpriseService = FakeEnterpriseService( + isElementCallAvailableResult = { isElementCallAvailable }, + ), ) } } diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt index 76e5403133..d755722bd3 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeBaseRoom.kt @@ -93,7 +93,15 @@ class FakeBaseRoom( return powerLevelsResult() } - override fun destroy() = Unit + private var isDestroyed = false + + override fun destroy() { + isDestroyed = true + } + + fun assertDestroyed() { + check(isDestroyed) { "Room should be destroyed" } + } override suspend fun userDisplayName(userId: UserId): Result = simulateLongTask { userDisplayNameResult(userId) diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_CallMenuItem_Day_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_CallMenuItem_Day_5_en.png new file mode 100644 index 0000000000..1b6fb4bab8 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_CallMenuItem_Day_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96a867cb12498cbdc97957bee07855dfaa13602baddaf933aff2b666ef4c7650 +size 3642 diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_CallMenuItem_Night_5_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_CallMenuItem_Night_5_en.png new file mode 100644 index 0000000000..d6fd8eeb70 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl.timeline.components_CallMenuItem_Night_5_en.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5bb36ccd718f3fec5b04f1bc812dc7718b5ea7fa4619c8b031466297a8d016fd +size 3659