Add tests and clean code after RoomList Filter rework
This commit is contained in:
@@ -16,6 +16,7 @@ import io.element.android.libraries.matrix.test.A_SESSION_ID
|
|||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
||||||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||||
|
import io.element.android.libraries.matrix.test.roomlist.FakeDynamicRoomList
|
||||||
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService
|
||||||
import io.element.android.libraries.matrix.ui.room.LoadingRoomState
|
import io.element.android.libraries.matrix.ui.room.LoadingRoomState
|
||||||
import io.element.android.libraries.matrix.ui.room.LoadingRoomStateFlowFactory
|
import io.element.android.libraries.matrix.ui.room.LoadingRoomStateFlowFactory
|
||||||
@@ -54,7 +55,8 @@ class LoadingBaseRoomStateFlowFactoryTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `flow should emit Loading and then Loaded when there is a room in cache after SS is loaded`() = runTest {
|
fun `flow should emit Loading and then Loaded when there is a room in cache after SS is loaded`() = runTest {
|
||||||
val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(sessionId = A_SESSION_ID, roomId = A_ROOM_ID))
|
val room = FakeJoinedRoom(baseRoom = FakeBaseRoom(sessionId = A_SESSION_ID, roomId = A_ROOM_ID))
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList()
|
||||||
|
val roomListService = FakeRoomListService(allRooms = roomList)
|
||||||
val matrixClient = FakeMatrixClient(A_SESSION_ID, roomListService = roomListService)
|
val matrixClient = FakeMatrixClient(A_SESSION_ID, roomListService = roomListService)
|
||||||
val flowFactory = LoadingRoomStateFlowFactory(matrixClient)
|
val flowFactory = LoadingRoomStateFlowFactory(matrixClient)
|
||||||
flowFactory
|
flowFactory
|
||||||
@@ -62,21 +64,22 @@ class LoadingBaseRoomStateFlowFactoryTest {
|
|||||||
.test {
|
.test {
|
||||||
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
|
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
|
||||||
matrixClient.givenGetRoomResult(A_ROOM_ID, room)
|
matrixClient.givenGetRoomResult(A_ROOM_ID, room)
|
||||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
roomList.loadingState.emit(RoomList.LoadingState.Loaded(1))
|
||||||
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loaded(room))
|
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loaded(room))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `flow should emit Loading and then Error when there is no room in cache after SS is loaded`() = runTest {
|
fun `flow should emit Loading and then Error when there is no room in cache after SS is loaded`() = runTest {
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList()
|
||||||
|
val roomListService = FakeRoomListService(allRooms = roomList)
|
||||||
val matrixClient = FakeMatrixClient(A_SESSION_ID, roomListService = roomListService)
|
val matrixClient = FakeMatrixClient(A_SESSION_ID, roomListService = roomListService)
|
||||||
val flowFactory = LoadingRoomStateFlowFactory(matrixClient)
|
val flowFactory = LoadingRoomStateFlowFactory(matrixClient)
|
||||||
flowFactory
|
flowFactory
|
||||||
.create(lifecycleScope = this, roomId = A_ROOM_ID, joinedRoom = null)
|
.create(lifecycleScope = this, roomId = A_ROOM_ID, joinedRoom = null)
|
||||||
.test {
|
.test {
|
||||||
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
|
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Loading)
|
||||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
roomList.loadingState.emit(RoomList.LoadingState.Loaded(1))
|
||||||
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Error)
|
assertThat(awaitItem()).isEqualTo(LoadingRoomState.Error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ import androidx.compose.foundation.lazy.LazyListState
|
|||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.rememberUpdatedState
|
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ import io.element.android.features.home.impl.filters.selection.FilterSelectionSt
|
|||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.debounce
|
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter as MatrixRoomListFilter
|
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter as MatrixRoomListFilter
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
|||||||
@@ -317,6 +317,4 @@ class RoomListPresenter(
|
|||||||
room.clearEventCacheStorage()
|
room.clearEventCacheStorage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,5 +66,4 @@ class RoomListSearchDataSource(
|
|||||||
}
|
}
|
||||||
roomList.updateFilter(filter)
|
roomList.updateFilter(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ import io.element.android.libraries.dateformatter.test.FakeDateFormatter
|
|||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
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.test.roomlist.FakeRoomListService
|
||||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -27,9 +29,13 @@ import java.time.Instant
|
|||||||
class RoomListDataSourceTest {
|
class RoomListDataSourceTest {
|
||||||
@Test
|
@Test
|
||||||
fun `when DateTimeObserver gets a date change, the room summaries are refreshed`() = runTest {
|
fun `when DateTimeObserver gets a date change, the room summaries are refreshed`() = runTest {
|
||||||
val roomListService = FakeRoomListService().apply {
|
val roomList = FakeDynamicRoomList().apply {
|
||||||
|
summaries.emit(listOf(aRoomSummary()))
|
||||||
|
}
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
).apply {
|
||||||
postState(RoomListService.State.Running)
|
postState(RoomListService.State.Running)
|
||||||
postAllRooms(listOf(aRoomSummary()))
|
|
||||||
}
|
}
|
||||||
val dateTimeObserver = FakeDateTimeObserver()
|
val dateTimeObserver = FakeDateTimeObserver()
|
||||||
var dateFormatterResult = "Today"
|
var dateFormatterResult = "Today"
|
||||||
@@ -61,9 +67,11 @@ class RoomListDataSourceTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when DateTimeObserver gets a time zone change, the room summaries are refreshed`() = runTest {
|
fun `when DateTimeObserver gets a time zone change, the room summaries are refreshed`() = runTest {
|
||||||
val roomListService = FakeRoomListService().apply {
|
val roomList = FakeDynamicRoomList(summaries = MutableStateFlow(listOf(aRoomSummary())))
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
).apply {
|
||||||
postState(RoomListService.State.Running)
|
postState(RoomListService.State.Running)
|
||||||
postAllRooms(listOf(aRoomSummary()))
|
|
||||||
}
|
}
|
||||||
val dateTimeObserver = FakeDateTimeObserver()
|
val dateTimeObserver = FakeDateTimeObserver()
|
||||||
var dateFormatterResult = "Today"
|
var dateFormatterResult = "Today"
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import kotlinx.coroutines.test.TestScope
|
|||||||
import kotlinx.coroutines.test.advanceUntilIdle
|
import kotlinx.coroutines.test.advanceUntilIdle
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter as MatrixRoomListFilter
|
|
||||||
|
|
||||||
class RoomListFiltersPresenterTest {
|
class RoomListFiltersPresenterTest {
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
|||||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
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.test.roomlist.FakeRoomListService
|
||||||
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||||
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
import io.element.android.libraries.matrix.test.verification.FakeSessionVerificationService
|
||||||
@@ -77,6 +78,7 @@ import io.element.android.tests.testutils.lambda.value
|
|||||||
import io.element.android.tests.testutils.test
|
import io.element.android.tests.testutils.test
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.advanceTimeBy
|
import kotlinx.coroutines.test.advanceTimeBy
|
||||||
@@ -91,7 +93,10 @@ class RoomListPresenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - load 1 room with success`() = runTest {
|
fun `present - load 1 room with success`() = runTest {
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList()
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val matrixClient = FakeMatrixClient(
|
val matrixClient = FakeMatrixClient(
|
||||||
roomListService = roomListService
|
roomListService = roomListService
|
||||||
)
|
)
|
||||||
@@ -102,8 +107,8 @@ class RoomListPresenterTest {
|
|||||||
presenter.test {
|
presenter.test {
|
||||||
val initialState = consumeItemsUntilPredicate { state -> state.contentState is RoomListContentState.Skeleton }.last()
|
val initialState = consumeItemsUntilPredicate { state -> state.contentState is RoomListContentState.Skeleton }.last()
|
||||||
assertThat(initialState.contentState).isInstanceOf(RoomListContentState.Skeleton::class.java)
|
assertThat(initialState.contentState).isInstanceOf(RoomListContentState.Skeleton::class.java)
|
||||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
roomList.loadingState.emit(RoomList.LoadingState.Loaded(1))
|
||||||
roomListService.postAllRooms(
|
roomList.summaries.emit(
|
||||||
listOf(
|
listOf(
|
||||||
aRoomSummary(
|
aRoomSummary(
|
||||||
numUnreadMentions = 1,
|
numUnreadMentions = 1,
|
||||||
@@ -128,9 +133,12 @@ class RoomListPresenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - handle DismissRequestVerificationPrompt`() = runTest {
|
fun `present - handle DismissRequestVerificationPrompt`() = runTest {
|
||||||
val roomListService = FakeRoomListService().apply {
|
val roomList = FakeDynamicRoomList(
|
||||||
postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
loadingState = MutableStateFlow(RoomList.LoadingState.Loaded(1))
|
||||||
}
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val encryptionService = FakeEncryptionService().apply {
|
val encryptionService = FakeEncryptionService().apply {
|
||||||
emitRecoveryState(RecoveryState.INCOMPLETE)
|
emitRecoveryState(RecoveryState.INCOMPLETE)
|
||||||
}
|
}
|
||||||
@@ -154,9 +162,12 @@ class RoomListPresenterTest {
|
|||||||
val encryptionService = FakeEncryptionService().apply {
|
val encryptionService = FakeEncryptionService().apply {
|
||||||
recoveryStateStateFlow.emit(RecoveryState.DISABLED)
|
recoveryStateStateFlow.emit(RecoveryState.DISABLED)
|
||||||
}
|
}
|
||||||
val roomListService = FakeRoomListService().apply {
|
val roomList = FakeDynamicRoomList(
|
||||||
postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
loadingState = MutableStateFlow(RoomList.LoadingState.Loaded(1))
|
||||||
}
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val matrixClient = FakeMatrixClient(
|
val matrixClient = FakeMatrixClient(
|
||||||
roomListService = roomListService,
|
roomListService = roomListService,
|
||||||
encryptionService = encryptionService,
|
encryptionService = encryptionService,
|
||||||
@@ -344,9 +355,13 @@ class RoomListPresenterTest {
|
|||||||
fun `present - change in notification settings updates the summary for decorations`() = runTest {
|
fun `present - change in notification settings updates the summary for decorations`() = runTest {
|
||||||
val userDefinedMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
val userDefinedMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
|
||||||
val notificationSettingsService = FakeNotificationSettingsService()
|
val notificationSettingsService = FakeNotificationSettingsService()
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList(
|
||||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
summaries = MutableStateFlow(listOf(aRoomSummary(userDefinedNotificationMode = userDefinedMode))),
|
||||||
roomListService.postAllRooms(listOf(aRoomSummary(userDefinedNotificationMode = userDefinedMode)))
|
loadingState = MutableStateFlow(RoomList.LoadingState.Loaded(1))
|
||||||
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val matrixClient = FakeMatrixClient(
|
val matrixClient = FakeMatrixClient(
|
||||||
roomListService = roomListService,
|
roomListService = roomListService,
|
||||||
notificationSettingsService = notificationSettingsService
|
notificationSettingsService = notificationSettingsService
|
||||||
@@ -397,8 +412,12 @@ class RoomListPresenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - when room service returns no room, then contentState is Empty`() = runTest {
|
fun `present - when room service returns no room, then contentState is Empty`() = runTest {
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList(
|
||||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(0))
|
loadingState = MutableStateFlow(RoomList.LoadingState.Loaded(0))
|
||||||
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val matrixClient = FakeMatrixClient(
|
val matrixClient = FakeMatrixClient(
|
||||||
roomListService = roomListService,
|
roomListService = roomListService,
|
||||||
)
|
)
|
||||||
@@ -479,16 +498,21 @@ class RoomListPresenterTest {
|
|||||||
val acceptDeclinePresenter = Presenter {
|
val acceptDeclinePresenter = Presenter {
|
||||||
anAcceptDeclineInviteState(eventSink = eventSinkRecorder)
|
anAcceptDeclineInviteState(eventSink = eventSinkRecorder)
|
||||||
}
|
}
|
||||||
val roomListService = FakeRoomListService()
|
|
||||||
val matrixClient = FakeMatrixClient(
|
|
||||||
roomListService = roomListService,
|
|
||||||
)
|
|
||||||
val roomSummary = aRoomSummary(
|
val roomSummary = aRoomSummary(
|
||||||
currentUserMembership = CurrentUserMembership.INVITED,
|
currentUserMembership = CurrentUserMembership.INVITED,
|
||||||
inviter = aRoomMember(),
|
inviter = aRoomMember(),
|
||||||
)
|
)
|
||||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
val roomList = FakeDynamicRoomList(
|
||||||
roomListService.postAllRooms(listOf(roomSummary))
|
summaries = MutableStateFlow(listOf(roomSummary)),
|
||||||
|
loadingState = MutableStateFlow(RoomList.LoadingState.Loaded(1))
|
||||||
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
|
val matrixClient = FakeMatrixClient(
|
||||||
|
roomListService = roomListService,
|
||||||
|
)
|
||||||
val presenter = createRoomListPresenter(
|
val presenter = createRoomListPresenter(
|
||||||
client = matrixClient,
|
client = matrixClient,
|
||||||
acceptDeclineInvitePresenter = acceptDeclinePresenter
|
acceptDeclineInvitePresenter = acceptDeclinePresenter
|
||||||
@@ -519,15 +543,20 @@ class RoomListPresenterTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `present - UpdateVisibleRange will cancel the previous subscription if called too soon`() = runTest {
|
fun `present - UpdateVisibleRange will cancel the previous subscription if called too soon`() = runTest {
|
||||||
val subscribeToVisibleRoomsLambda = lambdaRecorder { _: List<RoomId> -> }
|
val subscribeToVisibleRoomsLambda = lambdaRecorder { _: List<RoomId> -> }
|
||||||
val roomListService = FakeRoomListService(subscribeToVisibleRoomsLambda = subscribeToVisibleRoomsLambda)
|
|
||||||
val matrixClient = FakeMatrixClient(
|
|
||||||
roomListService = roomListService,
|
|
||||||
)
|
|
||||||
val roomSummary = aRoomSummary(
|
val roomSummary = aRoomSummary(
|
||||||
currentUserMembership = CurrentUserMembership.INVITED
|
currentUserMembership = CurrentUserMembership.INVITED
|
||||||
)
|
)
|
||||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
val roomList = FakeDynamicRoomList(
|
||||||
roomListService.postAllRooms(listOf(roomSummary))
|
summaries = MutableStateFlow(listOf(roomSummary)),
|
||||||
|
loadingState = MutableStateFlow(RoomList.LoadingState.Loaded(1))
|
||||||
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList },
|
||||||
|
subscribeToVisibleRoomsLambda = subscribeToVisibleRoomsLambda,
|
||||||
|
)
|
||||||
|
val matrixClient = FakeMatrixClient(
|
||||||
|
roomListService = roomListService,
|
||||||
|
)
|
||||||
val presenter = createRoomListPresenter(
|
val presenter = createRoomListPresenter(
|
||||||
client = matrixClient,
|
client = matrixClient,
|
||||||
)
|
)
|
||||||
@@ -548,15 +577,20 @@ class RoomListPresenterTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `present - UpdateVisibleRange subscribes to rooms in visible range`() = runTest {
|
fun `present - UpdateVisibleRange subscribes to rooms in visible range`() = runTest {
|
||||||
val subscribeToVisibleRoomsLambda = lambdaRecorder { _: List<RoomId> -> }
|
val subscribeToVisibleRoomsLambda = lambdaRecorder { _: List<RoomId> -> }
|
||||||
val roomListService = FakeRoomListService(subscribeToVisibleRoomsLambda = subscribeToVisibleRoomsLambda)
|
|
||||||
val matrixClient = FakeMatrixClient(
|
|
||||||
roomListService = roomListService,
|
|
||||||
)
|
|
||||||
val roomSummary = aRoomSummary(
|
val roomSummary = aRoomSummary(
|
||||||
currentUserMembership = CurrentUserMembership.INVITED
|
currentUserMembership = CurrentUserMembership.INVITED
|
||||||
)
|
)
|
||||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
val roomList = FakeDynamicRoomList(
|
||||||
roomListService.postAllRooms(listOf(roomSummary))
|
summaries = MutableStateFlow(listOf(roomSummary)),
|
||||||
|
loadingState = MutableStateFlow(RoomList.LoadingState.Loaded(1))
|
||||||
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList },
|
||||||
|
subscribeToVisibleRoomsLambda = subscribeToVisibleRoomsLambda,
|
||||||
|
)
|
||||||
|
val matrixClient = FakeMatrixClient(
|
||||||
|
roomListService = roomListService,
|
||||||
|
)
|
||||||
val presenter = createRoomListPresenter(
|
val presenter = createRoomListPresenter(
|
||||||
client = matrixClient,
|
client = matrixClient,
|
||||||
)
|
)
|
||||||
@@ -579,15 +613,20 @@ class RoomListPresenterTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `present - notification sound banner`() = runTest {
|
fun `present - notification sound banner`() = runTest {
|
||||||
val subscribeToVisibleRoomsLambda = lambdaRecorder { _: List<RoomId> -> }
|
val subscribeToVisibleRoomsLambda = lambdaRecorder { _: List<RoomId> -> }
|
||||||
val roomListService = FakeRoomListService(subscribeToVisibleRoomsLambda = subscribeToVisibleRoomsLambda)
|
|
||||||
val matrixClient = FakeMatrixClient(
|
|
||||||
roomListService = roomListService,
|
|
||||||
)
|
|
||||||
val roomSummary = aRoomSummary(
|
val roomSummary = aRoomSummary(
|
||||||
currentUserMembership = CurrentUserMembership.INVITED
|
currentUserMembership = CurrentUserMembership.INVITED
|
||||||
)
|
)
|
||||||
roomListService.postAllRoomsLoadingState(RoomList.LoadingState.Loaded(1))
|
val roomList = FakeDynamicRoomList(
|
||||||
roomListService.postAllRooms(listOf(roomSummary))
|
summaries = MutableStateFlow(listOf(roomSummary)),
|
||||||
|
loadingState = MutableStateFlow(RoomList.LoadingState.Loaded(1))
|
||||||
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList },
|
||||||
|
subscribeToVisibleRoomsLambda = subscribeToVisibleRoomsLambda,
|
||||||
|
)
|
||||||
|
val matrixClient = FakeMatrixClient(
|
||||||
|
roomListService = roomListService,
|
||||||
|
)
|
||||||
val onAnnouncementDismissedResult = lambdaRecorder<Announcement, Unit> { }
|
val onAnnouncementDismissedResult = lambdaRecorder<Announcement, Unit> { }
|
||||||
val announcementService = FakeAnnouncementService(
|
val announcementService = FakeAnnouncementService(
|
||||||
onAnnouncementDismissedResult = onAnnouncementDismissedResult,
|
onAnnouncementDismissedResult = onAnnouncementDismissedResult,
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ import io.element.android.libraries.eventformatter.test.FakeRoomLatestEventForma
|
|||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
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.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.test.roomlist.FakeRoomListService
|
||||||
|
import io.element.android.tests.testutils.lambda.assert
|
||||||
|
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||||
import io.element.android.tests.testutils.test
|
import io.element.android.tests.testutils.test
|
||||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -56,12 +59,15 @@ class RoomListSearchPresenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - query search changes`() = runTest {
|
fun `present - query search changes`() = runTest {
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList()
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val presenter = createRoomListSearchPresenter(roomListService)
|
val presenter = createRoomListSearchPresenter(roomListService)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
awaitItem().let { state ->
|
awaitItem().let { state ->
|
||||||
assertThat(
|
assertThat(
|
||||||
roomListService.allRooms.currentFilter.value
|
roomList.currentFilter.value
|
||||||
).isEqualTo(
|
).isEqualTo(
|
||||||
RoomListFilter.None
|
RoomListFilter.None
|
||||||
)
|
)
|
||||||
@@ -70,7 +76,7 @@ class RoomListSearchPresenterTest {
|
|||||||
awaitItem().let { state ->
|
awaitItem().let { state ->
|
||||||
assertThat(state.query.text).isEqualTo("Search")
|
assertThat(state.query.text).isEqualTo("Search")
|
||||||
assertThat(
|
assertThat(
|
||||||
roomListService.allRooms.currentFilter.value
|
roomList.currentFilter.value
|
||||||
).isEqualTo(
|
).isEqualTo(
|
||||||
RoomListFilter.NormalizedMatchRoomName("Search")
|
RoomListFilter.NormalizedMatchRoomName("Search")
|
||||||
)
|
)
|
||||||
@@ -79,7 +85,7 @@ class RoomListSearchPresenterTest {
|
|||||||
awaitItem().let { state ->
|
awaitItem().let { state ->
|
||||||
assertThat(state.query.text.toString()).isEmpty()
|
assertThat(state.query.text.toString()).isEmpty()
|
||||||
assertThat(
|
assertThat(
|
||||||
roomListService.allRooms.currentFilter.value
|
roomList.currentFilter.value
|
||||||
).isEqualTo(
|
).isEqualTo(
|
||||||
RoomListFilter.None
|
RoomListFilter.None
|
||||||
)
|
)
|
||||||
@@ -89,24 +95,51 @@ class RoomListSearchPresenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - room list changes`() = runTest {
|
fun `present - room list changes`() = runTest {
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList()
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val presenter = createRoomListSearchPresenter(roomListService)
|
val presenter = createRoomListSearchPresenter(roomListService)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
awaitItem().let { state ->
|
awaitItem().let { state ->
|
||||||
assertThat(state.results).isEmpty()
|
assertThat(state.results).isEmpty()
|
||||||
}
|
}
|
||||||
roomListService.postAllRooms(
|
roomList.summaries.emit(
|
||||||
listOf(aRoomSummary())
|
listOf(aRoomSummary())
|
||||||
)
|
)
|
||||||
awaitItem().let { state ->
|
awaitItem().let { state ->
|
||||||
assertThat(state.results).hasSize(1)
|
assertThat(state.results).hasSize(1)
|
||||||
}
|
}
|
||||||
roomListService.postAllRooms(emptyList())
|
roomList.summaries.emit(emptyList())
|
||||||
awaitItem().let { state ->
|
awaitItem().let { state ->
|
||||||
assertThat(state.results).isEmpty()
|
assertThat(state.results).isEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - UpdateVisibleRange triggers pagination when near end`() = runTest {
|
||||||
|
val loadMoreLambda = lambdaRecorder<Unit> { }
|
||||||
|
val roomList = FakeDynamicRoomList(loadMoreLambda = loadMoreLambda)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
|
val presenter = createRoomListSearchPresenter(roomListService)
|
||||||
|
presenter.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(RoomListSearchEvent.UpdateVisibleRange(IntRange(0, 9)))
|
||||||
|
// Give time for the coroutine to complete
|
||||||
|
testScheduler.advanceUntilIdle()
|
||||||
|
|
||||||
|
assert(loadMoreLambda).isCalledOnce()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TestScope.createRoomListSearchPresenter(
|
fun TestScope.createRoomListSearchPresenter(
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import io.element.android.features.messages.impl.messagecomposer.suggestions.Roo
|
|||||||
import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
|
import io.element.android.libraries.matrix.test.A_ROOM_ALIAS
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
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.test.roomlist.FakeRoomListService
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -22,7 +23,10 @@ import org.junit.Test
|
|||||||
class DefaultRoomAliasSuggestionsDataSourceTest {
|
class DefaultRoomAliasSuggestionsDataSourceTest {
|
||||||
@Test
|
@Test
|
||||||
fun `getAllRoomAliasSuggestions must emit a list of room alias suggestions`() = runTest {
|
fun `getAllRoomAliasSuggestions must emit a list of room alias suggestions`() = runTest {
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList()
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val sut = DefaultRoomAliasSuggestionsDataSource(
|
val sut = DefaultRoomAliasSuggestionsDataSource(
|
||||||
roomListService
|
roomListService
|
||||||
)
|
)
|
||||||
@@ -31,7 +35,7 @@ class DefaultRoomAliasSuggestionsDataSourceTest {
|
|||||||
)
|
)
|
||||||
sut.getAllRoomAliasSuggestions().test {
|
sut.getAllRoomAliasSuggestions().test {
|
||||||
assertThat(awaitItem()).isEmpty()
|
assertThat(awaitItem()).isEmpty()
|
||||||
roomListService.postAllRooms(
|
roomList.summaries.emit(
|
||||||
listOf(
|
listOf(
|
||||||
aRoomSummary(roomId = A_ROOM_ID_2, canonicalAlias = null),
|
aRoomSummary(roomId = A_ROOM_ID_2, canonicalAlias = null),
|
||||||
aRoomSummaryWithAnAlias,
|
aRoomSummaryWithAnAlias,
|
||||||
|
|||||||
@@ -17,10 +17,12 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
|||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
||||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
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.test.roomlist.FakeRoomListService
|
||||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||||
import io.element.android.tests.testutils.test
|
import io.element.android.tests.testutils.test
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
@@ -53,10 +55,14 @@ class EditDefaultNotificationSettingsPresenterTest {
|
|||||||
initialRoomModeIsDefault = false,
|
initialRoomModeIsDefault = false,
|
||||||
getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID)) },
|
getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID)) },
|
||||||
)
|
)
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList(
|
||||||
|
summaries = MutableStateFlow(listOf(aRoomSummary(userDefinedNotificationMode = RoomNotificationMode.ALL_MESSAGES)))
|
||||||
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService)
|
val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
roomListService.postAllRooms(listOf(aRoomSummary(userDefinedNotificationMode = RoomNotificationMode.ALL_MESSAGES)))
|
|
||||||
val loadedState = consumeItemsUntilPredicate { state ->
|
val loadedState = consumeItemsUntilPredicate { state ->
|
||||||
state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.ALL_MESSAGES }
|
state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.ALL_MESSAGES }
|
||||||
}.last()
|
}.last()
|
||||||
@@ -71,10 +77,8 @@ class EditDefaultNotificationSettingsPresenterTest {
|
|||||||
initialRoomModeIsDefault = false,
|
initialRoomModeIsDefault = false,
|
||||||
getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID, A_ROOM_ID_2)) },
|
getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID, A_ROOM_ID_2)) },
|
||||||
)
|
)
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList(
|
||||||
val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService)
|
summaries = MutableStateFlow(
|
||||||
presenter.test {
|
|
||||||
roomListService.postAllRooms(
|
|
||||||
listOf(
|
listOf(
|
||||||
aRoomSummary(
|
aRoomSummary(
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
@@ -86,8 +90,14 @@ class EditDefaultNotificationSettingsPresenterTest {
|
|||||||
name = "A",
|
name = "A",
|
||||||
userDefinedNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
|
userDefinedNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
|
val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService)
|
||||||
|
presenter.test {
|
||||||
val loadedState = consumeItemsUntilPredicate { state ->
|
val loadedState = consumeItemsUntilPredicate { state ->
|
||||||
state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY }
|
state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY }
|
||||||
}.last()
|
}.last()
|
||||||
@@ -103,10 +113,8 @@ class EditDefaultNotificationSettingsPresenterTest {
|
|||||||
initialRoomModeIsDefault = false,
|
initialRoomModeIsDefault = false,
|
||||||
getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID, A_ROOM_ID_2)) },
|
getRoomsWithUserDefinedRulesResult = { Result.success(listOf(A_ROOM_ID, A_ROOM_ID_2)) },
|
||||||
)
|
)
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList(
|
||||||
val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService)
|
summaries = MutableStateFlow(
|
||||||
presenter.test {
|
|
||||||
roomListService.postAllRooms(
|
|
||||||
listOf(
|
listOf(
|
||||||
aRoomSummary(
|
aRoomSummary(
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
@@ -118,8 +126,14 @@ class EditDefaultNotificationSettingsPresenterTest {
|
|||||||
name = null,
|
name = null,
|
||||||
userDefinedNotificationMode = RoomNotificationMode.MUTE,
|
userDefinedNotificationMode = RoomNotificationMode.MUTE,
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
|
val presenter = createEditDefaultNotificationSettingPresenter(notificationSettingsService, roomListService)
|
||||||
|
presenter.test {
|
||||||
val loadedState = consumeItemsUntilPredicate { state ->
|
val loadedState = consumeItemsUntilPredicate { state ->
|
||||||
state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.MUTE }
|
state.roomsWithUserDefinedMode.any { it.notificationMode == RoomNotificationMode.MUTE }
|
||||||
}.last()
|
}.last()
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import io.element.android.libraries.matrix.test.A_ROOM_ID
|
|||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.room.aRoomSummary
|
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.test.roomlist.FakeRoomListService
|
||||||
import io.element.android.libraries.matrix.test.spaces.FakeSpaceRoomList
|
import io.element.android.libraries.matrix.test.spaces.FakeSpaceRoomList
|
||||||
import io.element.android.libraries.matrix.test.spaces.FakeSpaceService
|
import io.element.android.libraries.matrix.test.spaces.FakeSpaceService
|
||||||
@@ -116,12 +117,15 @@ class AddRoomToSpacePresenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - searchResults shows Results when rooms available`() = runTest {
|
fun `present - searchResults shows Results when rooms available`() = runTest {
|
||||||
val roomListService = FakeRoomListService()
|
val roomList = FakeDynamicRoomList()
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val presenter = createAddRoomToSpacePresenter(roomListService = roomListService)
|
val presenter = createAddRoomToSpacePresenter(roomListService = roomListService)
|
||||||
presenter.test {
|
presenter.test {
|
||||||
awaitItem() // Initial state
|
awaitItem() // Initial state
|
||||||
// Post rooms to the service
|
// Post rooms to the service
|
||||||
roomListService.postAllRooms(
|
roomList.summaries.emit(
|
||||||
listOf(
|
listOf(
|
||||||
aRoomSummary(
|
aRoomSummary(
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
@@ -296,6 +300,29 @@ class AddRoomToSpacePresenterTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `present - UpdateSearchVisibleRange triggers pagination when near end`() = runTest {
|
||||||
|
val loadMoreLambda = lambdaRecorder<Unit> { }
|
||||||
|
val roomList = FakeDynamicRoomList(loadMoreLambda = loadMoreLambda)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
|
val presenter = createAddRoomToSpacePresenter(roomListService = roomListService)
|
||||||
|
presenter.test {
|
||||||
|
val state = awaitItem()
|
||||||
|
// Post rooms to simulate loaded content
|
||||||
|
roomList.summaries.emit(listOf(aRoomSummary()))
|
||||||
|
advanceUntilIdle()
|
||||||
|
skipItems(1)
|
||||||
|
|
||||||
|
// UpdateSearchVisibleRange should trigger loadMore
|
||||||
|
state.eventSink(AddRoomToSpaceEvent.UpdateSearchVisibleRange(IntRange(0, 9)))
|
||||||
|
advanceUntilIdle()
|
||||||
|
|
||||||
|
assert(loadMoreLambda).isCalledOnce()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `present - Dismiss after partial success calls reset`() = runTest {
|
fun `present - Dismiss after partial success calls reset`() = runTest {
|
||||||
val resetResult = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
val resetResult = lambdaRecorder<Result<Unit>> { Result.success(Unit) }
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import androidx.compose.ui.test.onNodeWithText
|
|||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.SearchBarResultState
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalled
|
import io.element.android.tests.testutils.EnsureNeverCalled
|
||||||
import io.element.android.tests.testutils.EventsRecorder
|
import io.element.android.tests.testutils.EventsRecorder
|
||||||
@@ -99,6 +100,21 @@ class AddRoomToSpaceViewTest {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Config(qualifiers = "h1024dp")
|
||||||
|
@Test
|
||||||
|
fun `displaying search results sends UpdateSearchVisibleRange event`() {
|
||||||
|
val eventsRecorder = EventsRecorder<AddRoomToSpaceEvent>()
|
||||||
|
val rooms = aSelectRoomInfoList()
|
||||||
|
rule.setAddRoomToSpaceView(
|
||||||
|
anAddRoomToSpaceState(
|
||||||
|
isSearchActive = true,
|
||||||
|
searchResults = SearchBarResultState.Results(rooms),
|
||||||
|
eventSink = eventsRecorder,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
eventsRecorder.assertTrue(0) { it is AddRoomToSpaceEvent.UpdateSearchVisibleRange }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setAddRoomToSpaceView(
|
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setAddRoomToSpaceView(
|
||||||
|
|||||||
@@ -12,17 +12,11 @@ import androidx.compose.foundation.gestures.Orientation
|
|||||||
import androidx.compose.foundation.lazy.LazyListLayoutInfo
|
import androidx.compose.foundation.lazy.LazyListLayoutInfo
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.derivedStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberUpdatedState
|
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.runtime.snapshotFlow
|
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
|
||||||
import kotlinx.coroutines.flow.map
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the lazy list is currently scrolling up.
|
* Returns whether the lazy list is currently scrolling up.
|
||||||
@@ -79,20 +73,3 @@ suspend fun LazyListState.animateScrollToItemCenter(index: Int) {
|
|||||||
animateScrollToItem(index, offset)
|
animateScrollToItem(index, offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun OnVisibleRangeChangeEffect(lazyListState: LazyListState, onChange: (IntRange) -> Unit) {
|
|
||||||
val onChangeUpdated by rememberUpdatedState(onChange)
|
|
||||||
LaunchedEffect(lazyListState) {
|
|
||||||
snapshotFlow { lazyListState.layoutInfo.visibleItemsInfo }
|
|
||||||
.map { visibleItemsInfo ->
|
|
||||||
val firstItemIndex = visibleItemsInfo.firstOrNull()?.index ?: 0
|
|
||||||
val size = visibleItemsInfo.size
|
|
||||||
firstItemIndex until firstItemIndex + size
|
|
||||||
}
|
|
||||||
.distinctUntilChanged()
|
|
||||||
.collectLatest { visibleRange ->
|
|
||||||
onChangeUpdated(visibleRange)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026 Element Creations Ltd.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||||
|
* Please see LICENSE files in the repository root for full details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.designsystem.utils
|
||||||
|
|
||||||
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.rememberUpdatedState
|
||||||
|
import androidx.compose.runtime.snapshotFlow
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun OnVisibleRangeChangeEffect(lazyListState: LazyListState, onChange: (IntRange) -> Unit) {
|
||||||
|
val onChangeUpdated by rememberUpdatedState(onChange)
|
||||||
|
LaunchedEffect(lazyListState) {
|
||||||
|
snapshotFlow { lazyListState.layoutInfo.visibleItemsInfo }
|
||||||
|
.map { visibleItemsInfo ->
|
||||||
|
val firstItemIndex = visibleItemsInfo.firstOrNull()?.index ?: 0
|
||||||
|
val size = visibleItemsInfo.size
|
||||||
|
firstItemIndex until firstItemIndex + size
|
||||||
|
}
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.collectLatest { visibleRange ->
|
||||||
|
onChangeUpdated(visibleRange)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,8 +8,6 @@
|
|||||||
|
|
||||||
package io.element.android.libraries.matrix.api.roomlist
|
package io.element.android.libraries.matrix.api.roomlist
|
||||||
|
|
||||||
import timber.log.Timber
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RoomList with dynamic filtering and loading.
|
* RoomList with dynamic filtering and loading.
|
||||||
* This is useful for large lists of rooms.
|
* This is useful for large lists of rooms.
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import kotlin.time.Duration
|
|||||||
* Can be retrieved from [RoomListService] methods.
|
* Can be retrieved from [RoomListService] methods.
|
||||||
*/
|
*/
|
||||||
interface RoomList {
|
interface RoomList {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The loading state of the room list.
|
* The loading state of the room list.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,13 +18,11 @@ import kotlinx.coroutines.flow.Flow
|
|||||||
import kotlinx.coroutines.flow.buffer
|
import kotlinx.coroutines.flow.buffer
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import kotlinx.coroutines.flow.catch
|
import kotlinx.coroutines.flow.catch
|
||||||
import kotlinx.coroutines.flow.launchIn
|
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import org.matrix.rustcomponents.sdk.Room
|
import org.matrix.rustcomponents.sdk.Room
|
||||||
import org.matrix.rustcomponents.sdk.RoomListDynamicEntriesController
|
import org.matrix.rustcomponents.sdk.RoomListDynamicEntriesController
|
||||||
|
import org.matrix.rustcomponents.sdk.RoomListEntriesDynamicFilterKind
|
||||||
import org.matrix.rustcomponents.sdk.RoomListEntriesListener
|
import org.matrix.rustcomponents.sdk.RoomListEntriesListener
|
||||||
import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate
|
import org.matrix.rustcomponents.sdk.RoomListEntriesUpdate
|
||||||
import org.matrix.rustcomponents.sdk.RoomListEntriesDynamicFilterKind
|
|
||||||
import org.matrix.rustcomponents.sdk.RoomListInterface
|
import org.matrix.rustcomponents.sdk.RoomListInterface
|
||||||
import org.matrix.rustcomponents.sdk.RoomListLoadingState
|
import org.matrix.rustcomponents.sdk.RoomListLoadingState
|
||||||
import org.matrix.rustcomponents.sdk.RoomListLoadingStateListener
|
import org.matrix.rustcomponents.sdk.RoomListLoadingStateListener
|
||||||
|
|||||||
@@ -90,8 +90,6 @@ internal class RoomListFactory(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private fun RoomListLoadingState.toLoadingState(): RoomList.LoadingState {
|
private fun RoomListLoadingState.toLoadingState(): RoomList.LoadingState {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is RoomListLoadingState.Loaded -> RoomList.LoadingState.Loaded(maximumNumberOfRooms?.toInt() ?: 0)
|
is RoomListLoadingState.Loaded -> RoomList.LoadingState.Loaded(maximumNumberOfRooms?.toInt() ?: 0)
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import org.matrix.rustcomponents.sdk.RoomListFilterCategory
|
|||||||
* Mapper for converting RoomListFilter to Rust SDK filter kinds.
|
* Mapper for converting RoomListFilter to Rust SDK filter kinds.
|
||||||
*/
|
*/
|
||||||
internal object RoomListFilterMapper {
|
internal object RoomListFilterMapper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base rust filters to always apply across all room lists.
|
* Base rust filters to always apply across all room lists.
|
||||||
* These filters ensure we show:
|
* These filters ensure we show:
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ internal class RustDynamicRoomList(
|
|||||||
private val dynamicController: () -> RoomListDynamicEntriesController?,
|
private val dynamicController: () -> RoomListDynamicEntriesController?,
|
||||||
private val addPagesCount: Int = DEFAULT_ADD_PAGES_COUNT
|
private val addPagesCount: Int = DEFAULT_ADD_PAGES_COUNT
|
||||||
) : DynamicRoomList {
|
) : DynamicRoomList {
|
||||||
|
|
||||||
private val mutex = Mutex()
|
private val mutex = Mutex()
|
||||||
|
|
||||||
override suspend fun rebuildSummaries() {
|
override suspend fun rebuildSummaries() {
|
||||||
|
|||||||
@@ -13,31 +13,30 @@ import io.element.android.libraries.matrix.api.roomlist.RoomList
|
|||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
|
||||||
import kotlinx.coroutines.flow.getAndUpdate
|
|
||||||
|
|
||||||
data class SimplePagedRoomList(
|
class FakeDynamicRoomList(
|
||||||
override val summaries: MutableStateFlow<List<RoomSummary>>,
|
override val summaries: MutableStateFlow<List<RoomSummary>> = MutableStateFlow(emptyList()),
|
||||||
override val loadingState: StateFlow<RoomList.LoadingState>,
|
override val loadingState: MutableStateFlow<RoomList.LoadingState> = MutableStateFlow(RoomList.LoadingState.NotLoaded),
|
||||||
private val currentFilter: MutableStateFlow<RoomListFilter>
|
override val pageSize: Int = Int.MAX_VALUE,
|
||||||
|
val currentFilter: MutableStateFlow<RoomListFilter> = MutableStateFlow(RoomListFilter.None),
|
||||||
|
private val loadMoreLambda: () -> Unit = {},
|
||||||
|
private val resetLambda: () -> Unit = {},
|
||||||
|
private val updateFilterLambda: (RoomListFilter) -> Unit = { filter -> currentFilter.value = filter },
|
||||||
|
private val rebuildSummariesLambda: () -> Unit = {},
|
||||||
) : DynamicRoomList {
|
) : DynamicRoomList {
|
||||||
override val pageSize: Int = Int.MAX_VALUE
|
|
||||||
private val loadedPages = MutableStateFlow(1)
|
|
||||||
|
|
||||||
override suspend fun loadMore() {
|
override suspend fun loadMore() {
|
||||||
// No-op
|
loadMoreLambda()
|
||||||
loadedPages.getAndUpdate { it + 1 }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun reset() {
|
override suspend fun reset() {
|
||||||
loadedPages.emit(1)
|
resetLambda()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun updateFilter(filter: RoomListFilter) {
|
override suspend fun updateFilter(filter: RoomListFilter) {
|
||||||
currentFilter.emit(filter)
|
updateFilterLambda(filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun rebuildSummaries() {
|
override suspend fun rebuildSummaries() {
|
||||||
// No-op
|
rebuildSummariesLambda()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,29 +11,19 @@ package io.element.android.libraries.matrix.test.roomlist
|
|||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.roomlist.DynamicRoomList
|
import io.element.android.libraries.matrix.api.roomlist.DynamicRoomList
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
import io.element.android.libraries.matrix.api.roomlist.RoomList
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListFilter
|
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
class FakeRoomListService(
|
class FakeRoomListService(
|
||||||
var subscribeToVisibleRoomsLambda: (List<RoomId>) -> Unit = {},
|
private val subscribeToVisibleRoomsLambda: (List<RoomId>) -> Unit = {},
|
||||||
|
private val createRoomListLambda: (pageSize: Int) -> DynamicRoomList = { pageSize -> FakeDynamicRoomList(pageSize = pageSize) },
|
||||||
|
override val allRooms: RoomList = createRoomListLambda(Int.MAX_VALUE),
|
||||||
) : RoomListService {
|
) : RoomListService {
|
||||||
private val allRoomSummariesFlow = MutableStateFlow<List<RoomSummary>>(emptyList())
|
|
||||||
private val allRoomsLoadingStateFlow = MutableStateFlow<RoomList.LoadingState>(RoomList.LoadingState.NotLoaded)
|
|
||||||
private val roomListStateFlow = MutableStateFlow<RoomListService.State>(RoomListService.State.Idle)
|
private val roomListStateFlow = MutableStateFlow<RoomListService.State>(RoomListService.State.Idle)
|
||||||
private val syncIndicatorStateFlow = MutableStateFlow<RoomListService.SyncIndicator>(RoomListService.SyncIndicator.Hide)
|
private val syncIndicatorStateFlow = MutableStateFlow<RoomListService.SyncIndicator>(RoomListService.SyncIndicator.Hide)
|
||||||
|
|
||||||
suspend fun postAllRooms(roomSummaries: List<RoomSummary>) {
|
|
||||||
allRoomSummariesFlow.emit(roomSummaries)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun postAllRoomsLoadingState(loadingState: RoomList.LoadingState) {
|
|
||||||
allRoomsLoadingStateFlow.emit(loadingState)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun postState(state: RoomListService.State) {
|
suspend fun postState(state: RoomListService.State) {
|
||||||
roomListStateFlow.emit(state)
|
roomListStateFlow.emit(state)
|
||||||
}
|
}
|
||||||
@@ -46,22 +36,12 @@ class FakeRoomListService(
|
|||||||
pageSize: Int,
|
pageSize: Int,
|
||||||
source: RoomList.Source,
|
source: RoomList.Source,
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
): DynamicRoomList {
|
) = createRoomListLambda(pageSize)
|
||||||
return when (source) {
|
|
||||||
RoomList.Source.All -> allRooms
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override suspend fun subscribeToVisibleRooms(roomIds: List<RoomId>) {
|
override suspend fun subscribeToVisibleRooms(roomIds: List<RoomId>) {
|
||||||
subscribeToVisibleRoomsLambda(roomIds)
|
subscribeToVisibleRoomsLambda(roomIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
override val allRooms = SimplePagedRoomList(
|
|
||||||
allRoomSummariesFlow,
|
|
||||||
allRoomsLoadingStateFlow,
|
|
||||||
MutableStateFlow(RoomListFilter.all())
|
|
||||||
)
|
|
||||||
|
|
||||||
override val state: StateFlow<RoomListService.State> = roomListStateFlow
|
override val state: StateFlow<RoomListService.State> = roomListStateFlow
|
||||||
|
|
||||||
override val syncIndicator: StateFlow<RoomListService.SyncIndicator> = syncIndicatorStateFlow
|
override val syncIndicator: StateFlow<RoomListService.SyncIndicator> = syncIndicatorStateFlow
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ plugins {
|
|||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "io.element.android.libraries.roomselect.impl"
|
namespace = "io.element.android.libraries.roomselect.impl"
|
||||||
|
|
||||||
|
testOptions {
|
||||||
|
unitTests {
|
||||||
|
isIncludeAndroidResources = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setupDependencyInjection()
|
setupDependencyInjection()
|
||||||
@@ -30,6 +36,6 @@ dependencies {
|
|||||||
implementation(projects.libraries.uiStrings)
|
implementation(projects.libraries.uiStrings)
|
||||||
api(projects.libraries.roomselect.api)
|
api(projects.libraries.roomselect.api)
|
||||||
|
|
||||||
testCommonDependencies(libs)
|
testCommonDependencies(libs, includeTestComposeView = true)
|
||||||
testImplementation(projects.libraries.matrix.test)
|
testImplementation(projects.libraries.matrix.test)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,5 +16,5 @@ sealed interface RoomSelectEvents {
|
|||||||
// TODO remove to restore multi-selection
|
// TODO remove to restore multi-selection
|
||||||
data object RemoveSelectedRoom : RoomSelectEvents
|
data object RemoveSelectedRoom : RoomSelectEvents
|
||||||
data object ToggleSearchActive : RoomSelectEvents
|
data object ToggleSearchActive : RoomSelectEvents
|
||||||
data class UpdateVisibleRange(val range: IntRange): RoomSelectEvents
|
data class UpdateVisibleRange(val range: IntRange) : RoomSelectEvents
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,22 +43,23 @@ open class RoomSelectStateProvider : PreviewParameterProvider<RoomSelectState> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun aRoomSelectState(
|
internal fun aRoomSelectState(
|
||||||
mode: RoomSelectMode = RoomSelectMode.Forward,
|
mode: RoomSelectMode = RoomSelectMode.Forward,
|
||||||
resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>> = SearchBarResultState.Initial(),
|
resultState: SearchBarResultState<ImmutableList<SelectRoomInfo>> = SearchBarResultState.Initial(),
|
||||||
searchQuery: String = "",
|
searchQuery: String = "",
|
||||||
isSearchActive: Boolean = false,
|
isSearchActive: Boolean = false,
|
||||||
selectedRooms: ImmutableList<SelectRoomInfo> = persistentListOf(),
|
selectedRooms: ImmutableList<SelectRoomInfo> = persistentListOf(),
|
||||||
|
eventSink: (RoomSelectEvents) -> Unit = {},
|
||||||
) = RoomSelectState(
|
) = RoomSelectState(
|
||||||
mode = mode,
|
mode = mode,
|
||||||
resultState = resultState,
|
resultState = resultState,
|
||||||
searchQuery = TextFieldState(initialText = searchQuery),
|
searchQuery = TextFieldState(initialText = searchQuery),
|
||||||
isSearchActive = isSearchActive,
|
isSearchActive = isSearchActive,
|
||||||
selectedRooms = selectedRooms,
|
selectedRooms = selectedRooms,
|
||||||
eventSink = {}
|
eventSink = eventSink,
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun aRoomSelectRoomList() = persistentListOf(
|
internal fun aRoomSelectRoomList() = persistentListOf(
|
||||||
aSelectRoomInfo(
|
aSelectRoomInfo(
|
||||||
roomId = RoomId("!room1:domain"),
|
roomId = RoomId("!room1:domain"),
|
||||||
name = "Room with name",
|
name = "Room with name",
|
||||||
|
|||||||
@@ -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.RoomListFilter
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
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.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.test.roomlist.FakeRoomListService
|
||||||
import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo
|
import io.element.android.libraries.matrix.ui.model.toSelectRoomInfo
|
||||||
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
import io.element.android.libraries.roomselect.api.RoomSelectMode
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
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 io.element.android.tests.testutils.testCoroutineDispatchers
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@@ -63,9 +67,12 @@ class RoomSelectPresenterTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `present - update query`() = runTest {
|
fun `present - update query`() = runTest {
|
||||||
val roomSummary = aRoomSummary()
|
val roomSummary = aRoomSummary()
|
||||||
val roomListService = FakeRoomListService().apply {
|
val roomList = FakeDynamicRoomList(
|
||||||
postAllRooms(listOf(roomSummary))
|
summaries = MutableStateFlow(listOf(roomSummary))
|
||||||
}
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val presenter = createRoomSelectPresenter(
|
val presenter = createRoomSelectPresenter(
|
||||||
roomListService = roomListService
|
roomListService = roomListService
|
||||||
)
|
)
|
||||||
@@ -81,12 +88,12 @@ class RoomSelectPresenterTest {
|
|||||||
skipItems(1)
|
skipItems(1)
|
||||||
initialState.searchQuery.setTextAndPlaceCursorAtEnd("string not contained")
|
initialState.searchQuery.setTextAndPlaceCursorAtEnd("string not contained")
|
||||||
assertThat(
|
assertThat(
|
||||||
roomListService.allRooms.currentFilter.value
|
roomList.currentFilter.value
|
||||||
).isEqualTo(
|
).isEqualTo(
|
||||||
RoomListFilter.NormalizedMatchRoomName("string not contained")
|
RoomListFilter.NormalizedMatchRoomName("string not contained")
|
||||||
)
|
)
|
||||||
assertThat(awaitItem().searchQuery.text.toString()).isEqualTo("string not contained")
|
assertThat(awaitItem().searchQuery.text.toString()).isEqualTo("string not contained")
|
||||||
roomListService.postAllRooms(
|
roomList.summaries.emit(
|
||||||
emptyList()
|
emptyList()
|
||||||
)
|
)
|
||||||
assertThat(awaitItem().resultState).isInstanceOf(SearchBarResultState.NoResultsFound::class.java)
|
assertThat(awaitItem().resultState).isInstanceOf(SearchBarResultState.NoResultsFound::class.java)
|
||||||
@@ -96,9 +103,12 @@ class RoomSelectPresenterTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `present - select and remove a room`() = runTest {
|
fun `present - select and remove a room`() = runTest {
|
||||||
val roomSummary = aRoomSummary()
|
val roomSummary = aRoomSummary()
|
||||||
val roomListService = FakeRoomListService().apply {
|
val roomList = FakeDynamicRoomList(
|
||||||
postAllRooms(listOf(roomSummary))
|
summaries = MutableStateFlow(listOf(roomSummary))
|
||||||
}
|
)
|
||||||
|
val roomListService = FakeRoomListService(
|
||||||
|
createRoomListLambda = { roomList }
|
||||||
|
)
|
||||||
val presenter = createRoomSelectPresenter(
|
val presenter = createRoomSelectPresenter(
|
||||||
roomListService = roomListService,
|
roomListService = roomListService,
|
||||||
)
|
)
|
||||||
@@ -114,6 +124,35 @@ class RoomSelectPresenterTest {
|
|||||||
cancel()
|
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(
|
internal fun TestScope.createRoomSelectPresenter(
|
||||||
|
|||||||
Reference in New Issue
Block a user