Browse Source

Add test for `MessageComposerPresenter`

kittykat-patch-1
Benoit Marty 2 years ago
parent
commit
f736b48a92
  1. 5
      features/messages/src/main/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenter.kt
  2. 190
      features/messages/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt
  3. 4
      features/roomlist/src/test/kotlin/io/element/android/features/roomlist/RoomListPresenterTests.kt
  4. 2
      libraries/core/src/main/kotlin/io/element/android/libraries/core/data/StableCharSequence.kt
  5. 4
      libraries/matrixtest/src/main/kotlin/io/element/android/libraries/matrixtest/room/FakeMatrixRoom.kt
  6. 6
      libraries/matrixtest/src/main/kotlin/io/element/android/libraries/matrixtest/room/RoomSummaryFixture.kt
  7. 1
      libraries/matrixtest/src/main/kotlin/io/element/android/libraries/matrixtest/timeline/FakeMatrixTimeline.kt

5
features/messages/src/main/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenter.kt

@ -59,7 +59,10 @@ class MessageComposerPresenter @Inject constructor(
when (event) { when (event) {
MessageComposerEvents.ToggleFullScreenState -> isFullScreen.value = !isFullScreen.value MessageComposerEvents.ToggleFullScreenState -> isFullScreen.value = !isFullScreen.value
is MessageComposerEvents.UpdateText -> text.value = event.text.toStableCharSequence() is MessageComposerEvents.UpdateText -> text.value = event.text.toStableCharSequence()
MessageComposerEvents.CloseSpecialMode -> composerMode.setToNormal() MessageComposerEvents.CloseSpecialMode -> {
text.value = "".toStableCharSequence()
composerMode.setToNormal()
}
is MessageComposerEvents.SendMessage -> appCoroutineScope.sendMessage(event.message, composerMode, text) is MessageComposerEvents.SendMessage -> appCoroutineScope.sendMessage(event.message, composerMode, text)
is MessageComposerEvents.SetMode -> composerMode.value = event.composerMode is MessageComposerEvents.SetMode -> composerMode.value = event.composerMode
} }

190
features/messages/src/test/kotlin/io/element/android/features/messages/textcomposer/MessageComposerPresenterTest.kt

@ -0,0 +1,190 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:OptIn(ExperimentalCoroutinesApi::class)
package io.element.android.features.messages.textcomposer
import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow
import app.cash.turbine.ReceiveTurbine
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.data.StableCharSequence
import io.element.android.libraries.matrixtest.core.A_ROOM_ID
import io.element.android.libraries.matrixtest.room.A_MESSAGE
import io.element.android.libraries.matrixtest.room.FakeMatrixRoom
import io.element.android.libraries.matrixtest.timeline.AN_EVENT_ID
import io.element.android.libraries.matrixtest.timeline.A_SENDER_NAME
import io.element.android.libraries.textcomposer.MessageComposerMode
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
class MessageComposerPresenterTest {
@Test
fun `present - initial state`() = runTest {
val presenter = MessageComposerPresenter(
this,
FakeMatrixRoom(A_ROOM_ID)
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
assertThat(initialState.isFullScreen).isFalse()
assertThat(initialState.text).isEqualTo(StableCharSequence(""))
assertThat(initialState.mode).isEqualTo(MessageComposerMode.Normal(""))
assertThat(initialState.isSendButtonVisible).isFalse()
}
}
@Test
fun `present - toggle fullscreen`() = runTest {
val presenter = MessageComposerPresenter(
this,
FakeMatrixRoom(A_ROOM_ID)
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
initialState.eventSink.invoke(MessageComposerEvents.ToggleFullScreenState)
val fullscreenState = awaitItem()
assertThat(fullscreenState.isFullScreen).isTrue()
fullscreenState.eventSink.invoke(MessageComposerEvents.ToggleFullScreenState)
val notFullscreenState = awaitItem()
assertThat(notFullscreenState.isFullScreen).isFalse()
}
}
@Test
fun `present - change message`() = runTest {
val presenter = MessageComposerPresenter(
this,
FakeMatrixRoom(A_ROOM_ID)
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
initialState.eventSink.invoke(MessageComposerEvents.UpdateText(A_MESSAGE))
val withMessageState = awaitItem()
assertThat(withMessageState.text).isEqualTo(StableCharSequence(A_MESSAGE))
assertThat(withMessageState.isSendButtonVisible).isTrue()
withMessageState.eventSink.invoke(MessageComposerEvents.UpdateText(""))
val withEmptyMessageState = awaitItem()
assertThat(withEmptyMessageState.text).isEqualTo(StableCharSequence(""))
assertThat(withEmptyMessageState.isSendButtonVisible).isFalse()
}
}
@Test
fun `present - change mode to edit`() = runTest {
val presenter = MessageComposerPresenter(
this,
FakeMatrixRoom(A_ROOM_ID)
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
var state = awaitItem()
val mode = anEditMode()
state.eventSink.invoke(MessageComposerEvents.SetMode(mode))
state = awaitItem()
assertThat(state.mode).isEqualTo(mode)
state = awaitItem()
assertThat(state.text).isEqualTo(StableCharSequence(A_MESSAGE))
assertThat(state.isSendButtonVisible).isTrue()
backToNormalMode(state, skipCount = 1)
}
}
private suspend fun ReceiveTurbine<MessageComposerState>.backToNormalMode(state: MessageComposerState, skipCount: Int = 0) {
state.eventSink.invoke(MessageComposerEvents.CloseSpecialMode)
skipItems(skipCount)
val normalState = awaitItem()
assertThat(normalState.mode).isEqualTo(MessageComposerMode.Normal(""))
assertThat(normalState.text).isEqualTo(StableCharSequence(""))
assertThat(normalState.isSendButtonVisible).isFalse()
}
@Test
fun `present - change mode to reply`() = runTest {
val presenter = MessageComposerPresenter(
this,
FakeMatrixRoom(A_ROOM_ID)
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
var state = awaitItem()
val mode = aReplyMode()
state.eventSink.invoke(MessageComposerEvents.SetMode(mode))
state = awaitItem()
assertThat(state.mode).isEqualTo(mode)
assertThat(state.text).isEqualTo(StableCharSequence(""))
assertThat(state.isSendButtonVisible).isFalse()
backToNormalMode(state)
}
}
@Test
fun `present - change mode to quote`() = runTest {
val presenter = MessageComposerPresenter(
this,
FakeMatrixRoom(A_ROOM_ID)
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
var state = awaitItem()
val mode = aQuoteMode()
state.eventSink.invoke(MessageComposerEvents.SetMode(mode))
state = awaitItem()
assertThat(state.mode).isEqualTo(mode)
assertThat(state.text).isEqualTo(StableCharSequence(""))
assertThat(state.isSendButtonVisible).isFalse()
backToNormalMode(state)
}
}
@Test
fun `present - send message`() = runTest {
val presenter = MessageComposerPresenter(
this,
FakeMatrixRoom(A_ROOM_ID)
)
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
initialState.eventSink.invoke(MessageComposerEvents.UpdateText(A_MESSAGE))
val withMessageState = awaitItem()
assertThat(withMessageState.text).isEqualTo(StableCharSequence(A_MESSAGE))
assertThat(withMessageState.isSendButtonVisible).isTrue()
withMessageState.eventSink.invoke(MessageComposerEvents.SendMessage(A_MESSAGE))
val messageSentState = awaitItem()
assertThat(messageSentState.text).isEqualTo(StableCharSequence(""))
assertThat(messageSentState.isSendButtonVisible).isFalse()
}
}
}
fun anEditMode() = MessageComposerMode.Edit(AN_EVENT_ID, A_MESSAGE)
fun aReplyMode() = MessageComposerMode.Reply(A_SENDER_NAME, AN_EVENT_ID, A_MESSAGE)
fun aQuoteMode() = MessageComposerMode.Quote(AN_EVENT_ID, A_MESSAGE)

4
features/roomlist/src/test/kotlin/io/element/android/features/roomlist/RoomListPresenterTests.kt

@ -30,7 +30,7 @@ import io.element.android.libraries.matrix.core.SessionId
import io.element.android.libraries.matrixtest.FakeMatrixClient import io.element.android.libraries.matrixtest.FakeMatrixClient
import io.element.android.libraries.matrixtest.core.A_ROOM_ID import io.element.android.libraries.matrixtest.core.A_ROOM_ID
import io.element.android.libraries.matrixtest.core.A_ROOM_ID_VALUE import io.element.android.libraries.matrixtest.core.A_ROOM_ID_VALUE
import io.element.android.libraries.matrixtest.room.A_LAST_MESSAGE import io.element.android.libraries.matrixtest.room.A_MESSAGE
import io.element.android.libraries.matrixtest.room.A_ROOM_NAME import io.element.android.libraries.matrixtest.room.A_ROOM_NAME
import io.element.android.libraries.matrixtest.room.FakeRoomSummaryDataSource import io.element.android.libraries.matrixtest.room.FakeRoomSummaryDataSource
import io.element.android.libraries.matrixtest.room.aRoomSummaryFilled import io.element.android.libraries.matrixtest.room.aRoomSummaryFilled
@ -187,7 +187,7 @@ private val aRoomListRoomSummary = RoomListRoomSummary(
name = A_ROOM_NAME, name = A_ROOM_NAME,
hasUnread = true, hasUnread = true,
timestamp = A_FORMATTED_DATE, timestamp = A_FORMATTED_DATE,
lastMessage = A_LAST_MESSAGE, lastMessage = A_MESSAGE,
avatarData = AvatarData(name = A_ROOM_NAME), avatarData = AvatarData(name = A_ROOM_NAME),
isPlaceholder = false, isPlaceholder = false,
) )

2
libraries/core/src/main/kotlin/io/element/android/libraries/core/data/StableCharSequence.kt

@ -24,6 +24,8 @@ class StableCharSequence(val charSequence: CharSequence) {
override fun hashCode() = hash override fun hashCode() = hash
override fun equals(other: Any?) = other is StableCharSequence && other.hash == hash override fun equals(other: Any?) = other is StableCharSequence && other.hash == hash
override fun toString(): String = "StableCharSequence(\"$charSequence\")"
} }
fun CharSequence.toStableCharSequence() = StableCharSequence(this) fun CharSequence.toStableCharSequence() = StableCharSequence(this)

4
libraries/matrixtest/src/main/kotlin/io/element/android/libraries/matrixtest/room/FakeMatrixRoom.kt

@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.core.RoomId
import io.element.android.libraries.matrix.room.MatrixRoom import io.element.android.libraries.matrix.room.MatrixRoom
import io.element.android.libraries.matrix.timeline.MatrixTimeline import io.element.android.libraries.matrix.timeline.MatrixTimeline
import io.element.android.libraries.matrixtest.timeline.FakeMatrixTimeline import io.element.android.libraries.matrixtest.timeline.FakeMatrixTimeline
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
@ -51,7 +52,8 @@ class FakeMatrixRoom(
} }
override suspend fun sendMessage(message: String): Result<Unit> { override suspend fun sendMessage(message: String): Result<Unit> {
TODO("Not yet implemented") delay(100)
return Result.success(Unit)
} }
override suspend fun editMessage(originalEventId: EventId, message: String): Result<Unit> { override suspend fun editMessage(originalEventId: EventId, message: String): Result<Unit> {

6
libraries/matrixtest/src/main/kotlin/io/element/android/libraries/matrixtest/room/RoomSummaryFixture.kt

@ -22,14 +22,14 @@ import io.element.android.libraries.matrix.room.RoomSummaryDetails
import io.element.android.libraries.matrixtest.core.A_ROOM_ID import io.element.android.libraries.matrixtest.core.A_ROOM_ID
const val A_ROOM_NAME = "aRoomName" const val A_ROOM_NAME = "aRoomName"
const val A_LAST_MESSAGE = "Last message" const val A_MESSAGE = "Hello world!"
fun aRoomSummaryFilled( fun aRoomSummaryFilled(
roomId: RoomId = A_ROOM_ID, roomId: RoomId = A_ROOM_ID,
name: String = A_ROOM_NAME, name: String = A_ROOM_NAME,
isDirect: Boolean = false, isDirect: Boolean = false,
avatarURLString: String? = null, avatarURLString: String? = null,
lastMessage: CharSequence? = A_LAST_MESSAGE, lastMessage: CharSequence? = A_MESSAGE,
lastMessageTimestamp: Long? = null, lastMessageTimestamp: Long? = null,
unreadNotificationCount: Int = 2, unreadNotificationCount: Int = 2,
) = RoomSummary.Filled( ) = RoomSummary.Filled(
@ -49,7 +49,7 @@ fun aRoomSummaryDetail(
name: String = A_ROOM_NAME, name: String = A_ROOM_NAME,
isDirect: Boolean = false, isDirect: Boolean = false,
avatarURLString: String? = null, avatarURLString: String? = null,
lastMessage: CharSequence? = A_LAST_MESSAGE, lastMessage: CharSequence? = A_MESSAGE,
lastMessageTimestamp: Long? = null, lastMessageTimestamp: Long? = null,
unreadNotificationCount: Int = 2, unreadNotificationCount: Int = 2,
) = RoomSummaryDetails( ) = RoomSummaryDetails(

1
libraries/matrixtest/src/main/kotlin/io/element/android/libraries/matrixtest/timeline/FakeMatrixTimeline.kt

@ -24,6 +24,7 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
import org.matrix.rustcomponents.sdk.TimelineListener import org.matrix.rustcomponents.sdk.TimelineListener
const val A_SENDER_NAME = "Alice"
const val AN_EVENT_ID_VALUE = "!anEventId" const val AN_EVENT_ID_VALUE = "!anEventId"
val AN_EVENT_ID = EventId(AN_EVENT_ID_VALUE) val AN_EVENT_ID = EventId(AN_EVENT_ID_VALUE)

Loading…
Cancel
Save