misc(power level) : update tests following api change

This commit is contained in:
ganfra 2025-12-09 20:50:31 +01:00
parent 400d520685
commit 48971d4aee
15 changed files with 418 additions and 605 deletions

View file

@ -63,6 +63,7 @@ import io.element.android.libraries.matrix.api.permalink.PermalinkParser
import io.element.android.libraries.matrix.api.room.MessageEventType
import io.element.android.libraries.matrix.api.room.RoomMembersState
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.tombstone.SuccessorRoom
import io.element.android.libraries.matrix.api.timeline.Timeline
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
@ -85,6 +86,7 @@ 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.aRoomInfo
import io.element.android.libraries.matrix.test.room.aRoomMember
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.test.timeline.aTimelineItemDebugInfo
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
@ -142,11 +144,7 @@ class MessagesPresenterTest {
fun `present - check that the room's unread flag is removed`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
markAsReadResult = { lambdaError() }
),
typingNoticeResult = { Result.success(Unit) },
@ -172,11 +170,7 @@ class MessagesPresenterTest {
}
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
),
liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) },
@ -222,11 +216,7 @@ class MessagesPresenterTest {
}
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
),
liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) },
@ -287,11 +277,7 @@ class MessagesPresenterTest {
val event = aMessageEvent()
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
eventPermalinkResult = { Result.success("a link") },
),
typingNoticeResult = { Result.success(Unit) },
@ -513,11 +499,7 @@ class MessagesPresenterTest {
val liveTimeline = FakeTimeline()
val joinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
),
liveTimeline = liveTimeline,
typingNoticeResult = { Result.success(Unit) },
@ -585,11 +567,7 @@ class MessagesPresenterTest {
fun `present - shows prompt to reinvite users in DM`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 1, activeMembersCount = 1))
},
@ -618,11 +596,7 @@ class MessagesPresenterTest {
fun `present - doesn't show reinvite prompt in non-direct room`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(isDirect = false, joinedMembersCount = 1, activeMembersCount = 1))
},
@ -644,11 +618,7 @@ class MessagesPresenterTest {
fun `present - doesn't show reinvite prompt if other party is present`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(isDirect = true, joinedMembersCount = 2, activeMembersCount = 2))
},
@ -671,11 +641,7 @@ class MessagesPresenterTest {
val inviteUserResult = lambdaRecorder { _: UserId -> Result.success(Unit) }
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
),
typingNoticeResult = { Result.success(Unit) },
inviteUserResult = inviteUserResult,
@ -706,11 +672,7 @@ class MessagesPresenterTest {
val inviteUserResult = lambdaRecorder { _: UserId -> Result.success(Unit) }
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
),
typingNoticeResult = { Result.success(Unit) },
inviteUserResult = inviteUserResult,
@ -743,11 +705,7 @@ class MessagesPresenterTest {
fun `present - handle reinviting other user when memberlist is not ready`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
),
typingNoticeResult = { Result.success(Unit) },
)
@ -768,11 +726,7 @@ class MessagesPresenterTest {
fun `present - handle reinviting other user when inviting fails`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
),
typingNoticeResult = { Result.success(Unit) },
inviteUserResult = { Result.failure(RuntimeException("Oops!")) },
@ -806,17 +760,7 @@ class MessagesPresenterTest {
fun `present - permission to post`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
canUserSendMessageResult = { _, messageEventType ->
when (messageEventType) {
MessageEventType.RoomMessage -> Result.success(true)
MessageEventType.Reaction -> Result.success(true)
else -> lambdaError()
}
},
roomPermissions = roomPermissions(),
),
typingNoticeResult = { Result.success(Unit) },
)
@ -832,17 +776,9 @@ class MessagesPresenterTest {
fun `present - no permission to post`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
canUserSendMessageResult = { _, messageEventType ->
when (messageEventType) {
MessageEventType.RoomMessage -> Result.success(false)
MessageEventType.Reaction -> Result.success(false)
else -> lambdaError()
}
},
roomPermissions = roomPermissions(
canSendMessage = false
),
),
typingNoticeResult = { Result.success(Unit) },
)
@ -858,11 +794,9 @@ class MessagesPresenterTest {
fun `present - permission to redact own`() = runTest {
val joinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOtherResult = { Result.success(false) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(
canRedactOther = false
),
),
typingNoticeResult = { Result.success(Unit) },
)
@ -879,11 +813,9 @@ class MessagesPresenterTest {
fun `present - permission to redact other`() = runTest {
val joinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOtherResult = { Result.success(true) },
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(false) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(
canRedactOwn = false
),
),
typingNoticeResult = { Result.success(Unit) },
)
@ -928,11 +860,7 @@ class MessagesPresenterTest {
val timeline = FakeTimeline()
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
),
liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) },
@ -972,11 +900,7 @@ class MessagesPresenterTest {
val analyticsService = FakeAnalyticsService()
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
),
liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) },
@ -1073,11 +997,7 @@ class MessagesPresenterTest {
}
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
),
liveTimeline = timeline,
typingNoticeResult = { Result.success(Unit) },
@ -1114,11 +1034,7 @@ class MessagesPresenterTest {
val successorReason = "This room has been moved to a new location"
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
initialRoomInfo = aRoomInfo(
successorRoom = SuccessorRoom(
roomId = successorRoomId,
@ -1142,11 +1058,7 @@ class MessagesPresenterTest {
fun `present - room without successor room has null successor info in state`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
initialRoomInfo = aRoomInfo(successorRoom = null)
),
typingNoticeResult = { Result.success(Unit) },
@ -1164,11 +1076,13 @@ class MessagesPresenterTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
sessionId = A_SESSION_ID,
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = FakeRoomPermissions(
canSendState = { true },
canSendMessage = { true },
canRedactOther = true,
canRedactOwn = true,
canPinUnpin = true,
),
initialRoomInfo = aRoomInfo(isDirect = true, isEncrypted = true)
).apply {
givenRoomMembersState(RoomMembersState.Ready(persistentListOf(aRoomMember(userId = A_SESSION_ID), aRoomMember(userId = A_USER_ID_2))))
@ -1311,16 +1225,44 @@ class MessagesPresenterTest {
}
}
private fun roomPermissions(
canStartCall: Boolean = true,
canRedactOther: Boolean = true,
canRedactOwn: Boolean = true,
canSendMessage: Boolean = true,
canSendReaction: Boolean = true,
canPinUnpin: Boolean = true,
) = FakeRoomPermissions(
canSendState = { type ->
when(type){
StateEventType.CALL_MEMBER -> canStartCall
else -> lambdaError()
}
},
canSendMessage = { type ->
when(type){
MessageEventType.RoomMessage -> canSendMessage
MessageEventType.Reaction -> canSendReaction
else -> lambdaError()
}
},
canRedactOther = canRedactOther,
canRedactOwn = canRedactOwn,
canPinUnpin = canPinUnpin,
)
private fun TestScope.createMessagesPresenter(
coroutineDispatchers: CoroutineDispatchers = testCoroutineDispatchers(),
timeline: Timeline = FakeTimeline(),
joinedRoom: FakeJoinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserJoinCallResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = FakeRoomPermissions(
canSendState = { true },
canSendMessage = { true },
canRedactOther = true,
canRedactOwn = true,
canPinUnpin = true,
),
).apply {
givenRoomInfo(aRoomInfo(id = roomId, name = ""))
},

View file

@ -69,6 +69,7 @@ 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.aRoomInfo
import io.element.android.libraries.matrix.test.room.aRoomMember
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
import io.element.android.libraries.mediapickers.api.PickerProvider
@ -991,9 +992,12 @@ class MessageComposerPresenterTest {
val invitedUser = aRoomMember(userId = A_USER_ID_3, membership = RoomMembershipState.INVITE)
val bob = aRoomMember(userId = A_USER_ID_2, membership = RoomMembershipState.JOIN)
val david = aRoomMember(userId = A_USER_ID_4, displayName = "Dave", membership = RoomMembershipState.JOIN)
var canUserTriggerRoomNotificationResult = true
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(canUserTriggerRoomNotificationResult = { Result.success(canUserTriggerRoomNotificationResult) }),
baseRoom = FakeBaseRoom(
roomPermissions = FakeRoomPermissions(
canTriggerRoomNotification = true,
)
),
typingNoticeResult = { Result.success(Unit) }
).apply {
givenRoomMembersState(
@ -1033,10 +1037,38 @@ class MessageComposerPresenterTest {
// If the suggestion isn't a mention, no suggestions are returned
initialState.eventSink(MessageComposerEvent.SuggestionReceived(Suggestion(0, 0, SuggestionType.Command, "")))
assertThat(awaitItem().suggestions).isEmpty()
}
}
// If user has no permission to send `@room` mentions, `RoomMemberSuggestion.Room` is not returned
canUserTriggerRoomNotificationResult = false
@Test
fun `present - room mention suggestions no permission`() = runTest {
val currentUser = aRoomMember(userId = A_USER_ID, membership = RoomMembershipState.JOIN)
val invitedUser = aRoomMember(userId = A_USER_ID_3, membership = RoomMembershipState.INVITE)
val bob = aRoomMember(userId = A_USER_ID_2, membership = RoomMembershipState.JOIN)
val david = aRoomMember(userId = A_USER_ID_4, displayName = "Dave", membership = RoomMembershipState.JOIN)
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
roomPermissions = FakeRoomPermissions(
canTriggerRoomNotification = false,
)
),
typingNoticeResult = { Result.success(Unit) }
).apply {
givenRoomMembersState(
RoomMembersState.Ready(
persistentListOf(currentUser, invitedUser, bob, david),
)
)
givenRoomInfo(aRoomInfo(isDirect = false))
}
val presenter = createPresenter(room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
// An empty suggestion returns the joined members that are not the current user, but not the room
initialState.eventSink(MessageComposerEvent.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, "")))
skipItems(1)
assertThat(awaitItem().suggestions)
.containsExactly(ResolvedSuggestion.Member(bob), ResolvedSuggestion.Member(david))
}
@ -1049,7 +1081,9 @@ class MessageComposerPresenterTest {
val bob = aRoomMember(userId = A_USER_ID_2, membership = RoomMembershipState.JOIN)
val david = aRoomMember(userId = A_USER_ID_4, displayName = "Dave", membership = RoomMembershipState.JOIN)
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(canUserTriggerRoomNotificationResult = { Result.success(true) }),
baseRoom = FakeBaseRoom(
roomPermissions = FakeRoomPermissions(canTriggerRoomNotification = true),
),
typingNoticeResult = { Result.success(Unit) }
).apply {
givenRoomMembersState(
@ -1069,7 +1103,6 @@ class MessageComposerPresenterTest {
presenter.present()
}.test {
val initialState = awaitItem()
// An empty suggestion returns the joined members that are not the current user, but not the room
initialState.eventSink(MessageComposerEvent.SuggestionReceived(Suggestion(0, 0, SuggestionType.Mention, "")))
skipItems(1)

View file

@ -22,6 +22,8 @@ import io.element.android.libraries.designsystem.utils.snackbar.SnackbarDispatch
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.room.JoinedRoom
import io.element.android.libraries.matrix.api.room.MessageEventType
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.sync.SyncService
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo
@ -31,6 +33,7 @@ import io.element.android.libraries.matrix.test.A_UNIQUE_ID
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.aRoomInfo
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.sync.FakeSyncService
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.test.timeline.aMessageContent
@ -38,6 +41,7 @@ import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
import io.element.android.services.analytics.api.AnalyticsService
import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.lambda.assert
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.test
@ -55,9 +59,7 @@ class PinnedMessagesListPresenterTest {
fun `present - initial state`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
}
@ -74,9 +76,7 @@ class PinnedMessagesListPresenterTest {
fun `present - timeline failure state`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
},
@ -95,9 +95,7 @@ class PinnedMessagesListPresenterTest {
fun `present - empty state`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf()))
},
@ -117,9 +115,7 @@ class PinnedMessagesListPresenterTest {
val pinnedEventsTimeline = createPinnedMessagesTimeline()
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
},
@ -146,9 +142,7 @@ class PinnedMessagesListPresenterTest {
val analyticsService = FakeAnalyticsService()
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
},
@ -194,9 +188,7 @@ class PinnedMessagesListPresenterTest {
val pinnedEventsTimeline = createPinnedMessagesTimeline()
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
},
@ -225,9 +217,7 @@ class PinnedMessagesListPresenterTest {
val pinnedEventsTimeline = createPinnedMessagesTimeline()
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
},
@ -256,9 +246,7 @@ class PinnedMessagesListPresenterTest {
val pinnedEventsTimeline = createPinnedMessagesTimeline()
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canRedactOwnResult = { Result.success(true) },
canRedactOtherResult = { Result.success(true) },
canUserPinUnpinResult = { Result.success(true) },
roomPermissions = roomPermissions(),
).apply {
givenRoomInfo(aRoomInfo(pinnedEventIds = listOf(AN_EVENT_ID)))
},
@ -295,6 +283,16 @@ class PinnedMessagesListPresenterTest {
)
}
private fun roomPermissions(
canRedactOther: Boolean = true,
canRedactOwn: Boolean = true,
canPinUnpin: Boolean = true,
) = FakeRoomPermissions(
canRedactOther = canRedactOther,
canRedactOwn = canRedactOwn,
canPinUnpin = canPinUnpin,
)
private fun TestScope.createPinnedMessagesListPresenter(
navigator: PinnedMessagesListNavigator = FakePinnedMessagesListNavigator(),
room: JoinedRoom = FakeJoinedRoom(),

View file

@ -35,7 +35,9 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.ThreadId
import io.element.android.libraries.matrix.api.core.UniqueId
import io.element.android.libraries.matrix.api.core.asEventId
import io.element.android.libraries.matrix.api.room.MessageEventType
import io.element.android.libraries.matrix.api.room.RoomMembersState
import io.element.android.libraries.matrix.api.room.StateEventType
import io.element.android.libraries.matrix.api.room.tombstone.PredecessorRoom
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
import io.element.android.libraries.matrix.api.timeline.ReceiptType
@ -55,6 +57,7 @@ import io.element.android.libraries.matrix.test.A_USER_ID
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.aRoomMember
import io.element.android.libraries.matrix.test.room.powerlevels.FakeRoomPermissions
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.matrix.test.timeline.aMessageContent
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
@ -66,6 +69,7 @@ import io.element.android.tests.testutils.awaitLastSequentialItem
import io.element.android.tests.testutils.consumeItemsUntilPredicate
import io.element.android.tests.testutils.lambda.any
import io.element.android.tests.testutils.lambda.assert
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.test
@ -97,9 +101,7 @@ class TimelinePresenterTest {
@Test
fun `present - initial state`() = runTest {
val presenter = createTimelinePresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
assertThat(initialState.timelineItems).isEmpty()
assertThat(initialState.isLive).isTrue()
@ -118,9 +120,7 @@ class TimelinePresenterTest {
this.paginateLambda = paginateLambda
}
val presenter = createTimelinePresenter(timeline = timeline)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitItem()
initialState.eventSink.invoke(TimelineEvents.LoadMore(Timeline.PaginationDirection.BACKWARDS))
initialState.eventSink.invoke(TimelineEvents.LoadMore(Timeline.PaginationDirection.FORWARDS))
@ -166,9 +166,6 @@ class TimelinePresenterTest {
)
val room = FakeJoinedRoom(
liveTimeline = timeline,
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
)
)
val sessionPreferencesStore = InMemorySessionPreferencesStore(isSendPublicReadReceiptsEnabled = isSendPublicReadReceiptsEnabled)
val presenter = createTimelinePresenter(
@ -176,9 +173,7 @@ class TimelinePresenterTest {
room = room,
sessionPreferencesStore = sessionPreferencesStore,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(0))
runCurrent()
@ -211,9 +206,7 @@ class TimelinePresenterTest {
this.sendReadReceiptLambda = sendReadReceiptsLambda
}
val presenter = createTimelinePresenter(timeline)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
skipItems(1)
awaitItem().run {
eventSink.invoke(TimelineEvents.OnScrollFinished(1))
@ -252,9 +245,7 @@ class TimelinePresenterTest {
timeline = timeline,
sessionPreferencesStore = sessionPreferencesStore,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
skipItems(1)
awaitItem().run {
eventSink.invoke(TimelineEvents.OnScrollFinished(0))
@ -290,9 +281,7 @@ class TimelinePresenterTest {
this.sendReadReceiptLambda = sendReadReceiptsLambda
}
val presenter = createTimelinePresenter(timeline)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
skipItems(1)
awaitItem().run {
eventSink.invoke(TimelineEvents.OnScrollFinished(1))
@ -320,9 +309,7 @@ class TimelinePresenterTest {
this.sendReadReceiptLambda = sendReadReceiptsLambda
}
val presenter = createTimelinePresenter(timeline)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
skipItems(1)
val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.OnScrollFinished(1))
@ -339,9 +326,7 @@ class TimelinePresenterTest {
markAsReadResult = { Result.success(Unit) },
)
val presenter = createTimelinePresenter(timeline)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
assertThat(initialState.newEventState).isEqualTo(NewEventState.None)
assertThat(initialState.timelineItems.size).isEqualTo(0)
@ -390,9 +375,7 @@ class TimelinePresenterTest {
timelineItems = timelineItems,
)
val presenter = createTimelinePresenter(timeline)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
assertThat(initialState.newEventState).isEqualTo(NewEventState.None)
assertThat(initialState.timelineItems.size).isEqualTo(0)
@ -446,9 +429,7 @@ class TimelinePresenterTest {
val presenter = createTimelinePresenter(
sendPollResponseAction = sendPollResponseAction,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.SelectPollAnswer(AN_EVENT_ID, "anAnswerId"))
}
@ -462,9 +443,7 @@ class TimelinePresenterTest {
val presenter = createTimelinePresenter(
endPollAction = endPollAction,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.EndPoll(AN_EVENT_ID))
}
@ -481,9 +460,7 @@ class TimelinePresenterTest {
val presenter = createTimelinePresenter(
messagesNavigator = navigator,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
awaitFirstItem().eventSink(TimelineEvents.EditPoll(AN_EVENT_ID))
onEditPollClickLambda.assertions().isCalledOnce().with(value(AN_EVENT_ID))
}
@ -500,9 +477,7 @@ class TimelinePresenterTest {
),
redactedVoiceMessageManager = redactedVoiceMessageManager,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
assertThat(redactedVoiceMessageManager.invocations.size).isEqualTo(0)
skipItems(2)
assertThat(redactedVoiceMessageManager.invocations.size).isEqualTo(1)
@ -528,16 +503,14 @@ class TimelinePresenterTest {
liveTimeline = liveTimeline,
createTimelineResult = { Result.success(detachedTimeline) },
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
roomPermissions = roomPermissions(),
threadRootIdForEventResult = { _ -> Result.success(null) },
),
)
val presenter = createTimelinePresenter(
room = room,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
awaitItem().also { state ->
@ -579,15 +552,13 @@ class TimelinePresenterTest {
)
),
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
roomPermissions = roomPermissions(),
threadRootIdForEventResult = { Result.success(null) },
),
),
timelineItemIndexer = timelineItemIndexer,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
advanceUntilIdle()
@ -619,14 +590,12 @@ class TimelinePresenterTest {
),
createTimelineResult = { Result.failure(RuntimeException("An error")) },
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
roomPermissions = roomPermissions(),
threadRootIdForEventResult = { _ -> Result.success(null) },
),
)
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
initialState.eventSink(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
awaitItem().also { state ->
@ -668,7 +637,7 @@ class TimelinePresenterTest {
liveTimeline = liveTimeline,
createTimelineResult = { Result.success(detachedTimeline) },
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
roomPermissions = roomPermissions(),
threadRootIdForEventResult = { _ -> Result.success(threadId) },
),
)
@ -679,9 +648,7 @@ class TimelinePresenterTest {
timeline = liveTimeline,
messagesNavigator = navigator,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
@ -729,7 +696,7 @@ class TimelinePresenterTest {
liveTimeline = liveTimeline,
createTimelineResult = { Result.success(detachedTimeline) },
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
roomPermissions = roomPermissions(),
threadRootIdForEventResult = { _ -> Result.success(threadId) },
),
)
@ -740,9 +707,7 @@ class TimelinePresenterTest {
timeline = liveTimeline,
messagesNavigator = navigator,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
@ -785,7 +750,7 @@ class TimelinePresenterTest {
liveTimeline = liveTimeline,
createTimelineResult = { Result.success(detachedTimeline) },
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
roomPermissions = roomPermissions(),
// Use a different thread id
threadRootIdForEventResult = { _ -> Result.success(A_THREAD_ID_2) },
),
@ -797,9 +762,7 @@ class TimelinePresenterTest {
timeline = liveTimeline,
messagesNavigator = navigator,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
@ -846,7 +809,7 @@ class TimelinePresenterTest {
liveTimeline = liveTimeline,
createTimelineResult = { Result.success(detachedTimeline) },
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
roomPermissions = roomPermissions(),
// The event is in the main timeline, not in a thread
threadRootIdForEventResult = { _ -> Result.success(null) },
),
@ -858,9 +821,7 @@ class TimelinePresenterTest {
timeline = liveTimeline,
messagesNavigator = navigator,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
initialState.eventSink.invoke(TimelineEvents.FocusOnEvent(AN_EVENT_ID))
@ -891,9 +852,7 @@ class TimelinePresenterTest {
fun `present - show shield hide shield`() = runTest {
val presenter = createTimelinePresenter()
val shield = aCriticalShield()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
assertThat(initialState.messageShield).isNull()
initialState.eventSink(TimelineEvents.ShowShieldDialog(shield))
@ -929,7 +888,9 @@ class TimelinePresenterTest {
)
val room = FakeJoinedRoom(
liveTimeline = timeline,
baseRoom = FakeBaseRoom(canUserSendMessageResult = { _, _ -> Result.success(true) }),
baseRoom = FakeBaseRoom(
roomPermissions = roomPermissions(),
),
).apply {
givenRoomMembersState(RoomMembersState.Unknown)
}
@ -937,9 +898,7 @@ class TimelinePresenterTest {
val avatarUrl = "https://domain.com/avatar.jpg"
val presenter = createTimelinePresenter(timeline, room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = consumeItemsUntilPredicate(30.seconds) { it.timelineItems.isNotEmpty() }.last()
val event = initialState.timelineItems.first() as TimelineItem.Event
assertThat(event.senderAvatar.url).isNull()
@ -963,15 +922,13 @@ class TimelinePresenterTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
roomPermissions = roomPermissions(),
predecessorRoomResult = { predecessorRoom }
),
)
val presenter = createTimelinePresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
assertThat(initialState.timelineRoomInfo.predecessorRoom).isNotNull()
assertThat(initialState.timelineRoomInfo.predecessorRoom?.roomId).isEqualTo(predecessorRoomId)
@ -982,14 +939,12 @@ class TimelinePresenterTest {
fun `present - timeline room info no predecessor`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
roomPermissions = roomPermissions(),
predecessorRoomResult = { null }
),
)
val presenter = createTimelinePresenter(room = room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
presenter.test {
val initialState = awaitFirstItem()
assertThat(initialState.timelineRoomInfo.predecessorRoom).isNull()
}
@ -999,7 +954,7 @@ class TimelinePresenterTest {
fun `present - timeline event navigate to room`() = runTest {
val room = FakeJoinedRoom(
baseRoom = FakeBaseRoom(
canUserSendMessageResult = { _, _ -> Result.success(true) },
roomPermissions = roomPermissions(),
),
)
val onNavigateToRoomLambda = lambdaRecorder<RoomId, EventId?, List<String>, Unit> { _, _, _ -> }
@ -1025,11 +980,32 @@ class TimelinePresenterTest {
return awaitItem()
}
private fun roomPermissions(
canRedactOther: Boolean = false,
canRedactOwn: Boolean = true,
canSendMessage: Boolean = true,
canSendReaction: Boolean = true,
canPinUnpin: Boolean = false,
) = FakeRoomPermissions(
canSendMessage = { type ->
when(type){
MessageEventType.RoomMessage -> canSendMessage
MessageEventType.Reaction -> canSendReaction
else -> lambdaError()
}
},
canRedactOther = canRedactOther,
canRedactOwn = canRedactOwn,
canPinUnpin = canPinUnpin,
)
private fun TestScope.createTimelinePresenter(
timeline: Timeline = FakeTimeline(),
room: FakeJoinedRoom = FakeJoinedRoom(
liveTimeline = timeline,
baseRoom = FakeBaseRoom(canUserSendMessageResult = { _, _ -> Result.success(true) }),
baseRoom = FakeBaseRoom(
roomPermissions = roomPermissions(),
),
),
redactedVoiceMessageManager: RedactedVoiceMessageManager = FakeRedactedVoiceMessageManager(),
messagesNavigator: FakeMessagesNavigator = FakeMessagesNavigator(),