@@ -23,12 +23,20 @@ import io.element.android.libraries.matrix.test.room.FakeBaseRoom
2323import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
2424import io.element.android.libraries.matrix.test.room.aRoomInfo
2525import io.element.android.tests.testutils.WarmUpRule
26+ import io.element.android.tests.testutils.lambda.lambdaRecorder
2627import io.element.android.tests.testutils.testCoroutineDispatchers
28+ import kotlinx.collections.immutable.persistentListOf
2729import kotlinx.coroutines.ExperimentalCoroutinesApi
30+ import kotlinx.coroutines.launch
31+ import kotlinx.coroutines.sync.Mutex
32+ import kotlinx.coroutines.sync.withLock
2833import kotlinx.coroutines.test.TestScope
2934import kotlinx.coroutines.test.runTest
35+ import kotlinx.coroutines.time.withTimeout
36+ import kotlinx.coroutines.withTimeout
3037import org.junit.Rule
3138import org.junit.Test
39+ import kotlin.time.Duration.Companion.seconds
3240
3341@ExperimentalCoroutinesApi
3442class RoomMemberListPresenterTest {
@@ -67,6 +75,59 @@ class RoomMemberListPresenterTest {
6775 }
6876 }
6977
78+ @Test
79+ fun `member loading is done automatically when RoomInfo's activeMemberCount changes` () = runTest {
80+ val reloadMembersMutex = Mutex ()
81+ val updateMembersLambda = lambdaRecorder<Unit > {
82+ if (reloadMembersMutex.isLocked) {
83+ reloadMembersMutex.unlock()
84+ }
85+ }
86+ val room = FakeJoinedRoom (
87+ baseRoom = FakeBaseRoom (
88+ updateMembersResult = updateMembersLambda,
89+ canInviteResult = { Result .success(true ) }
90+ ).apply {
91+ // Needed to avoid discarding the loaded members as a partial and invalid result
92+ givenRoomInfo(aRoomInfo(joinedMembersCount = 2 ))
93+ }
94+ )
95+ val presenter = createPresenter(joinedRoom = room)
96+ moleculeFlow(RecompositionMode .Immediate ) {
97+ presenter.present()
98+ }.test {
99+ skipItems(1 )
100+ val initialState = awaitItem()
101+ assertThat(initialState.roomMembers.isLoading()).isTrue()
102+ room.givenRoomMembersState(RoomMembersState .Ready (aRoomMemberList()))
103+ // Skip item while the new members state is processed
104+ skipItems(1 )
105+ val loadedMembersState = awaitItem()
106+ assertThat(loadedMembersState.roomMembers.isLoading()).isFalse()
107+ assertThat(loadedMembersState.roomMembers.dataOrNull()?.joined).isNotEmpty()
108+
109+ // Assert no events are emitted only with that change
110+ expectNoEvents()
111+
112+ // This will only progress if the `Room.updateMembers()` function is called, triggered by the RoomInfo change
113+ withTimeout(10 .seconds) {
114+ reloadMembersMutex.withLock {
115+ launch { room.givenRoomInfo(aRoomInfo(activeMembersCount = 0L )) }
116+ }
117+ }
118+
119+ // Wait for the update to be processed
120+ skipItems(1 )
121+
122+ // Update the room members state as `Room.updateMembers()` would have done with the actual implementation
123+ room.givenRoomMembersState(RoomMembersState .Ready (persistentListOf()))
124+ // Wait for another update
125+ skipItems(1 )
126+ // The members should be reloaded now
127+ assertThat(awaitItem().roomMembers.dataOrNull()?.joined).isEmpty()
128+ }
129+ }
130+
70131 @Test
71132 fun `open search` () = runTest {
72133 val presenter = createPresenter(
0 commit comments