Add tests and clean code after RoomList Filter rework

This commit is contained in:
ganfra
2026-01-30 15:03:50 +01:00
parent 0824a3ab8b
commit 9641d3ef4f
27 changed files with 325 additions and 161 deletions

View File

@@ -16,6 +16,12 @@ plugins {
android {
namespace = "io.element.android.libraries.roomselect.impl"
testOptions {
unitTests {
isIncludeAndroidResources = true
}
}
}
setupDependencyInjection()
@@ -30,6 +36,6 @@ dependencies {
implementation(projects.libraries.uiStrings)
api(projects.libraries.roomselect.api)
testCommonDependencies(libs)
testCommonDependencies(libs, includeTestComposeView = true)
testImplementation(projects.libraries.matrix.test)
}

View File

@@ -16,5 +16,5 @@ sealed interface RoomSelectEvents {
// TODO remove to restore multi-selection
data object RemoveSelectedRoom : RoomSelectEvents
data object ToggleSearchActive : RoomSelectEvents
data class UpdateVisibleRange(val range: IntRange): RoomSelectEvents
data class UpdateVisibleRange(val range: IntRange) : RoomSelectEvents
}

View File

@@ -43,22 +43,23 @@ open class RoomSelectStateProvider : PreviewParameterProvider<RoomSelectState> {
)
}
private fun aRoomSelectState(
internal fun aRoomSelectState(
mode: RoomSelectMode = RoomSelectMode.Forward,
resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>> = SearchBarResultState.Initial(),
searchQuery: String = "",
isSearchActive: Boolean = false,
selectedRooms: ImmutableList<SelectRoomInfo> = persistentListOf(),
eventSink: (RoomSelectEvents) -> Unit = {},
) = RoomSelectState(
mode = mode,
resultState = resultState,
searchQuery = TextFieldState(initialText = searchQuery),
isSearchActive = isSearchActive,
selectedRooms = selectedRooms,
eventSink = {}
eventSink = eventSink,
)
private fun aRoomSelectRoomList() = persistentListOf(
internal fun aRoomSelectRoomList() = persistentListOf(
aSelectRoomInfo(
roomId = RoomId("!room1:domain"),
name = "Room with name",

View File

@@ -17,13 +17,17 @@ import io.element.android.libraries.designsystem.theme.components.SearchBarResul
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import io.element.android.libraries.matrix.test.room.aRoomSummary
import io.element.android.libraries.matrix.test.roomlist.FakeDynamicRoomList
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo
import io.element.android.libraries.roomselect.api.RoomSelectMode
import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.lambda.assert
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.testCoroutineDispatchers
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest
import org.junit.Rule
@@ -63,9 +67,12 @@ class RoomSelectPresenterTest {
@Test
fun `present - update query`() = runTest {
val roomSummary = aRoomSummary()
val roomListService = FakeRoomListService().apply {
postAllRooms(listOf(roomSummary))
}
val roomList = FakeDynamicRoomList(
summaries = MutableStateFlow(listOf(roomSummary))
)
val roomListService = FakeRoomListService(
createRoomListLambda = { roomList }
)
val presenter = createRoomSelectPresenter(
roomListService = roomListService
)
@@ -81,12 +88,12 @@ class RoomSelectPresenterTest {
skipItems(1)
initialState.searchQuery.setTextAndPlaceCursorAtEnd("string not contained")
assertThat(
roomListService.allRooms.currentFilter.value
roomList.currentFilter.value
).isEqualTo(
RoomListFilter.NormalizedMatchRoomName("string not contained")
)
assertThat(awaitItem().searchQuery.text.toString()).isEqualTo("string not contained")
roomListService.postAllRooms(
roomList.summaries.emit(
emptyList()
)
assertThat(awaitItem().resultState).isInstanceOf(SearchBarResultState.NoResultsFound::class.java)
@@ -96,9 +103,12 @@ class RoomSelectPresenterTest {
@Test
fun `present - select and remove a room`() = runTest {
val roomSummary = aRoomSummary()
val roomListService = FakeRoomListService().apply {
postAllRooms(listOf(roomSummary))
}
val roomList = FakeDynamicRoomList(
summaries = MutableStateFlow(listOf(roomSummary))
)
val roomListService = FakeRoomListService(
createRoomListLambda = { roomList }
)
val presenter = createRoomSelectPresenter(
roomListService = roomListService,
)
@@ -114,6 +124,35 @@ class RoomSelectPresenterTest {
cancel()
}
}
@Test
fun `present - UpdateVisibleRange triggers pagination when near end`() = runTest {
val loadMoreLambda = lambdaRecorder<Unit> { }
val roomList = FakeDynamicRoomList(
summaries = MutableStateFlow(listOf()),
loadMoreLambda = loadMoreLambda,
)
val roomListService = FakeRoomListService(
createRoomListLambda = { roomList }
)
val presenter = createRoomSelectPresenter(roomListService = roomListService)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
// Post some rooms to simulate loaded content
val rooms = (1..10).map { aRoomSummary() }
roomList.summaries.emit(rooms)
skipItems(1)
// UpdateVisibleRange near end should trigger loadMore
initialState.eventSink(RoomSelectEvents.UpdateVisibleRange(IntRange(0, 9)))
// Give time for the coroutine to complete
testScheduler.advanceUntilIdle()
assert(loadMoreLambda).isCalledOnce()
}
}
}
internal fun TestScope.createRoomSelectPresenter(