diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt index ac53f191d3..44a4563720 100644 --- a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/pinned/list/PinnedMessagesListPresenterTest.kt @@ -18,16 +18,20 @@ package io.element.android.features.messages.impl.pinned.list import com.google.common.truth.Truth.assertThat import io.element.android.features.messages.impl.actionlist.FakeActionListPresenter +import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.fixtures.aTimelineItemsFactory import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider +import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.networkmonitor.api.NetworkMonitor import io.element.android.features.networkmonitor.test.FakeNetworkMonitor import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.featureflag.test.FakeFeatureFlagService -import io.element.android.libraries.matrix.api.core.UniqueId +import io.element.android.libraries.matrix.api.core.EventId +import io.element.android.libraries.matrix.api.core.TransactionId import io.element.android.libraries.matrix.api.room.MatrixRoom import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.test.AN_EVENT_ID import io.element.android.libraries.matrix.test.A_UNIQUE_ID import io.element.android.libraries.matrix.test.room.FakeMatrixRoom @@ -35,6 +39,9 @@ import io.element.android.libraries.matrix.test.room.aRoomInfo import io.element.android.libraries.matrix.test.timeline.FakeTimeline import io.element.android.libraries.matrix.test.timeline.aMessageContent import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem +import io.element.android.tests.testutils.lambda.assert +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.coroutines.flow.flowOf import kotlinx.coroutines.test.TestScope @@ -114,20 +121,7 @@ class PinnedMessagesListPresenterTest { @Test fun `present - filled state`() = runTest { - val messageContent = aMessageContent("A message") - val pinnedEventsTimeline = FakeTimeline( - timelineItems = flowOf( - listOf( - MatrixTimelineItem.Event( - uniqueId = A_UNIQUE_ID, - event = anEventTimelineItem( - eventId = AN_EVENT_ID, - content = messageContent, - ), - ) - ) - ) - ) + val pinnedEventsTimeline = createPinnedMessagesTimeline() val room = FakeMatrixRoom( pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) }, canRedactOwnResult = { Result.success(true) }, @@ -149,6 +143,161 @@ class PinnedMessagesListPresenterTest { } } + @Test + fun `present - redact event`() = runTest { + val redactEventLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String? -> Result.success(true) } + val pinnedEventsTimeline = createPinnedMessagesTimeline().apply { + this.redactEventLambda = redactEventLambda + } + val room = FakeMatrixRoom( + pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ).apply { + givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) + } + val presenter = createPinnedMessagesListPresenter(room = room, isFeatureEnabled = true) + presenter.test { + skipItems(3) + val filledState = awaitItem() as PinnedMessagesListState.Filled + val eventItem = filledState.timelineItems.first() as TimelineItem.Event + filledState.eventSink(PinnedMessagesListEvents.HandleAction(TimelineItemAction.Redact, eventItem)) + cancelAndIgnoreRemainingEvents() + assert(redactEventLambda) + .isCalledOnce() + .with(value(AN_EVENT_ID), value(null), value(null)) + } + } + + @Test + fun `present - unpin event`() = runTest { + val unpinEventLambda = lambdaRecorder { _: EventId? -> Result.success(true) } + val pinnedEventsTimeline = createPinnedMessagesTimeline().apply { + this.unpinEventLambda = unpinEventLambda + } + val room = FakeMatrixRoom( + pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ).apply { + givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) + } + val presenter = createPinnedMessagesListPresenter(room = room, isFeatureEnabled = true) + presenter.test { + skipItems(3) + val filledState = awaitItem() as PinnedMessagesListState.Filled + val eventItem = filledState.timelineItems.first() as TimelineItem.Event + filledState.eventSink(PinnedMessagesListEvents.HandleAction(TimelineItemAction.Unpin, eventItem)) + cancelAndIgnoreRemainingEvents() + assert(unpinEventLambda) + .isCalledOnce() + .with(value(AN_EVENT_ID)) + } + } + + @Test + fun `present - navigate to event`() = runTest { + val onViewInTimelineClickLambda = lambdaRecorder { _: EventId -> } + val navigator = FakePinnedMessagesListNavigator().apply { + this.onViewInTimelineClickLambda = onViewInTimelineClickLambda + } + val pinnedEventsTimeline = createPinnedMessagesTimeline() + val room = FakeMatrixRoom( + pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ).apply { + givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) + } + val presenter = createPinnedMessagesListPresenter(room = room, navigator = navigator, isFeatureEnabled = true) + presenter.test { + skipItems(3) + val filledState = awaitItem() as PinnedMessagesListState.Filled + val eventItem = filledState.timelineItems.first() as TimelineItem.Event + filledState.eventSink(PinnedMessagesListEvents.HandleAction(TimelineItemAction.ViewInTimeline, eventItem)) + cancelAndIgnoreRemainingEvents() + assert(onViewInTimelineClickLambda) + .isCalledOnce() + .with(value(AN_EVENT_ID)) + } + } + + @Test + fun `present - show view source action`() = runTest { + val onShowEventDebugInfoClickLambda = lambdaRecorder { _: EventId?, _: TimelineItemDebugInfo -> } + val navigator = FakePinnedMessagesListNavigator().apply { + this.onShowEventDebugInfoClickLambda = onShowEventDebugInfoClickLambda + } + val pinnedEventsTimeline = createPinnedMessagesTimeline() + val room = FakeMatrixRoom( + pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ).apply { + givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) + } + val presenter = createPinnedMessagesListPresenter(room = room, navigator = navigator, isFeatureEnabled = true) + presenter.test { + skipItems(3) + val filledState = awaitItem() as PinnedMessagesListState.Filled + val eventItem = filledState.timelineItems.first() as TimelineItem.Event + filledState.eventSink(PinnedMessagesListEvents.HandleAction(TimelineItemAction.ViewSource, eventItem)) + cancelAndIgnoreRemainingEvents() + assert(onShowEventDebugInfoClickLambda) + .isCalledOnce() + .with(value(AN_EVENT_ID), value(eventItem.debugInfo)) + } + } + + @Test + fun `present - forward event`() = runTest { + val onForwardEventClickLambda = lambdaRecorder { _: EventId -> } + val navigator = FakePinnedMessagesListNavigator().apply { + this.onForwardEventClickLambda = onForwardEventClickLambda + } + val pinnedEventsTimeline = createPinnedMessagesTimeline() + val room = FakeMatrixRoom( + pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) }, + canRedactOwnResult = { Result.success(true) }, + canRedactOtherResult = { Result.success(true) }, + canUserPinUnpinResult = { Result.success(true) }, + ).apply { + givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID))) + } + val presenter = createPinnedMessagesListPresenter(room = room, navigator = navigator, isFeatureEnabled = true) + presenter.test { + skipItems(3) + val filledState = awaitItem() as PinnedMessagesListState.Filled + val eventItem = filledState.timelineItems.first() as TimelineItem.Event + filledState.eventSink(PinnedMessagesListEvents.HandleAction(TimelineItemAction.Forward, eventItem)) + cancelAndIgnoreRemainingEvents() + assert(onForwardEventClickLambda) + .isCalledOnce() + .with(value(AN_EVENT_ID)) + } + } + + private fun createPinnedMessagesTimeline(): FakeTimeline { + val messageContent = aMessageContent("A message") + return FakeTimeline( + timelineItems = flowOf( + listOf( + MatrixTimelineItem.Event( + uniqueId = A_UNIQUE_ID, + event = anEventTimelineItem( + eventId = AN_EVENT_ID, + content = messageContent, + ), + ) + ) + ) + ) + } + private fun TestScope.createPinnedMessagesListPresenter( navigator: PinnedMessagesListNavigator = FakePinnedMessagesListNavigator(), room: MatrixRoom = FakeMatrixRoom(),