|
|
@ -18,16 +18,20 @@ package io.element.android.features.messages.impl.pinned.list |
|
|
|
|
|
|
|
|
|
|
|
import com.google.common.truth.Truth.assertThat |
|
|
|
import com.google.common.truth.Truth.assertThat |
|
|
|
import io.element.android.features.messages.impl.actionlist.FakeActionListPresenter |
|
|
|
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.fixtures.aTimelineItemsFactory |
|
|
|
import io.element.android.features.messages.impl.pinned.PinnedEventsTimelineProvider |
|
|
|
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.api.NetworkMonitor |
|
|
|
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor |
|
|
|
import io.element.android.features.networkmonitor.test.FakeNetworkMonitor |
|
|
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher |
|
|
|
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatcher |
|
|
|
import io.element.android.libraries.featureflag.api.FeatureFlags |
|
|
|
import io.element.android.libraries.featureflag.api.FeatureFlags |
|
|
|
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService |
|
|
|
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.room.MatrixRoom |
|
|
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem |
|
|
|
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.AN_EVENT_ID |
|
|
|
import io.element.android.libraries.matrix.test.A_UNIQUE_ID |
|
|
|
import io.element.android.libraries.matrix.test.A_UNIQUE_ID |
|
|
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom |
|
|
|
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.FakeTimeline |
|
|
|
import io.element.android.libraries.matrix.test.timeline.aMessageContent |
|
|
|
import io.element.android.libraries.matrix.test.timeline.aMessageContent |
|
|
|
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem |
|
|
|
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 io.element.android.tests.testutils.test |
|
|
|
import kotlinx.coroutines.flow.flowOf |
|
|
|
import kotlinx.coroutines.flow.flowOf |
|
|
|
import kotlinx.coroutines.test.TestScope |
|
|
|
import kotlinx.coroutines.test.TestScope |
|
|
@ -114,20 +121,7 @@ class PinnedMessagesListPresenterTest { |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
fun `present - filled state`() = runTest { |
|
|
|
fun `present - filled state`() = runTest { |
|
|
|
val messageContent = aMessageContent("A message") |
|
|
|
val pinnedEventsTimeline = createPinnedMessagesTimeline() |
|
|
|
val pinnedEventsTimeline = FakeTimeline( |
|
|
|
|
|
|
|
timelineItems = flowOf( |
|
|
|
|
|
|
|
listOf( |
|
|
|
|
|
|
|
MatrixTimelineItem.Event( |
|
|
|
|
|
|
|
uniqueId = A_UNIQUE_ID, |
|
|
|
|
|
|
|
event = anEventTimelineItem( |
|
|
|
|
|
|
|
eventId = AN_EVENT_ID, |
|
|
|
|
|
|
|
content = messageContent, |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
val room = FakeMatrixRoom( |
|
|
|
val room = FakeMatrixRoom( |
|
|
|
pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) }, |
|
|
|
pinnedEventsTimelineResult = { Result.success(pinnedEventsTimeline) }, |
|
|
|
canRedactOwnResult = { Result.success(true) }, |
|
|
|
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( |
|
|
|
private fun TestScope.createPinnedMessagesListPresenter( |
|
|
|
navigator: PinnedMessagesListNavigator = FakePinnedMessagesListNavigator(), |
|
|
|
navigator: PinnedMessagesListNavigator = FakePinnedMessagesListNavigator(), |
|
|
|
room: MatrixRoom = FakeMatrixRoom(), |
|
|
|
room: MatrixRoom = FakeMatrixRoom(), |
|
|
|