diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt index 3012a095e8..d5893c2c49 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt @@ -45,23 +45,35 @@ import kotlinx.collections.immutable.toPersistentList import java.util.UUID import kotlin.random.Random -fun aTimelineState(timelineItems: ImmutableList = persistentListOf()) = TimelineState( +fun aTimelineState( + timelineItems: ImmutableList = persistentListOf(), + paginationState: MatrixTimeline.PaginationState = aPaginationState(), + eventSink: (TimelineEvents) -> Unit = {}, +) = TimelineState( timelineItems = timelineItems, timelineRoomInfo = aTimelineRoomInfo(), - paginationState = MatrixTimeline.PaginationState( - isBackPaginating = false, - hasMoreToLoadBackwards = true, - beginningOfRoomReached = false, - ), + paginationState = paginationState, highlightedEventId = null, newEventState = NewEventState.None, sessionState = aSessionState( isSessionVerified = true, isKeyBackupEnabled = true, ), - eventSink = {}, + eventSink = eventSink, ) +fun aPaginationState( + isBackPaginating: Boolean = false, + hasMoreToLoadBackwards: Boolean = true, + beginningOfRoomReached: Boolean = false, +): MatrixTimeline.PaginationState { + return MatrixTimeline.PaginationState( + isBackPaginating = isBackPaginating, + hasMoreToLoadBackwards = hasMoreToLoadBackwards, + beginningOfRoomReached = beginningOfRoomReached, + ) +} + internal fun aTimelineItemList(content: TimelineItemEventContent): ImmutableList { return persistentListOf( // 3 items (First Middle Last) with isMine = false diff --git a/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt new file mode 100644 index 0000000000..f80f4ce4c2 --- /dev/null +++ b/features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/timeline/TimelineViewTest.kt @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024 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.features.messages.impl.timeline + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.element.android.tests.testutils.EnsureNeverCalledWithParam +import io.element.android.tests.testutils.EnsureNeverCalledWithTwoParams +import io.element.android.tests.testutils.EventsRecorder +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class TimelineViewTest { + @get:Rule val rule = createAndroidComposeRule() + + @Test + fun `reaching the end of the timeline with more events to load emits a LoadMore event`() { + val eventsRecorder = EventsRecorder() + rule.setContent { + TimelineView( + aTimelineState( + eventSink = eventsRecorder, + paginationState = aPaginationState( + hasMoreToLoadBackwards = true, + ) + ), + roomName = null, + onUserDataClicked = EnsureNeverCalledWithParam(), + onMessageClicked = EnsureNeverCalledWithParam(), + onMessageLongClicked = EnsureNeverCalledWithParam(), + onTimestampClicked = EnsureNeverCalledWithParam(), + onSwipeToReply = EnsureNeverCalledWithParam(), + onReactionClicked = EnsureNeverCalledWithTwoParams(), + onReactionLongClicked = EnsureNeverCalledWithTwoParams(), + onMoreReactionsClicked = EnsureNeverCalledWithParam(), + onReadReceiptClick = EnsureNeverCalledWithParam(), + ) + } + eventsRecorder.assertSingle(TimelineEvents.LoadMore) + } + + @Test + fun `reaching the end of the timeline does not send a LoadMore event`() { + val eventsRecorder = EventsRecorder(expectEvents = false) + rule.setContent { + TimelineView( + aTimelineState( + eventSink = eventsRecorder, + paginationState = aPaginationState( + hasMoreToLoadBackwards = false, + ) + ), + roomName = null, + onUserDataClicked = EnsureNeverCalledWithParam(), + onMessageClicked = EnsureNeverCalledWithParam(), + onMessageLongClicked = EnsureNeverCalledWithParam(), + onTimestampClicked = EnsureNeverCalledWithParam(), + onSwipeToReply = EnsureNeverCalledWithParam(), + onReactionClicked = EnsureNeverCalledWithTwoParams(), + onReactionLongClicked = EnsureNeverCalledWithTwoParams(), + onMoreReactionsClicked = EnsureNeverCalledWithParam(), + onReadReceiptClick = EnsureNeverCalledWithParam(), + ) + } + } +} diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt index e98c025238..870806d424 100644 --- a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/EnsureNeverCalled.kt @@ -27,3 +27,9 @@ class EnsureNeverCalledWithParam : (T) -> Unit { throw AssertionError("Should not be called and is called with $p1") } } + +class EnsureNeverCalledWithTwoParams : (T, U) -> Unit { + override fun invoke(p1: T, p2: U) { + throw AssertionError("Should not be called and is called with $p1 and $p2") + } +}