Timeline: fix some tests and a one more
This commit is contained in:
parent
8f2afbd797
commit
231f278adb
9 changed files with 137 additions and 54 deletions
|
|
@ -30,8 +30,8 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
|
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
@ -154,13 +154,14 @@ internal fun aTimelineItemDebugInfo(
|
||||||
model, originalJson, latestEditedJson
|
model, originalJson, latestEditedJson
|
||||||
)
|
)
|
||||||
|
|
||||||
fun aGroupedEvents(): TimelineItem.GroupedEvents {
|
fun aGroupedEvents(id: Long = 0): TimelineItem.GroupedEvents {
|
||||||
val event = aTimelineItemEvent(
|
val event = aTimelineItemEvent(
|
||||||
isMine = true,
|
isMine = true,
|
||||||
content = aTimelineItemStateEventContent(),
|
content = aTimelineItemStateEventContent(),
|
||||||
groupPosition = TimelineItemGroupPosition.None
|
groupPosition = TimelineItemGroupPosition.None
|
||||||
)
|
)
|
||||||
return TimelineItem.GroupedEvents(
|
return TimelineItem.GroupedEvents(
|
||||||
|
id = id.toString(),
|
||||||
events = listOf(
|
events = listOf(
|
||||||
event,
|
event,
|
||||||
event,
|
event,
|
||||||
|
|
|
||||||
|
|
@ -262,6 +262,7 @@ private fun BoxScope.TimelineScrollHelper(
|
||||||
}
|
}
|
||||||
|
|
||||||
JumpToBottomButton(
|
JumpToBottomButton(
|
||||||
|
// Use inverse of canAutoScroll otherwise we might briefly see the before the scroll animation is triggered
|
||||||
isVisible = !canAutoScroll,
|
isVisible = !canAutoScroll,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.BottomEnd)
|
.align(Alignment.BottomEnd)
|
||||||
|
|
|
||||||
|
|
@ -572,6 +572,8 @@ class MessagesPresenterTest {
|
||||||
val timelinePresenter = TimelinePresenter(
|
val timelinePresenter = TimelinePresenter(
|
||||||
timelineItemsFactory = aTimelineItemsFactory(),
|
timelineItemsFactory = aTimelineItemsFactory(),
|
||||||
room = matrixRoom,
|
room = matrixRoom,
|
||||||
|
dispatchers = coroutineDispatchers,
|
||||||
|
appScope = this
|
||||||
)
|
)
|
||||||
val buildMeta = aBuildMeta()
|
val buildMeta = aBuildMeta()
|
||||||
val actionListPresenter = ActionListPresenter(buildMeta = buildMeta)
|
val actionListPresenter = ActionListPresenter(buildMeta = buildMeta)
|
||||||
|
|
|
||||||
|
|
@ -52,4 +52,5 @@ internal fun aMessageEvent(
|
||||||
localSendState = sendState,
|
localSendState = sendState,
|
||||||
inReplyTo = inReplyTo,
|
inReplyTo = inReplyTo,
|
||||||
debugInfo = debugInfo,
|
debugInfo = debugInfo,
|
||||||
|
origin = null
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -23,22 +23,25 @@ import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.messages.fixtures.aTimelineItemsFactory
|
import io.element.android.features.messages.fixtures.aTimelineItemsFactory
|
||||||
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
import io.element.android.features.messages.impl.timeline.TimelineEvents
|
||||||
import io.element.android.features.messages.impl.timeline.TimelinePresenter
|
import io.element.android.features.messages.impl.timeline.TimelinePresenter
|
||||||
|
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||||
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.virtual.VirtualTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem
|
||||||
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.room.FakeMatrixRoom
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
|
import io.element.android.libraries.matrix.test.room.aMessageContent
|
||||||
import io.element.android.libraries.matrix.test.room.anEventTimelineItem
|
import io.element.android.libraries.matrix.test.room.anEventTimelineItem
|
||||||
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
import io.element.android.libraries.matrix.test.timeline.FakeMatrixTimeline
|
||||||
|
import io.element.android.tests.testutils.awaitWithLatch
|
||||||
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class TimelinePresenterTest {
|
class TimelinePresenterTest {
|
||||||
@Test
|
@Test
|
||||||
fun `present - initial state`() = runTest {
|
fun `present - initial state`() = runTest {
|
||||||
val presenter = TimelinePresenter(
|
val presenter = createTimelinePresenter()
|
||||||
timelineItemsFactory = aTimelineItemsFactory(),
|
|
||||||
room = FakeMatrixRoom(),
|
|
||||||
)
|
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -51,10 +54,7 @@ class TimelinePresenterTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - load more`() = runTest {
|
fun `present - load more`() = runTest {
|
||||||
val presenter = TimelinePresenter(
|
val presenter = createTimelinePresenter()
|
||||||
timelineItemsFactory = aTimelineItemsFactory(),
|
|
||||||
room = FakeMatrixRoom(),
|
|
||||||
)
|
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -73,10 +73,7 @@ class TimelinePresenterTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - set highlighted event`() = runTest {
|
fun `present - set highlighted event`() = runTest {
|
||||||
val presenter = TimelinePresenter(
|
val presenter = createTimelinePresenter()
|
||||||
timelineItemsFactory = aTimelineItemsFactory(),
|
|
||||||
room = FakeMatrixRoom(),
|
|
||||||
)
|
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
|
|
@ -94,70 +91,106 @@ class TimelinePresenterTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - on scroll finished send read receipt if an event is before the index`() = runTest {
|
fun `present - on scroll finished send read receipt if an event is before the index`() = runTest {
|
||||||
val timeline = FakeMatrixTimeline()
|
val timeline = FakeMatrixTimeline(
|
||||||
val timelineItemsFactory = aTimelineItemsFactory().apply {
|
initialTimelineItems = listOf(
|
||||||
replaceWith(listOf(MatrixTimelineItem.Event(0, anEventTimelineItem())))
|
MatrixTimelineItem.Event(0, anEventTimelineItem())
|
||||||
}
|
)
|
||||||
val room = FakeMatrixRoom(matrixTimeline = timeline)
|
|
||||||
val presenter = TimelinePresenter(
|
|
||||||
timelineItemsFactory = timelineItemsFactory,
|
|
||||||
room = room,
|
|
||||||
)
|
)
|
||||||
|
val presenter = createTimelinePresenter(timeline)
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
assertThat(timeline.sendReadReceiptCount).isEqualTo(0)
|
assertThat(timeline.sendReadReceiptCount).isEqualTo(0)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
|
awaitWithLatch { latch ->
|
||||||
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0))
|
timeline.sendReadReceiptLatch = latch
|
||||||
|
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0))
|
||||||
|
}
|
||||||
assertThat(timeline.sendReadReceiptCount).isEqualTo(1)
|
assertThat(timeline.sendReadReceiptCount).isEqualTo(1)
|
||||||
|
cancelAndIgnoreRemainingEvents()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - on scroll finished will not send read receipt no event is before the index`() = runTest {
|
fun `present - on scroll finished will not send read receipt no event is before the index`() = runTest {
|
||||||
val timeline = FakeMatrixTimeline()
|
val timeline = FakeMatrixTimeline(
|
||||||
val timelineItemsFactory = aTimelineItemsFactory().apply {
|
initialTimelineItems = listOf(
|
||||||
replaceWith(listOf(MatrixTimelineItem.Event(0, anEventTimelineItem())))
|
MatrixTimelineItem.Event(0, anEventTimelineItem())
|
||||||
}
|
)
|
||||||
val room = FakeMatrixRoom(matrixTimeline = timeline)
|
|
||||||
val presenter = TimelinePresenter(
|
|
||||||
timelineItemsFactory = timelineItemsFactory,
|
|
||||||
room = room,
|
|
||||||
)
|
)
|
||||||
|
val presenter = createTimelinePresenter(timeline)
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
assertThat(timeline.sendReadReceiptCount).isEqualTo(0)
|
assertThat(timeline.sendReadReceiptCount).isEqualTo(0)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
|
awaitWithLatch { latch ->
|
||||||
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(1))
|
timeline.sendReadReceiptLatch = latch
|
||||||
|
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(1))
|
||||||
|
}
|
||||||
assertThat(timeline.sendReadReceiptCount).isEqualTo(0)
|
assertThat(timeline.sendReadReceiptCount).isEqualTo(0)
|
||||||
|
cancelAndIgnoreRemainingEvents()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - on scroll finished will not send read receipt only virtual events exist before the index`() = runTest {
|
fun `present - on scroll finished will not send read receipt only virtual events exist before the index`() = runTest {
|
||||||
val timeline = FakeMatrixTimeline()
|
val timeline = FakeMatrixTimeline(
|
||||||
val timelineItemsFactory = aTimelineItemsFactory().apply {
|
initialTimelineItems = listOf(
|
||||||
replaceWith(listOf(MatrixTimelineItem.Virtual(0, VirtualTimelineItem.ReadMarker)))
|
MatrixTimelineItem.Virtual(0, VirtualTimelineItem.ReadMarker)
|
||||||
}
|
)
|
||||||
val room = FakeMatrixRoom(matrixTimeline = timeline)
|
|
||||||
val presenter = TimelinePresenter(
|
|
||||||
timelineItemsFactory = timelineItemsFactory,
|
|
||||||
room = room,
|
|
||||||
)
|
)
|
||||||
|
val presenter = createTimelinePresenter(timeline)
|
||||||
moleculeFlow(RecompositionClock.Immediate) {
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
}.test {
|
}.test {
|
||||||
assertThat(timeline.sendReadReceiptCount).isEqualTo(0)
|
assertThat(timeline.sendReadReceiptCount).isEqualTo(0)
|
||||||
val initialState = awaitItem()
|
val initialState = awaitItem()
|
||||||
|
awaitWithLatch { latch ->
|
||||||
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(1))
|
timeline.sendReadReceiptLatch = latch
|
||||||
|
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0))
|
||||||
|
}
|
||||||
assertThat(timeline.sendReadReceiptCount).isEqualTo(0)
|
assertThat(timeline.sendReadReceiptCount).isEqualTo(0)
|
||||||
|
cancelAndIgnoreRemainingEvents()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - covers hasNewItems scenarios`() = runTest {
|
||||||
|
val timeline = FakeMatrixTimeline()
|
||||||
|
val presenter = createTimelinePresenter(timeline)
|
||||||
|
moleculeFlow(RecompositionClock.Immediate) {
|
||||||
|
presenter.present()
|
||||||
|
}.test {
|
||||||
|
val initialState = awaitItem()
|
||||||
|
assertThat(initialState.hasNewItems).isFalse()
|
||||||
|
assertThat(initialState.timelineItems.size).isEqualTo(0)
|
||||||
|
timeline.updateTimelineItems {
|
||||||
|
listOf(MatrixTimelineItem.Event(0, anEventTimelineItem(content = aMessageContent())))
|
||||||
|
}
|
||||||
|
skipItems(1)
|
||||||
|
assertThat(awaitItem().timelineItems.size).isEqualTo(1)
|
||||||
|
timeline.updateTimelineItems { items ->
|
||||||
|
items + listOf(MatrixTimelineItem.Event(1, anEventTimelineItem(content = aMessageContent())))
|
||||||
|
}
|
||||||
|
skipItems(1)
|
||||||
|
assertThat(awaitItem().timelineItems.size).isEqualTo(2)
|
||||||
|
assertThat(awaitItem().hasNewItems).isTrue()
|
||||||
|
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0))
|
||||||
|
assertThat(awaitItem().hasNewItems).isFalse()
|
||||||
|
cancelAndIgnoreRemainingEvents()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun TestScope.createTimelinePresenter(
|
||||||
|
timeline: MatrixTimeline = FakeMatrixTimeline(),
|
||||||
|
timelineItemsFactory: TimelineItemsFactory = aTimelineItemsFactory()
|
||||||
|
): TimelinePresenter {
|
||||||
|
return TimelinePresenter(
|
||||||
|
timelineItemsFactory = timelineItemsFactory,
|
||||||
|
room = FakeMatrixRoom(matrixTimeline = timeline),
|
||||||
|
dispatchers = testCoroutineDispatchers(),
|
||||||
|
appScope = this
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ class TimelineItemGrouperTest {
|
||||||
localSendState = LocalEventSendState.Sent(AN_EVENT_ID),
|
localSendState = LocalEventSendState.Sent(AN_EVENT_ID),
|
||||||
inReplyTo = null,
|
inReplyTo = null,
|
||||||
debugInfo = aTimelineItemDebugInfo(),
|
debugInfo = aTimelineItemDebugInfo(),
|
||||||
|
origin = null
|
||||||
)
|
)
|
||||||
private val aNonGroupableItem = aMessageEvent()
|
private val aNonGroupableItem = aMessageEvent()
|
||||||
private val aNonGroupableItemNoEvent = TimelineItem.Virtual("virtual", aTimelineItemDaySeparatorModel("Today"))
|
private val aNonGroupableItemNoEvent = TimelineItem.Virtual("virtual", aTimelineItemDaySeparatorModel("Today"))
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,17 @@ import io.element.android.libraries.matrix.api.room.message.RoomMessage
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.MessageType
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails
|
||||||
|
import io.element.android.libraries.matrix.api.timeline.item.event.TextMessageType
|
||||||
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_ROOM_ID
|
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_ROOM_NAME
|
||||||
import io.element.android.libraries.matrix.test.A_UNIQUE_ID
|
|
||||||
import io.element.android.libraries.matrix.test.A_USER_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.A_USER_NAME
|
||||||
|
|
||||||
|
|
@ -114,6 +117,7 @@ fun anEventTimelineItem(
|
||||||
timestamp = timestamp,
|
timestamp = timestamp,
|
||||||
content = content,
|
content = content,
|
||||||
debugInfo = debugInfo,
|
debugInfo = debugInfo,
|
||||||
|
origin = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun aProfileTimelineDetails(
|
fun aProfileTimelineDetails(
|
||||||
|
|
@ -138,6 +142,21 @@ fun aProfileChangeMessageContent(
|
||||||
prevAvatarUrl = prevAvatarUrl,
|
prevAvatarUrl = prevAvatarUrl,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun aMessageContent(
|
||||||
|
body: String = "body",
|
||||||
|
inReplyTo: InReplyTo? = null,
|
||||||
|
isEdited: Boolean = false,
|
||||||
|
messageType: MessageType = TextMessageType(
|
||||||
|
body = body,
|
||||||
|
formatted = null
|
||||||
|
)
|
||||||
|
) = MessageContent(
|
||||||
|
body = body,
|
||||||
|
inReplyTo = inReplyTo,
|
||||||
|
isEdited = isEdited,
|
||||||
|
type = messageType
|
||||||
|
)
|
||||||
|
|
||||||
fun aTimelineItemDebugInfo(
|
fun aTimelineItemDebugInfo(
|
||||||
model: String = "Rust(Model())",
|
model: String = "Rust(Model())",
|
||||||
originalJson: String? = null,
|
originalJson: String? = null,
|
||||||
|
|
@ -145,3 +164,4 @@ fun aTimelineItemDebugInfo(
|
||||||
) = TimelineItemDebugInfo(
|
) = TimelineItemDebugInfo(
|
||||||
model, originalJson, latestEditedJson
|
model, originalJson, latestEditedJson
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ package io.element.android.libraries.matrix.test.timeline
|
||||||
import io.element.android.libraries.matrix.api.core.EventId
|
import io.element.android.libraries.matrix.api.core.EventId
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimeline
|
||||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||||
|
import io.element.android.tests.testutils.simulateLongTask
|
||||||
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
@ -36,6 +38,8 @@ class FakeMatrixTimeline(
|
||||||
var sendReadReceiptCount = 0
|
var sendReadReceiptCount = 0
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
var sendReadReceiptLatch: CompletableDeferred<Unit>? = null
|
||||||
|
|
||||||
fun updatePaginationState(update: (MatrixTimeline.PaginationState.() -> MatrixTimeline.PaginationState)) {
|
fun updatePaginationState(update: (MatrixTimeline.PaginationState.() -> MatrixTimeline.PaginationState)) {
|
||||||
_paginationState.getAndUpdate(update)
|
_paginationState.getAndUpdate(update)
|
||||||
}
|
}
|
||||||
|
|
@ -62,13 +66,13 @@ class FakeMatrixTimeline(
|
||||||
return Result.success(Unit)
|
return Result.success(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun fetchDetailsForEvent(eventId: EventId): Result<Unit> = simulateLongTask {
|
||||||
override suspend fun fetchDetailsForEvent(eventId: EventId): Result<Unit> {
|
Result.success(Unit)
|
||||||
return Result.success(Unit)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun sendReadReceipt(eventId: EventId): Result<Unit> {
|
override suspend fun sendReadReceipt(eventId: EventId): Result<Unit> = simulateLongTask {
|
||||||
sendReadReceiptCount++
|
sendReadReceiptCount++
|
||||||
return Result.success(Unit)
|
sendReadReceiptLatch?.complete(Unit)
|
||||||
|
Result.success(Unit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,12 @@
|
||||||
|
|
||||||
package io.element.android.tests.testutils
|
package io.element.android.tests.testutils
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CompletableDeferred
|
||||||
|
import kotlinx.coroutines.TimeoutCancellationException
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.withTimeout
|
||||||
|
import kotlin.time.Duration
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Workaround for https://github.com/cashapp/molecule/issues/249.
|
* Workaround for https://github.com/cashapp/molecule/issues/249.
|
||||||
|
|
@ -26,3 +31,18 @@ suspend inline fun <T> simulateLongTask(lambda: () -> T): T {
|
||||||
delay(1)
|
delay(1)
|
||||||
return lambda()
|
return lambda()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used for testing events in Presenter, where the event does not emit new state.
|
||||||
|
* If the (virtual) timeout is passed, we release the latch manually.
|
||||||
|
*/
|
||||||
|
suspend fun awaitWithLatch(timeout: Duration = 300.milliseconds, block: (CompletableDeferred<Unit>) -> Unit) {
|
||||||
|
val latch = CompletableDeferred<Unit>()
|
||||||
|
try {
|
||||||
|
withTimeout(timeout) {
|
||||||
|
latch.also(block).await()
|
||||||
|
}
|
||||||
|
} catch (exception: TimeoutCancellationException) {
|
||||||
|
latch.complete(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue