Timeline : continue to fix more tests...
This commit is contained in:
@@ -27,6 +27,7 @@ import com.bumble.appyx.testing.junit4.util.MainDispatcherRule
|
||||
import com.bumble.appyx.testing.unit.common.helper.parentNodeTestHelper
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.appnav.di.RoomComponentFactory
|
||||
import io.element.android.appnav.room.RoomNavigationTarget
|
||||
import io.element.android.appnav.room.joined.JoinedRoomLoadedFlowNode
|
||||
import io.element.android.features.messages.api.MessagesEntryPoint
|
||||
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
|
||||
@@ -124,7 +125,7 @@ class JoinRoomLoadedFlowNodeTest {
|
||||
// GIVEN
|
||||
val room = FakeMatrixRoom()
|
||||
val fakeMessagesEntryPoint = FakeMessagesEntryPoint()
|
||||
val inputs = JoinedRoomLoadedFlowNode.Inputs(room)
|
||||
val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Messages())
|
||||
val roomFlowNode = createJoinedRoomLoadedFlowNode(
|
||||
plugins = listOf(inputs),
|
||||
messagesEntryPoint = fakeMessagesEntryPoint,
|
||||
@@ -146,7 +147,7 @@ class JoinRoomLoadedFlowNodeTest {
|
||||
val room = FakeMatrixRoom()
|
||||
val fakeMessagesEntryPoint = FakeMessagesEntryPoint()
|
||||
val fakeRoomDetailsEntryPoint = FakeRoomDetailsEntryPoint()
|
||||
val inputs = JoinedRoomLoadedFlowNode.Inputs(room)
|
||||
val inputs = JoinedRoomLoadedFlowNode.Inputs(room, RoomNavigationTarget.Messages())
|
||||
val roomFlowNode = createJoinedRoomLoadedFlowNode(
|
||||
plugins = listOf(inputs),
|
||||
messagesEntryPoint = fakeMessagesEntryPoint,
|
||||
|
||||
@@ -18,9 +18,11 @@ package io.element.android.features.location.impl.common.actions
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.location.api.Location
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.net.URLEncoder
|
||||
|
||||
@Ignore
|
||||
internal class AndroidLocationActionsTest {
|
||||
// We use an Android-native encoder in the actual app, switch to an equivalent JVM one for the tests
|
||||
private fun urlEncoder(input: String) = URLEncoder.encode(input, "US-ASCII")
|
||||
|
||||
@@ -65,6 +65,7 @@ import io.element.android.libraries.featureflag.api.FeatureFlags
|
||||
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
|
||||
import io.element.android.libraries.featureflag.test.InMemoryAppPreferencesStore
|
||||
import io.element.android.libraries.featureflag.test.InMemorySessionPreferencesStore
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoomMembersState
|
||||
@@ -83,6 +84,7 @@ import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
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.timeline.FakeTimeline
|
||||
import io.element.android.libraries.mediapickers.test.FakePickerProvider
|
||||
import io.element.android.libraries.mediaplayer.test.FakeMediaPlayer
|
||||
import io.element.android.libraries.mediaupload.api.MediaSender
|
||||
@@ -97,6 +99,9 @@ import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||
import io.element.android.tests.testutils.consumeItemsUntilTimeout
|
||||
import io.element.android.tests.testutils.lambda.assert
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import io.mockk.mockk
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
@@ -169,7 +174,13 @@ class MessagesPresenterTest {
|
||||
@Test
|
||||
fun `present - handle toggling a reaction`() = runTest {
|
||||
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
|
||||
val room = FakeMatrixRoom()
|
||||
val toggleReactionSuccess = lambdaRecorder { _: String, _: EventId -> Result.success(Unit) }
|
||||
val toggleReactionFailure = lambdaRecorder { _: String, _: EventId -> Result.failure<Unit>(IllegalStateException("Failed to send reaction")) }
|
||||
|
||||
val timeline = FakeTimeline().apply {
|
||||
this.toggleReactionLambda = toggleReactionSuccess
|
||||
}
|
||||
val room = FakeMatrixRoom(liveTimeline = timeline)
|
||||
val presenter = createMessagesPresenter(matrixRoom = room, coroutineDispatchers = coroutineDispatchers)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
@@ -177,29 +188,42 @@ class MessagesPresenterTest {
|
||||
skipItems(1)
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink.invoke(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID))
|
||||
assertThat(room.myReactions.count()).isEqualTo(1)
|
||||
// No crashes when sending a reaction failed
|
||||
room.givenToggleReactionResult(Result.failure(IllegalStateException("Failed to send reaction")))
|
||||
timeline.apply { toggleReactionLambda = toggleReactionFailure }
|
||||
initialState.eventSink.invoke(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID))
|
||||
assertThat(room.myReactions.count()).isEqualTo(1)
|
||||
assertThat(awaitItem().actionListState.target).isEqualTo(ActionListState.Target.None)
|
||||
|
||||
assert(toggleReactionSuccess)
|
||||
.isCalledOnce()
|
||||
.with(value("👍"), value(AN_EVENT_ID))
|
||||
assert(toggleReactionFailure)
|
||||
.isCalledOnce()
|
||||
.with(value("👍"), value(AN_EVENT_ID))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - handle toggling a reaction twice`() = runTest {
|
||||
val coroutineDispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true)
|
||||
val room = FakeMatrixRoom()
|
||||
val toggleReactionSuccess = lambdaRecorder { _: String, _: EventId -> Result.success(Unit) }
|
||||
|
||||
val timeline = FakeTimeline().apply {
|
||||
this.toggleReactionLambda = toggleReactionSuccess
|
||||
}
|
||||
val room = FakeMatrixRoom(liveTimeline = timeline)
|
||||
val presenter = createMessagesPresenter(matrixRoom = room, coroutineDispatchers = coroutineDispatchers)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitFirstItem()
|
||||
initialState.eventSink.invoke(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID))
|
||||
assertThat(room.myReactions.count()).isEqualTo(1)
|
||||
|
||||
initialState.eventSink.invoke(MessagesEvents.ToggleReaction("👍", AN_EVENT_ID))
|
||||
assertThat(room.myReactions.count()).isEqualTo(0)
|
||||
assert(toggleReactionSuccess)
|
||||
.isCalledExactly(2)
|
||||
.withSequence(
|
||||
listOf(value("👍"), value(AN_EVENT_ID)),
|
||||
listOf(value("👍"), value(AN_EVENT_ID)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,7 +298,7 @@ class MessagesPresenterTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
skipItems(3)
|
||||
skipItems(2)
|
||||
val initialState = awaitItem()
|
||||
initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.Reply, aMessageEvent(eventId = null)))
|
||||
assertThat(awaitItem().actionListState.target).isEqualTo(ActionListState.Target.None)
|
||||
@@ -430,7 +454,6 @@ class MessagesPresenterTest {
|
||||
initialState.eventSink.invoke(MessagesEvents.HandleAction(TimelineItemAction.Redact, aMessageEvent()))
|
||||
assertThat(matrixRoom.redactEventEventIdParam).isEqualTo(AN_EVENT_ID)
|
||||
assertThat(awaitItem().actionListState.target).isEqualTo(ActionListState.Target.None)
|
||||
skipItems(1) // back paginating
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ import io.element.android.libraries.matrix.test.permalink.FakePermalinkBuilder
|
||||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.mediapickers.api.PickerProvider
|
||||
import io.element.android.libraries.mediapickers.test.FakePickerProvider
|
||||
import io.element.android.libraries.mediaupload.api.MediaPreProcessor
|
||||
@@ -82,6 +83,10 @@ import io.element.android.libraries.textcomposer.model.Suggestion
|
||||
import io.element.android.libraries.textcomposer.model.SuggestionType
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.lambda.any
|
||||
import io.element.android.tests.testutils.lambda.assert
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.lambda.value
|
||||
import io.element.android.tests.testutils.waitForPredicate
|
||||
import io.mockk.mockk
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
@@ -260,7 +265,13 @@ class MessageComposerPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - edit sent message`() = runTest {
|
||||
val fakeMatrixRoom = FakeMatrixRoom()
|
||||
val editMessageLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String, _: String?, _: List<Mention> ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val timeline = FakeTimeline().apply {
|
||||
this.editMessageLambda = editMessageLambda
|
||||
}
|
||||
val fakeMatrixRoom = FakeMatrixRoom(liveTimeline = timeline)
|
||||
val presenter = createPresenter(
|
||||
this,
|
||||
fakeMatrixRoom,
|
||||
@@ -284,7 +295,13 @@ class MessageComposerPresenterTest {
|
||||
skipItems(1)
|
||||
val messageSentState = awaitItem()
|
||||
assertThat(messageSentState.richTextEditorState.messageHtml).isEqualTo("")
|
||||
assertThat(fakeMatrixRoom.editMessageCalls.first()).isEqualTo(ANOTHER_MESSAGE to ANOTHER_MESSAGE)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
assert(editMessageLambda)
|
||||
.isCalledOnce()
|
||||
.with(any(), any(), value(ANOTHER_MESSAGE), value(ANOTHER_MESSAGE), any())
|
||||
|
||||
assertThat(analyticsService.capturedEvents).containsExactly(
|
||||
Composer(
|
||||
inThread = false,
|
||||
@@ -298,7 +315,13 @@ class MessageComposerPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - edit not sent message`() = runTest {
|
||||
val fakeMatrixRoom = FakeMatrixRoom()
|
||||
val editMessageLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String, _: String?, _: List<Mention> ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val timeline = FakeTimeline().apply {
|
||||
this.editMessageLambda = editMessageLambda
|
||||
}
|
||||
val fakeMatrixRoom = FakeMatrixRoom(liveTimeline = timeline)
|
||||
val presenter = createPresenter(
|
||||
this,
|
||||
fakeMatrixRoom,
|
||||
@@ -322,7 +345,13 @@ class MessageComposerPresenterTest {
|
||||
skipItems(1)
|
||||
val messageSentState = awaitItem()
|
||||
assertThat(messageSentState.richTextEditorState.messageHtml).isEqualTo("")
|
||||
assertThat(fakeMatrixRoom.editMessageCalls.first()).isEqualTo(ANOTHER_MESSAGE to ANOTHER_MESSAGE)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
assert(editMessageLambda)
|
||||
.isCalledOnce()
|
||||
.with(any(), any(), value(ANOTHER_MESSAGE), value(ANOTHER_MESSAGE), any())
|
||||
|
||||
assertThat(analyticsService.capturedEvents).containsExactly(
|
||||
Composer(
|
||||
inThread = false,
|
||||
@@ -336,7 +365,13 @@ class MessageComposerPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - reply message`() = runTest {
|
||||
val fakeMatrixRoom = FakeMatrixRoom()
|
||||
val replyMessageLambda = lambdaRecorder {_: EventId, _: String, _: String?, _:List<Mention> ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val timeline = FakeTimeline().apply {
|
||||
this.replyMessageLambda = replyMessageLambda
|
||||
}
|
||||
val fakeMatrixRoom = FakeMatrixRoom(liveTimeline = timeline)
|
||||
val presenter = createPresenter(
|
||||
this,
|
||||
fakeMatrixRoom,
|
||||
@@ -356,7 +391,13 @@ class MessageComposerPresenterTest {
|
||||
state.eventSink.invoke(MessageComposerEvents.SendMessage(A_REPLY.toMessage()))
|
||||
val messageSentState = awaitItem()
|
||||
assertThat(messageSentState.richTextEditorState.messageHtml).isEqualTo("")
|
||||
assertThat(fakeMatrixRoom.replyMessageParameter).isEqualTo(A_REPLY to A_REPLY)
|
||||
|
||||
advanceUntilIdle()
|
||||
|
||||
assert(replyMessageLambda)
|
||||
.isCalledOnce()
|
||||
.with(any(),value(A_REPLY),value(A_REPLY),any())
|
||||
|
||||
assertThat(analyticsService.capturedEvents).containsExactly(
|
||||
Composer(
|
||||
inThread = false,
|
||||
@@ -832,7 +873,17 @@ class MessageComposerPresenterTest {
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@Test
|
||||
fun `present - send messages with intentional mentions`() = runTest {
|
||||
val room = FakeMatrixRoom()
|
||||
val replyMessageLambda = lambdaRecorder {_: EventId, _: String, _: String?, _:List<Mention> ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val editMessageLambda = lambdaRecorder { _: EventId?, _: TransactionId?, _: String, _: String?, _: List<Mention> ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
val timeline = FakeTimeline().apply {
|
||||
this.replyMessageLambda = replyMessageLambda
|
||||
this.editMessageLambda = editMessageLambda
|
||||
}
|
||||
val room = FakeMatrixRoom(liveTimeline = timeline)
|
||||
val presenter = createPresenter(room = room, coroutineScope = this)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
@@ -867,7 +918,9 @@ class MessageComposerPresenterTest {
|
||||
initialState.eventSink(MessageComposerEvents.SendMessage(A_MESSAGE.toMessage()))
|
||||
advanceUntilIdle()
|
||||
|
||||
assertThat(room.sendMessageMentions).isEqualTo(listOf(Mention.User(A_USER_ID_2)))
|
||||
assert(replyMessageLambda)
|
||||
.isCalledOnce()
|
||||
.with(any(), any(), any(), value(listOf(Mention.User(A_USER_ID_2))))
|
||||
|
||||
// Check intentional mentions on edit message
|
||||
skipItems(1)
|
||||
@@ -883,7 +936,10 @@ class MessageComposerPresenterTest {
|
||||
initialState.eventSink(MessageComposerEvents.SendMessage(A_MESSAGE.toMessage()))
|
||||
advanceUntilIdle()
|
||||
|
||||
assertThat(room.sendMessageMentions).isEqualTo(listOf(Mention.User(A_USER_ID_3)))
|
||||
assert(editMessageLambda)
|
||||
.isCalledOnce()
|
||||
.with(any(), any(), any(), any(), value(listOf(Mention.User(A_USER_ID_3))))
|
||||
|
||||
|
||||
skipItems(1)
|
||||
}
|
||||
|
||||
@@ -20,16 +20,17 @@ import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.poll.PollAnswer
|
||||
import io.element.android.libraries.matrix.api.timeline.MatrixTimelineItem
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.matrix.test.timeline.aPollContent
|
||||
import io.element.android.libraries.matrix.test.timeline.anEventTimelineItem
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
|
||||
fun aPollTimeline(
|
||||
fun aPollTimelineItems(
|
||||
polls: Map<EventId, PollContent> = emptyMap(),
|
||||
): FakeTimeline {
|
||||
return FakeTimeline(
|
||||
initialTimelineItems = polls.map { entry ->
|
||||
): Flow<List<MatrixTimelineItem>> {
|
||||
return flowOf(
|
||||
polls.map { entry ->
|
||||
MatrixTimelineItem.Event(
|
||||
entry.key.value,
|
||||
anEventTimelineItem(
|
||||
|
||||
@@ -25,33 +25,42 @@ import im.vector.app.features.analytics.plan.Composer
|
||||
import im.vector.app.features.analytics.plan.PollCreation
|
||||
import io.element.android.features.messages.test.FakeMessageComposerContext
|
||||
import io.element.android.features.poll.api.create.CreatePollMode
|
||||
import io.element.android.features.poll.impl.aPollTimeline
|
||||
import io.element.android.features.poll.impl.aPollTimelineItems
|
||||
import io.element.android.features.poll.impl.anOngoingPollContent
|
||||
import io.element.android.features.poll.impl.data.PollRepository
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.poll.PollKind
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.LiveTimelineProvider
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.room.SavePollInvocation
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.services.analytics.test.FakeAnalyticsService
|
||||
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.lambda.value
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.test.advanceUntilIdle
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
|
||||
class CreatePollPresenterTest {
|
||||
@OptIn(ExperimentalCoroutinesApi::class) class CreatePollPresenterTest {
|
||||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
|
||||
private val pollEventId = AN_EVENT_ID
|
||||
private var navUpInvocationsCount = 0
|
||||
private val existingPoll = anOngoingPollContent()
|
||||
private val timeline = FakeTimeline(
|
||||
timelineItems = aPollTimelineItems(mapOf(pollEventId to existingPoll))
|
||||
)
|
||||
private val fakeMatrixRoom = FakeMatrixRoom(
|
||||
liveTimeline = aPollTimeline(
|
||||
mapOf(pollEventId to existingPoll)
|
||||
)
|
||||
liveTimeline = timeline
|
||||
)
|
||||
private val fakeAnalyticsService = FakeAnalyticsService()
|
||||
private val fakeMessageComposerContext = FakeMessageComposerContext()
|
||||
@@ -80,7 +89,7 @@ class CreatePollPresenterTest {
|
||||
@Test
|
||||
fun `in edit mode, if poll doesn't exist, error is tracked and screen is closed`() = runTest {
|
||||
val room = FakeMatrixRoom(
|
||||
liveTimeline = aPollTimeline()
|
||||
liveTimeline = FakeTimeline()
|
||||
)
|
||||
val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(AN_EVENT_ID), room = room)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
@@ -180,6 +189,12 @@ class CreatePollPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `edit poll sends a poll edit event`() = runTest {
|
||||
val editPollLambda = lambdaRecorder { _: EventId, _: String, _: List<String>, _: Int, _: PollKind ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
timeline.apply {
|
||||
this.editPollLambda = editPollLambda
|
||||
}
|
||||
val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(pollEventId))
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
@@ -201,16 +216,18 @@ class CreatePollPresenterTest {
|
||||
).apply {
|
||||
eventSink(CreatePollEvents.Save)
|
||||
}
|
||||
delay(1) // Wait for the coroutine to finish
|
||||
assertThat(fakeMatrixRoom.editPollInvocations.size).isEqualTo(1)
|
||||
assertThat(fakeMatrixRoom.editPollInvocations.last()).isEqualTo(
|
||||
SavePollInvocation(
|
||||
question = "Changed question",
|
||||
answers = listOf("Changed answer 1", "Changed answer 2", "Maybe"),
|
||||
maxSelections = 1,
|
||||
pollKind = PollKind.Disclosed
|
||||
advanceUntilIdle() // Wait for the coroutine to finish
|
||||
|
||||
assert(editPollLambda)
|
||||
.isCalledOnce()
|
||||
.with(
|
||||
value(pollEventId),
|
||||
value("Changed question"),
|
||||
value(listOf("Changed answer 1", "Changed answer 2", "Maybe")),
|
||||
value(1),
|
||||
value(PollKind.Disclosed)
|
||||
)
|
||||
)
|
||||
|
||||
assertThat(fakeAnalyticsService.capturedEvents.size).isEqualTo(2)
|
||||
assertThat(fakeAnalyticsService.capturedEvents[0]).isEqualTo(
|
||||
Composer(
|
||||
@@ -233,6 +250,12 @@ class CreatePollPresenterTest {
|
||||
@Test
|
||||
fun `when edit poll fails, error is tracked`() = runTest {
|
||||
val error = Exception("cause")
|
||||
val editPollLambda = lambdaRecorder { _: EventId, _: String, _: List<String>, _: Int, _: PollKind ->
|
||||
Result.failure<Unit>(error)
|
||||
}
|
||||
timeline.apply {
|
||||
this.editPollLambda = editPollLambda
|
||||
}
|
||||
fakeMatrixRoom.givenEditPollResult(Result.failure(error))
|
||||
val presenter = createCreatePollPresenter(mode = CreatePollMode.EditPoll(pollEventId))
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
@@ -241,8 +264,8 @@ class CreatePollPresenterTest {
|
||||
awaitDefaultItem()
|
||||
awaitPollLoaded().eventSink(CreatePollEvents.SetAnswer(0, "A"))
|
||||
awaitPollLoaded(newAnswer1 = "A").eventSink(CreatePollEvents.Save)
|
||||
delay(1) // Wait for the coroutine to finish
|
||||
assertThat(fakeMatrixRoom.editPollInvocations).hasSize(1)
|
||||
advanceUntilIdle() // Wait for the coroutine to finish
|
||||
assert(editPollLambda).isCalledOnce()
|
||||
assertThat(fakeAnalyticsService.capturedEvents).isEmpty()
|
||||
assertThat(fakeAnalyticsService.trackedErrors).hasSize(1)
|
||||
assertThat(fakeAnalyticsService.trackedErrors).containsExactly(
|
||||
@@ -497,22 +520,22 @@ class CreatePollPresenterTest {
|
||||
newAnswer1: String? = null,
|
||||
newAnswer2: String? = null,
|
||||
) =
|
||||
awaitItem().apply {
|
||||
assertThat(canSave).isTrue()
|
||||
assertThat(canAddAnswer).isTrue()
|
||||
assertThat(question).isEqualTo(newQuestion ?: existingPoll.question)
|
||||
assertThat(answers).isEqualTo(existingPoll.expectedAnswersState().toMutableList().apply {
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.canSave).isTrue()
|
||||
assertThat(state.canAddAnswer).isTrue()
|
||||
assertThat(state.question).isEqualTo(newQuestion ?: existingPoll.question)
|
||||
assertThat(state.answers).isEqualTo(existingPoll.expectedAnswersState().toMutableList().apply {
|
||||
newAnswer1?.let { this[0] = Answer(it, true) }
|
||||
newAnswer2?.let { this[1] = Answer(it, true) }
|
||||
})
|
||||
assertThat(pollKind).isEqualTo(existingPoll.kind)
|
||||
assertThat(state.pollKind).isEqualTo(existingPoll.kind)
|
||||
}
|
||||
|
||||
private fun createCreatePollPresenter(
|
||||
mode: CreatePollMode = CreatePollMode.NewPoll,
|
||||
room: MatrixRoom = fakeMatrixRoom,
|
||||
): CreatePollPresenter = CreatePollPresenter(
|
||||
repository = PollRepository(room),
|
||||
repository = PollRepository(room, LiveTimelineProvider(room)),
|
||||
analyticsService = fakeAnalyticsService,
|
||||
messageComposerContext = fakeMessageComposerContext,
|
||||
navigateUp = { navUpInvocationsCount++ },
|
||||
|
||||
@@ -22,7 +22,7 @@ import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.poll.api.actions.EndPollAction
|
||||
import io.element.android.features.poll.api.actions.SendPollResponseAction
|
||||
import io.element.android.features.poll.impl.aPollTimeline
|
||||
import io.element.android.features.poll.impl.aPollTimelineItems
|
||||
import io.element.android.features.poll.impl.anEndedPollContent
|
||||
import io.element.android.features.poll.impl.anOngoingPollContent
|
||||
import io.element.android.features.poll.impl.history.model.PollHistoryFilter
|
||||
@@ -32,14 +32,20 @@ import io.element.android.features.poll.test.actions.FakeEndPollAction
|
||||
import io.element.android.features.poll.test.actions.FakeSendPollResponseAction
|
||||
import io.element.android.libraries.dateformatter.test.FakeDaySeparatorFormatter
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.lambda.assert
|
||||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.tests.testutils.testCoroutineDispatchers
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.getAndUpdate
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
@@ -50,11 +56,14 @@ class PollHistoryPresenterTest {
|
||||
@get:Rule
|
||||
val warmUpRule = WarmUpRule()
|
||||
|
||||
private val timeline = aPollTimeline(
|
||||
polls = mapOf(
|
||||
private val backwardPaginationStatus = MutableStateFlow(Timeline.PaginationStatus(isPaginating = false, hasMoreToLoad = true))
|
||||
private val timeline = FakeTimeline(
|
||||
timelineItems = aPollTimelineItems(
|
||||
mapOf(
|
||||
AN_EVENT_ID to anOngoingPollContent(),
|
||||
AN_EVENT_ID_2 to anEndedPollContent()
|
||||
)
|
||||
)),
|
||||
backwardPaginationStatus = backwardPaginationStatus
|
||||
)
|
||||
private val room = FakeMatrixRoom(
|
||||
liveTimeline = timeline
|
||||
@@ -66,7 +75,6 @@ class PollHistoryPresenterTest {
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
skipItems(1)
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.activeFilter).isEqualTo(PollHistoryFilter.ONGOING)
|
||||
assertThat(state.pollHistoryItems.size).isEqualTo(0)
|
||||
@@ -127,26 +135,30 @@ class PollHistoryPresenterTest {
|
||||
|
||||
@Test
|
||||
fun `present - load more scenario`() = runTest {
|
||||
val paginateLambda = lambdaRecorder{ _: Timeline.PaginationDirection ->
|
||||
Result.success(false)
|
||||
}
|
||||
timeline.apply {
|
||||
this.paginateLambda = paginateLambda
|
||||
}
|
||||
val presenter = createPollHistoryPresenter(room = room)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
skipItems(2)
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.pollHistoryItems.size).isEqualTo(2)
|
||||
}
|
||||
timeline.updatePaginationState {
|
||||
copy(isBackPaginating = false)
|
||||
}
|
||||
skipItems(1)
|
||||
val loadedState = awaitItem()
|
||||
assertThat(loadedState.isLoading).isFalse()
|
||||
loadedState.eventSink(PollHistoryEvents.LoadMore)
|
||||
backwardPaginationStatus.getAndUpdate { it.copy(isPaginating = true) }
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.isLoading).isTrue()
|
||||
}
|
||||
backwardPaginationStatus.getAndUpdate { it.copy(isPaginating = false) }
|
||||
awaitItem().also { state ->
|
||||
assertThat(state.isLoading).isFalse()
|
||||
}
|
||||
// Called once by the initial load and once by the load more event
|
||||
assert(paginateLambda).isCalledExactly(2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ import io.element.android.libraries.indicator.impl.DefaultIndicatorService
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.timeline.Timeline
|
||||
import io.element.android.libraries.preferences.impl.store.DefaultSessionPreferencesStore
|
||||
import io.element.android.libraries.push.test.notifications.FakeNotificationDrawerManager
|
||||
import io.element.android.services.analytics.noop.NoopAnalyticsService
|
||||
@@ -146,7 +147,7 @@ class RoomListScreen(
|
||||
Singleton.appScope.launch {
|
||||
withContext(coroutineDispatchers.io) {
|
||||
matrixClient.getRoom(roomId)!!.use { room ->
|
||||
room.timeline.paginateBackwards(20, 50)
|
||||
room.liveTimeline.paginate(Timeline.PaginationDirection.BACKWARDS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,13 @@ inline fun <reified T1, reified T2, reified T3, reified T4, reified R> lambdaRec
|
||||
return LambdaFourParamsRecorder(ensureNeverCalled, block)
|
||||
}
|
||||
|
||||
inline fun <reified T1, reified T2, reified T3, reified T4, reified T5, reified R> lambdaRecorder(
|
||||
ensureNeverCalled: Boolean = false,
|
||||
noinline block: (T1, T2, T3, T4, T5) -> R
|
||||
): LambdaFiveParamsRecorder<T1, T2, T3, T4, T5, R> {
|
||||
return LambdaFiveParamsRecorder(ensureNeverCalled, block)
|
||||
}
|
||||
|
||||
class LambdaNoParamRecorder<out R>(ensureNeverCalled: Boolean, val block: () -> R) : LambdaRecorder(ensureNeverCalled), () -> R {
|
||||
override fun invoke(): R {
|
||||
onInvoke()
|
||||
@@ -109,3 +116,12 @@ class LambdaFourParamsRecorder<in T1, in T2, in T3, in T4, out R>(ensureNeverCal
|
||||
return block(p1, p2, p3, p4)
|
||||
}
|
||||
}
|
||||
|
||||
class LambdaFiveParamsRecorder<in T1, in T2, in T3, in T4, in T5, out R>(ensureNeverCalled: Boolean, val block: (T1, T2, T3, T4, T5) -> R) : LambdaRecorder(
|
||||
ensureNeverCalled
|
||||
), (T1, T2, T3, T4, T5) -> R {
|
||||
override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4, p5: T5): R {
|
||||
onInvoke(p1, p2, p3, p4, p5)
|
||||
return block(p1, p2, p3, p4, p5)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user