Browse Source

Room navigation : fix tests on invite after the refactoring

pull/2695/head
ganfra 5 months ago
parent
commit
fbb92f0c9a
  1. 10
      appnav/src/test/kotlin/io/element/android/appnav/JoinRoomLoadedFlowNodeTest.kt
  2. 15
      features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/di/InviteModule.kt
  3. 4
      features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListPresenter.kt
  4. 16
      features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt
  5. 8
      features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteView.kt
  6. 2
      features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteViewWrapper.kt
  7. 10
      features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/InternalAcceptDeclineInviteEvents.kt
  8. 257
      features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/invitelist/InviteListPresenterTests.kt
  9. 248
      features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt
  10. 4
      features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt
  11. 4
      features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt
  12. 7
      features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/JoinRoomModule.kt
  13. 4
      features/leaveroom/impl/src/test/kotlin/io/element/android/features/leaveroom/impl/LeaveRoomPresenterImplTest.kt
  14. 2
      features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/actions/AndroidLocationActionsTest.kt
  15. 39
      features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryView.kt
  16. 32
      features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryViewTest.kt
  17. 1
      libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt
  18. 12
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt
  19. 11
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt
  20. 3
      libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/SimplePagedRoomList.kt
  21. 5
      libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt

10
appnav/src/test/kotlin/io/element/android/appnav/RoomFlowNodeTest.kt → appnav/src/test/kotlin/io/element/android/appnav/JoinRoomLoadedFlowNodeTest.kt

@ -32,7 +32,6 @@ import io.element.android.features.messages.api.MessagesEntryPoint @@ -32,7 +32,6 @@ import io.element.android.features.messages.api.MessagesEntryPoint
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
import io.element.android.libraries.architecture.childNode
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
@ -41,7 +40,7 @@ import kotlinx.coroutines.test.runTest @@ -41,7 +40,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
class RoomFlowNodeTest {
class JoinRoomLoadedFlowNodeTest {
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
@ -88,7 +87,7 @@ class RoomFlowNodeTest { @@ -88,7 +87,7 @@ class RoomFlowNodeTest {
}
}
private fun aRoomFlowNode(
private fun createJoinedRoomLoadedFlowNode(
plugins: List<Plugin>,
messagesEntryPoint: MessagesEntryPoint = FakeMessagesEntryPoint(),
roomDetailsEntryPoint: RoomDetailsEntryPoint = FakeRoomDetailsEntryPoint(),
@ -99,7 +98,6 @@ class RoomFlowNodeTest { @@ -99,7 +98,6 @@ class RoomFlowNodeTest {
messagesEntryPoint = messagesEntryPoint,
roomDetailsEntryPoint = roomDetailsEntryPoint,
appNavigationStateService = FakeAppNavigationStateService(),
roomMembershipObserver = RoomMembershipObserver(),
appCoroutineScope = coroutineScope,
roomComponentFactory = FakeRoomComponentFactory(),
matrixClient = FakeMatrixClient(),
@ -111,7 +109,7 @@ class RoomFlowNodeTest { @@ -111,7 +109,7 @@ class RoomFlowNodeTest {
val room = FakeMatrixRoom()
val fakeMessagesEntryPoint = FakeMessagesEntryPoint()
val inputs = JoinedRoomLoadedFlowNode.Inputs(room)
val roomFlowNode = aRoomFlowNode(
val roomFlowNode = createJoinedRoomLoadedFlowNode(
plugins = listOf(inputs),
messagesEntryPoint = fakeMessagesEntryPoint,
coroutineScope = this
@ -133,7 +131,7 @@ class RoomFlowNodeTest { @@ -133,7 +131,7 @@ class RoomFlowNodeTest {
val fakeMessagesEntryPoint = FakeMessagesEntryPoint()
val fakeRoomDetailsEntryPoint = FakeRoomDetailsEntryPoint()
val inputs = JoinedRoomLoadedFlowNode.Inputs(room)
val roomFlowNode = aRoomFlowNode(
val roomFlowNode = createJoinedRoomLoadedFlowNode(
plugins = listOf(inputs),
messagesEntryPoint = fakeMessagesEntryPoint,
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,

15
features/invite/api/src/main/kotlin/io/element/android/features/invite/api/response/AcceptDeclineInvitePresenter.kt → features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/di/InviteModule.kt

@ -14,8 +14,19 @@ @@ -14,8 +14,19 @@
* limitations under the License.
*/
package io.element.android.features.invite.api.response
package io.element.android.features.invite.impl.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Binds
import dagger.Module
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.invite.impl.response.AcceptDeclineInvitePresenter
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.SessionScope
interface AcceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>
@ContributesTo(SessionScope::class)
@Module
interface InviteModule {
@Binds
fun bindAcceptDeclinePresenter(presenter: AcceptDeclineInvitePresenter): Presenter<AcceptDeclineInviteState>
}

4
features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/invitelist/InviteListPresenter.kt

@ -25,7 +25,7 @@ import androidx.compose.runtime.remember @@ -25,7 +25,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import io.element.android.features.invite.api.SeenInvitesStore
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.response.AcceptDeclineInvitePresenter
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.invite.api.response.InviteData
import io.element.android.features.invite.impl.model.InviteListInviteSummary
import io.element.android.features.invite.impl.model.InviteSender
@ -42,7 +42,7 @@ import javax.inject.Inject @@ -42,7 +42,7 @@ import javax.inject.Inject
class InviteListPresenter @Inject constructor(
private val client: MatrixClient,
private val store: SeenInvitesStore,
private val acceptDeclineInvitePresenter: AcceptDeclineInvitePresenter,
private val acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
) : Presenter<InviteListState> {
@Composable
override fun present(): InviteListState {

16
features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInvitePresenter.kt → features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenter.kt

@ -26,10 +26,10 @@ import androidx.compose.runtime.setValue @@ -26,10 +26,10 @@ import androidx.compose.runtime.setValue
import com.squareup.anvil.annotations.ContributesBinding
import im.vector.app.features.analytics.plan.JoinedRoom
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.response.AcceptDeclineInvitePresenter
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.invite.api.response.InviteData
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.architecture.runCatchingUpdatingState
import io.element.android.libraries.architecture.runUpdatingState
import io.element.android.libraries.di.SessionScope
@ -44,12 +44,11 @@ import java.util.Optional @@ -44,12 +44,11 @@ import java.util.Optional
import javax.inject.Inject
import kotlin.jvm.optionals.getOrNull
@ContributesBinding(SessionScope::class)
class DefaultAcceptDeclineInvitePresenter @Inject constructor(
class AcceptDeclineInvitePresenter @Inject constructor(
private val client: MatrixClient,
private val analyticsService: AnalyticsService,
private val notificationDrawerManager: NotificationDrawerManager,
) : AcceptDeclineInvitePresenter {
) : Presenter<AcceptDeclineInviteState> {
@Composable
override fun present(): AcceptDeclineInviteState {
@ -66,6 +65,7 @@ class DefaultAcceptDeclineInvitePresenter @Inject constructor( @@ -66,6 +65,7 @@ class DefaultAcceptDeclineInvitePresenter @Inject constructor(
is AcceptDeclineInviteEvents.AcceptInvite -> {
currentInvite = Optional.of(event.invite)
localCoroutineScope.acceptInvite(event.invite.roomId, acceptedAction)
currentInvite = Optional.empty()
}
is AcceptDeclineInviteEvents.DeclineInvite -> {
@ -73,7 +73,7 @@ class DefaultAcceptDeclineInvitePresenter @Inject constructor( @@ -73,7 +73,7 @@ class DefaultAcceptDeclineInvitePresenter @Inject constructor(
declinedAction.value = AsyncAction.Confirming
}
is DefaultAcceptDeclineInviteEvents.ConfirmDeclineInvite -> {
is InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite -> {
declinedAction.value = AsyncAction.Uninitialized
currentInvite.getOrNull()?.let {
localCoroutineScope.declineInvite(it.roomId, declinedAction)
@ -81,16 +81,16 @@ class DefaultAcceptDeclineInvitePresenter @Inject constructor( @@ -81,16 +81,16 @@ class DefaultAcceptDeclineInvitePresenter @Inject constructor(
currentInvite = Optional.empty()
}
is DefaultAcceptDeclineInviteEvents.CancelDeclineInvite -> {
is InternalAcceptDeclineInviteEvents.CancelDeclineInvite -> {
currentInvite = Optional.empty()
declinedAction.value = AsyncAction.Uninitialized
}
is DefaultAcceptDeclineInviteEvents.DismissAcceptError -> {
is InternalAcceptDeclineInviteEvents.DismissAcceptError -> {
acceptedAction.value = AsyncAction.Uninitialized
}
is DefaultAcceptDeclineInviteEvents.DismissDeclineError -> {
is InternalAcceptDeclineInviteEvents.DismissDeclineError -> {
declinedAction.value = AsyncAction.Uninitialized
}
}

8
features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteView.kt

@ -45,14 +45,14 @@ fun AcceptDeclineInviteView( @@ -45,14 +45,14 @@ fun AcceptDeclineInviteView(
async = state.acceptAction,
onSuccess = onInviteAccepted,
onErrorDismiss = {
state.eventSink(DefaultAcceptDeclineInviteEvents.DismissAcceptError)
state.eventSink(InternalAcceptDeclineInviteEvents.DismissAcceptError)
},
)
AsyncActionView(
async = state.declineAction,
onSuccess = onInviteDeclined,
onErrorDismiss = {
state.eventSink(DefaultAcceptDeclineInviteEvents.DismissDeclineError)
state.eventSink(InternalAcceptDeclineInviteEvents.DismissDeclineError)
},
confirmationDialog = {
val invite = state.invite.getOrNull()
@ -60,10 +60,10 @@ fun AcceptDeclineInviteView( @@ -60,10 +60,10 @@ fun AcceptDeclineInviteView(
DeclineConfirmationDialog(
invite = invite,
onConfirmClicked = {
state.eventSink(DefaultAcceptDeclineInviteEvents.ConfirmDeclineInvite)
state.eventSink(InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite)
},
onDismissClicked = {
state.eventSink(DefaultAcceptDeclineInviteEvents.CancelDeclineInvite)
state.eventSink(InternalAcceptDeclineInviteEvents.CancelDeclineInvite)
}
)
}

2
features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInviteView.kt → features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInviteViewWrapper.kt

@ -26,7 +26,7 @@ import io.element.android.libraries.matrix.api.core.RoomId @@ -26,7 +26,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
import javax.inject.Inject
@ContributesBinding(SessionScope::class)
class DefaultAcceptDeclineInviteView @Inject constructor() : AcceptDeclineInviteView {
class AcceptDeclineInviteViewWrapper @Inject constructor() : AcceptDeclineInviteView {
@Composable
override fun Render(

10
features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/DefaultAcceptDeclineInviteEvents.kt → features/invite/impl/src/main/kotlin/io/element/android/features/invite/impl/response/InternalAcceptDeclineInviteEvents.kt

@ -18,9 +18,9 @@ package io.element.android.features.invite.impl.response @@ -18,9 +18,9 @@ package io.element.android.features.invite.impl.response
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
sealed interface DefaultAcceptDeclineInviteEvents: AcceptDeclineInviteEvents {
data object ConfirmDeclineInvite : DefaultAcceptDeclineInviteEvents
data object CancelDeclineInvite : DefaultAcceptDeclineInviteEvents
data object DismissAcceptError : DefaultAcceptDeclineInviteEvents
data object DismissDeclineError : DefaultAcceptDeclineInviteEvents
sealed interface InternalAcceptDeclineInviteEvents: AcceptDeclineInviteEvents {
data object ConfirmDeclineInvite : InternalAcceptDeclineInviteEvents
data object CancelDeclineInvite : InternalAcceptDeclineInviteEvents
data object DismissAcceptError : InternalAcceptDeclineInviteEvents
data object DismissDeclineError : InternalAcceptDeclineInviteEvents
}

257
features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/InviteListPresenterTests.kt → features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/invitelist/InviteListPresenterTests.kt

@ -14,7 +14,7 @@ @@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.element.android.features.invite.impl
package io.element.android.features.invite.impl.invitelist
import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
@ -22,11 +22,14 @@ import app.cash.turbine.TurbineTestContext @@ -22,11 +22,14 @@ import app.cash.turbine.TurbineTestContext
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import io.element.android.features.invite.api.SeenInvitesStore
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.invite.api.response.anAcceptDeclineInviteState
import io.element.android.features.invite.impl.invitelist.InviteListEvents
import io.element.android.features.invite.impl.invitelist.InviteListPresenter
import io.element.android.features.invite.impl.invitelist.InviteListState
import io.element.android.features.invite.test.FakeSeenInvitesStore
import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.matrix.api.MatrixClient
@ -60,7 +63,7 @@ class InviteListPresenterTests { @@ -60,7 +63,7 @@ class InviteListPresenterTests {
@Test
fun `present - starts empty, adds invites when received`() = runTest {
val roomListService = FakeRoomListService()
val presenter = createPresenter(
val presenter = createInviteListPresenter(
FakeMatrixClient(roomListService = roomListService)
)
moleculeFlow(RecompositionMode.Immediate) {
@ -81,7 +84,7 @@ class InviteListPresenterTests { @@ -81,7 +84,7 @@ class InviteListPresenterTests {
@Test
fun `present - uses user ID and avatar for direct invites`() = runTest {
val roomListService = FakeRoomListService().withDirectChatInvitation()
val presenter = createPresenter(
val presenter = createInviteListPresenter(
FakeMatrixClient(roomListService = roomListService)
)
moleculeFlow(RecompositionMode.Immediate) {
@ -107,7 +110,7 @@ class InviteListPresenterTests { @@ -107,7 +110,7 @@ class InviteListPresenterTests {
@Test
fun `present - includes sender details for room invites`() = runTest {
val roomListService = FakeRoomListService().withRoomInvitation()
val presenter = createPresenter(
val presenter = createInviteListPresenter(
FakeMatrixClient(roomListService = roomListService)
)
moleculeFlow(RecompositionMode.Immediate) {
@ -128,247 +131,15 @@ class InviteListPresenterTests { @@ -128,247 +131,15 @@ class InviteListPresenterTests {
}
}
@Test
fun `present - shows confirm dialog for declining direct chat invites`() = runTest {
val roomListService = FakeRoomListService().withDirectChatInvitation()
val presenter = InviteListPresenter(
FakeMatrixClient(
roomListService = roomListService,
),
FakeSeenInvitesStore(),
FakeAnalyticsService(),
FakeNotificationDrawerManager()
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val originalState = awaitInitialItem()
originalState.eventSink(InviteListEvents.DeclineInvite(originalState.inviteList[0]))
val newState = awaitItem()
assertThat(newState.declineConfirmationDialog).isInstanceOf(InviteDeclineConfirmationDialog.Visible::class.java)
val confirmDialog = newState.declineConfirmationDialog as InviteDeclineConfirmationDialog.Visible
assertThat(confirmDialog.isDirect).isTrue()
assertThat(confirmDialog.name).isEqualTo(A_ROOM_NAME)
}
}
@Test
fun `present - shows confirm dialog for declining room invites`() = runTest {
val roomListService = FakeRoomListService().withRoomInvitation()
val presenter = createPresenter(
FakeMatrixClient(roomListService = roomListService)
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val originalState = awaitInitialItem()
originalState.eventSink(InviteListEvents.DeclineInvite(originalState.inviteList[0]))
val newState = awaitItem()
assertThat(newState.declineConfirmationDialog).isInstanceOf(InviteDeclineConfirmationDialog.Visible::class.java)
val confirmDialog = newState.declineConfirmationDialog as InviteDeclineConfirmationDialog.Visible
assertThat(confirmDialog.isDirect).isFalse()
assertThat(confirmDialog.name).isEqualTo(A_ROOM_NAME)
}
}
@Test
fun `present - hides confirm dialog when cancelling`() = runTest {
val roomListService = FakeRoomListService().withRoomInvitation()
val presenter = createPresenter(
FakeMatrixClient(roomListService = roomListService)
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val originalState = awaitInitialItem()
originalState.eventSink(InviteListEvents.DeclineInvite(originalState.inviteList[0]))
skipItems(1)
originalState.eventSink(InviteListEvents.CancelDeclineInvite)
val newState = awaitItem()
assertThat(newState.declineConfirmationDialog).isInstanceOf(InviteDeclineConfirmationDialog.Hidden::class.java)
}
}
@Test
fun `present - declines invite after confirming`() = runTest {
val roomListService = FakeRoomListService().withRoomInvitation()
val fakeNotificationDrawerManager = FakeNotificationDrawerManager()
val client = FakeMatrixClient(
roomListService = roomListService,
)
val room = FakeMatrixRoom()
val presenter = createPresenter(client = client, notificationDrawerManager = fakeNotificationDrawerManager)
client.givenGetRoomResult(A_ROOM_ID, room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val originalState = awaitInitialItem()
originalState.eventSink(InviteListEvents.DeclineInvite(originalState.inviteList[0]))
skipItems(1)
originalState.eventSink(InviteListEvents.ConfirmDeclineInvite)
skipItems(2)
assertThat(fakeNotificationDrawerManager.getClearMembershipNotificationForRoomCount(client.sessionId, A_ROOM_ID)).isEqualTo(1)
}
}
@Test
fun `present - declines invite after confirming and sets state on error`() = runTest {
val roomListService = FakeRoomListService().withRoomInvitation()
val client = FakeMatrixClient(
roomListService = roomListService,
)
val room = FakeMatrixRoom()
val presenter = createPresenter(client)
val ex = Throwable("Ruh roh!")
room.givenLeaveRoomError(ex)
client.givenGetRoomResult(A_ROOM_ID, room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val originalState = awaitInitialItem()
originalState.eventSink(InviteListEvents.DeclineInvite(originalState.inviteList[0]))
skipItems(1)
originalState.eventSink(InviteListEvents.ConfirmDeclineInvite)
skipItems(1)
val newState = awaitItem()
assertThat(newState.declinedAction).isEqualTo(AsyncData.Failure<Unit>(ex))
}
}
@Test
fun `present - dismisses declining error state`() = runTest {
val roomListService = FakeRoomListService().withRoomInvitation()
val client = FakeMatrixClient(
roomListService = roomListService,
)
val room = FakeMatrixRoom()
val presenter = createPresenter(client)
val ex = Throwable("Ruh roh!")
room.givenLeaveRoomError(ex)
client.givenGetRoomResult(A_ROOM_ID, room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val originalState = awaitInitialItem()
originalState.eventSink(InviteListEvents.DeclineInvite(originalState.inviteList[0]))
skipItems(1)
originalState.eventSink(InviteListEvents.ConfirmDeclineInvite)
skipItems(2)
originalState.eventSink(InviteListEvents.DismissDeclineError)
val newState = awaitItem()
assertThat(newState.declinedAction).isEqualTo(AsyncData.Uninitialized)
}
}
@Test
fun `present - accepts invites and sets state on success`() = runTest {
val roomListService = FakeRoomListService().withRoomInvitation()
val fakeNotificationDrawerManager = FakeNotificationDrawerManager()
val client = FakeMatrixClient(
roomListService = roomListService,
)
val room = FakeMatrixRoom()
val presenter = createPresenter(client = client, notificationDrawerManager = fakeNotificationDrawerManager)
client.givenGetRoomResult(A_ROOM_ID, room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val originalState = awaitInitialItem()
originalState.eventSink(InviteListEvents.AcceptInvite(originalState.inviteList[0]))
val newState = awaitItem()
assertThat(newState.acceptedAction).isEqualTo(AsyncData.Success(A_ROOM_ID))
assertThat(fakeNotificationDrawerManager.getClearMembershipNotificationForRoomCount(client.sessionId, A_ROOM_ID)).isEqualTo(1)
}
}
@Test
fun `present - accepts invites and sets state on error`() = runTest {
val roomListService = FakeRoomListService().withRoomInvitation()
val client = FakeMatrixClient(
roomListService = roomListService,
)
val room = FakeMatrixRoom()
val presenter = createPresenter(client)
val ex = Throwable("Ruh roh!")
room.givenJoinRoomResult(Result.failure(ex))
client.givenGetRoomResult(A_ROOM_ID, room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val originalState = awaitInitialItem()
originalState.eventSink(InviteListEvents.AcceptInvite(originalState.inviteList[0]))
assertThat(awaitItem().acceptedAction).isEqualTo(AsyncData.Failure<RoomId>(ex))
}
}
@Test
fun `present - dismisses accepting error state`() = runTest {
val roomListService = FakeRoomListService().withRoomInvitation()
val client = FakeMatrixClient(
roomListService = roomListService,
)
val room = FakeMatrixRoom()
val presenter = createPresenter(client)
val ex = Throwable("Ruh roh!")
room.givenJoinRoomResult(Result.failure(ex))
client.givenGetRoomResult(A_ROOM_ID, room)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val originalState = awaitInitialItem()
originalState.eventSink(InviteListEvents.AcceptInvite(originalState.inviteList[0]))
skipItems(1)
originalState.eventSink(InviteListEvents.DismissAcceptError)
val newState = awaitItem()
assertThat(newState.acceptedAction).isEqualTo(AsyncData.Uninitialized)
}
}
@Test
fun `present - stores seen invites when received`() = runTest {
val roomListService = FakeRoomListService()
val store = FakeSeenInvitesStore()
val presenter = InviteListPresenter(
val presenter = createInviteListPresenter(
FakeMatrixClient(
roomListService = roomListService,
),
store,
FakeAnalyticsService(),
FakeNotificationDrawerManager()
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@ -400,13 +171,11 @@ class InviteListPresenterTests { @@ -400,13 +171,11 @@ class InviteListPresenterTests {
val roomListService = FakeRoomListService()
val store = FakeSeenInvitesStore()
store.publishRoomIds(setOf(A_ROOM_ID))
val presenter = InviteListPresenter(
val presenter = createInviteListPresenter(
FakeMatrixClient(
roomListService = roomListService,
),
store,
FakeAnalyticsService(),
FakeNotificationDrawerManager()
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
@ -494,15 +263,13 @@ class InviteListPresenterTests { @@ -494,15 +263,13 @@ class InviteListPresenterTests {
return awaitItem()
}
private fun createPresenter(
private fun createInviteListPresenter(
client: MatrixClient,
seenInvitesStore: SeenInvitesStore = FakeSeenInvitesStore(),
fakeAnalyticsService: AnalyticsService = FakeAnalyticsService(),
notificationDrawerManager: NotificationDrawerManager = FakeNotificationDrawerManager()
acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState> = Presenter { anAcceptDeclineInviteState() },
) = InviteListPresenter(
client,
seenInvitesStore,
fakeAnalyticsService,
notificationDrawerManager
acceptDeclineInvitePresenter = acceptDeclineInvitePresenter,
)
}

248
features/invite/impl/src/test/kotlin/io/element/android/features/invite/impl/response/AcceptDeclineInvitePresenterTest.kt

@ -0,0 +1,248 @@ @@ -0,0 +1,248 @@
/*
* Copyright (c) 2024 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.
*/
package io.element.android.features.invite.impl.response
import com.google.common.truth.Truth.assertThat
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.response.InviteData
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_NAME
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.push.api.notifications.NotificationDrawerManager
import io.element.android.libraries.push.test.notifications.FakeNotificationDrawerManager
import io.element.android.services.analytics.api.AnalyticsService
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.test
import kotlinx.coroutines.test.runTest
import org.junit.Rule
import org.junit.Test
import java.util.Optional
class AcceptDeclineInvitePresenterTest {
@get:Rule
val warmUpRule = WarmUpRule()
@Test
fun `present - initial state`() = runTest {
val presenter = createAcceptDeclineInvitePresenter()
presenter.test {
awaitItem().also { state ->
assertThat(state.acceptAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
assertThat(state.declineAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
assertThat(state.invite).isEqualTo(Optional.empty<InviteData>())
}
}
}
@Test
fun `present - declining invite cancel flow`() = runTest {
val presenter = createAcceptDeclineInvitePresenter()
presenter.test {
val inviteData = anInviteData()
awaitItem().also { state ->
state.eventSink(
AcceptDeclineInviteEvents.DeclineInvite(inviteData)
)
}
skipItems(1)
awaitItem().also { state ->
assertThat(state.invite).isEqualTo(Optional.of(inviteData))
assertThat(state.declineAction).isInstanceOf(AsyncAction.Confirming::class.java)
state.eventSink(
InternalAcceptDeclineInviteEvents.CancelDeclineInvite
)
}
skipItems(1)
awaitItem().also { state ->
assertThat(state.invite).isEqualTo(Optional.empty<InviteData>())
assertThat(state.declineAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
}
}
}
@Test
fun `present - declining invite error flow`() = runTest {
val declineInviteFailure = lambdaRecorder { ->
Result.failure<Unit>(RuntimeException("Failed to leave room"))
}
val client = FakeMatrixClient().apply {
givenGetRoomResult(
roomId = A_ROOM_ID,
result = FakeMatrixRoom().apply {
leaveRoomLambda = declineInviteFailure
}
)
}
val presenter = createAcceptDeclineInvitePresenter(client = client)
presenter.test {
val inviteData = anInviteData()
awaitItem().also { state ->
state.eventSink(
AcceptDeclineInviteEvents.DeclineInvite(inviteData)
)
}
skipItems(1)
awaitItem().also { state ->
state.eventSink(
InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite
)
}
skipItems(1)
awaitItem().also { state ->
assertThat(state.declineAction).isInstanceOf(AsyncAction.Failure::class.java)
state.eventSink(
InternalAcceptDeclineInviteEvents.DismissDeclineError
)
}
skipItems(1)
awaitItem().also { state ->
assertThat(state.invite).isEqualTo(Optional.empty<InviteData>())
assertThat(state.declineAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
}
cancelAndConsumeRemainingEvents()
}
assert(declineInviteFailure).isCalledOnce()
}
@Test
fun `present - declining invite success flow`() = runTest {
val declineInviteSuccess = lambdaRecorder { ->
Result.success(Unit)
}
val client = FakeMatrixClient().apply {
givenGetRoomResult(
roomId = A_ROOM_ID,
result = FakeMatrixRoom().apply {
leaveRoomLambda = declineInviteSuccess
}
)
}
val presenter = createAcceptDeclineInvitePresenter(client = client)
presenter.test {
val inviteData = anInviteData()
awaitItem().also { state ->
state.eventSink(
AcceptDeclineInviteEvents.DeclineInvite(inviteData)
)
}
skipItems(1)
awaitItem().also { state ->
state.eventSink(
InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite
)
}
skipItems(1)
awaitItem().also { state ->
assertThat(state.declineAction).isInstanceOf(AsyncAction.Success::class.java)
}
cancelAndConsumeRemainingEvents()
}
assert(declineInviteSuccess).isCalledOnce()
}
@Test
fun `present - accepting invite error flow`() = runTest {
val joinRoomFailure = lambdaRecorder { roomId: RoomId ->
Result.failure<RoomId>(RuntimeException("Failed to join room $roomId"))
}
val client = FakeMatrixClient().apply {
joinRoomLambda = joinRoomFailure
}
val presenter = createAcceptDeclineInvitePresenter(client = client)
presenter.test {
val inviteData = anInviteData()
awaitItem().also { state ->
state.eventSink(
AcceptDeclineInviteEvents.AcceptInvite(inviteData)
)
}
skipItems(1)
awaitItem().also { state ->
assertThat(state.invite).isEqualTo(Optional.of(inviteData))
assertThat(state.acceptAction).isInstanceOf(AsyncAction.Failure::class.java)
state.eventSink(
InternalAcceptDeclineInviteEvents.DismissAcceptError
)
}
skipItems(1)
awaitItem().also { state ->
assertThat(state.invite).isEqualTo(Optional.empty<InviteData>())
assertThat(state.acceptAction).isInstanceOf(AsyncAction.Uninitialized::class.java)
}
cancelAndConsumeRemainingEvents()
}
assert(joinRoomFailure).isCalledOnce()
}
@Test
fun `present - accepting invite success flow`() = runTest {
val joinRoomSuccess = lambdaRecorder { roomId: RoomId ->
Result.success(roomId)
}
val client = FakeMatrixClient().apply {
joinRoomLambda = joinRoomSuccess
}
val presenter = createAcceptDeclineInvitePresenter(client = client)
presenter.test {
val inviteData = anInviteData()
awaitItem().also { state ->
state.eventSink(
AcceptDeclineInviteEvents.AcceptInvite(inviteData)
)
}
skipItems(1)
awaitItem().also { state ->
assertThat(state.invite).isEqualTo(Optional.of(inviteData))
assertThat(state.acceptAction).isInstanceOf(AsyncAction.Success::class.java)
}
cancelAndConsumeRemainingEvents()
}
assert(joinRoomSuccess).isCalledOnce()
}
private fun anInviteData(
roomId: RoomId = A_ROOM_ID,
name: String = A_ROOM_NAME,
isDirect: Boolean = false
): InviteData {
return InviteData(
roomId = roomId,
roomName = name,
isDirect = isDirect
)
}
private fun createAcceptDeclineInvitePresenter(
client: MatrixClient = FakeMatrixClient(),
analyticsService: AnalyticsService = FakeAnalyticsService(),
notificationDrawerManager: NotificationDrawerManager = FakeNotificationDrawerManager(),
): AcceptDeclineInvitePresenter {
return AcceptDeclineInvitePresenter(
client = client,
analyticsService = analyticsService,
notificationDrawerManager = notificationDrawerManager,
)
}
}

4
features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomPresenter.kt

@ -23,7 +23,7 @@ import androidx.compose.runtime.produceState @@ -23,7 +23,7 @@ import androidx.compose.runtime.produceState
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
import io.element.android.features.invite.api.response.AcceptDeclineInvitePresenter
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.invite.api.response.InviteData
import io.element.android.features.roomdirectory.api.RoomDescription
import io.element.android.libraries.architecture.AsyncData
@ -39,7 +39,7 @@ class JoinRoomPresenter @AssistedInject constructor( @@ -39,7 +39,7 @@ class JoinRoomPresenter @AssistedInject constructor(
@Assisted private val roomId: RoomId,
@Assisted private val roomDescription: Optional<RoomDescription>,
private val matrixClient: MatrixClient,
private val acceptDeclineInvitePresenter: AcceptDeclineInvitePresenter,
private val acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
) : Presenter<JoinRoomState> {
interface Factory {

4
features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/JoinRoomView.kt

@ -187,7 +187,7 @@ private fun JoinRoomContent( @@ -187,7 +187,7 @@ private fun JoinRoomContent(
}
@Composable
fun JoinRoomMembersCount(memberCount: Long) {
private fun JoinRoomMembersCount(memberCount: Long) {
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier
@ -227,7 +227,7 @@ private fun JoinRoomTopBar( @@ -227,7 +227,7 @@ private fun JoinRoomTopBar(
@PreviewLightDark
@Composable
fun JoinRoomViewPreview(@PreviewParameter(JoinRoomStateProvider::class) state: JoinRoomState) = ElementPreview {
internal fun JoinRoomViewPreview(@PreviewParameter(JoinRoomStateProvider::class) state: JoinRoomState) = ElementPreview {
JoinRoomView(
state = state,
onBackPressed = { }

7
features/joinroom/impl/src/main/kotlin/io/element/android/features/joinroom/impl/di/JoinRoomModule.kt

@ -19,13 +19,13 @@ package io.element.android.features.joinroom.impl.di @@ -19,13 +19,13 @@ package io.element.android.features.joinroom.impl.di
import com.squareup.anvil.annotations.ContributesTo
import dagger.Module
import dagger.Provides
import io.element.android.features.invite.api.response.AcceptDeclineInvitePresenter
import io.element.android.features.invite.api.response.AcceptDeclineInviteState
import io.element.android.features.joinroom.impl.JoinRoomPresenter
import io.element.android.features.roomdirectory.api.RoomDescription
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.roomlist.RoomListService
import java.util.Optional
@Module
@ -33,9 +33,8 @@ import java.util.Optional @@ -33,9 +33,8 @@ import java.util.Optional
object JoinRoomModule {
@Provides
fun providesJoinRoomPresenterFactory(
roomListService: RoomListService,
client: MatrixClient,
acceptDeclineInvitePresenter: AcceptDeclineInvitePresenter,
acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
): JoinRoomPresenter.Factory {
return object : JoinRoomPresenter.Factory {
override fun create(roomId: RoomId, roomDescription: Optional<RoomDescription>): JoinRoomPresenter {

4
features/leaveroom/impl/src/test/kotlin/io/element/android/features/leaveroom/impl/LeaveRoomPresenterImplTest.kt

@ -164,7 +164,7 @@ class LeaveRoomPresenterImplTest { @@ -164,7 +164,7 @@ class LeaveRoomPresenterImplTest {
givenGetRoomResult(
roomId = A_ROOM_ID,
result = FakeMatrixRoom().apply {
givenLeaveRoomError(RuntimeException("Blimey!"))
this.leaveRoomLambda = { Result.failure(RuntimeException("Blimey!"))}
},
)
}
@ -210,7 +210,7 @@ class LeaveRoomPresenterImplTest { @@ -210,7 +210,7 @@ class LeaveRoomPresenterImplTest {
givenGetRoomResult(
roomId = A_ROOM_ID,
result = FakeMatrixRoom().apply {
givenLeaveRoomError(RuntimeException("Blimey!"))
this.leaveRoomLambda = { Result.failure(RuntimeException("Blimey!"))}
},
)
}

2
features/location/impl/src/test/kotlin/io/element/android/features/location/impl/common/actions/AndroidLocationActionsTest.kt

@ -18,9 +18,11 @@ package io.element.android.features.location.impl.common.actions @@ -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")

39
features/roomdirectory/impl/src/main/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryView.kt

@ -91,8 +91,8 @@ fun RoomDirectoryView( @@ -91,8 +91,8 @@ fun RoomDirectoryView(
onResultClicked = onResultClicked,
onJoinClicked = ::joinRoom,
modifier = Modifier
.padding(padding)
.consumeWindowInsets(padding)
.padding(padding)
.consumeWindowInsets(padding)
)
}
)
@ -199,10 +199,10 @@ private fun RoomDirectoryRoomList( @@ -199,10 +199,10 @@ private fun RoomDirectoryRoomList(
@Composable
private fun LoadMoreIndicator(modifier: Modifier = Modifier) {
Box(
modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(24.dp),
modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(24.dp),
contentAlignment = Alignment.Center,
) {
CircularProgressIndicator(
@ -273,14 +273,14 @@ private fun RoomDirectoryRoomRow( @@ -273,14 +273,14 @@ private fun RoomDirectoryRoomRow(
) {
Row(
modifier = modifier
.fillMaxWidth()
.clickable(enabled = roomDescription.canBeJoined, onClick = onClick)
.padding(
top = 12.dp,
bottom = 12.dp,
start = 16.dp,
)
.height(IntrinsicSize.Min),
.fillMaxWidth()
.clickable(enabled = roomDescription.canBeJoined, onClick = onClick)
.padding(
top = 12.dp,
bottom = 12.dp,
start = 16.dp,
)
.height(IntrinsicSize.Min),
) {
Avatar(
avatarData = roomDescription.avatarData(AvatarSize.RoomDirectoryItem),
@ -288,8 +288,8 @@ private fun RoomDirectoryRoomRow( @@ -288,8 +288,8 @@ private fun RoomDirectoryRoomRow(
)
Column(
modifier = Modifier
.weight(1f)
.padding(start = 16.dp)
.weight(1f)
.padding(start = 16.dp)
) {
Text(
text = roomDescription.name,
@ -311,9 +311,10 @@ private fun RoomDirectoryRoomRow( @@ -311,9 +311,10 @@ private fun RoomDirectoryRoomRow(
text = stringResource(id = CommonStrings.action_join),
color = ElementTheme.colors.textSuccessPrimary,
modifier = Modifier
.align(Alignment.CenterVertically)
.clickable(onClick = onJoinClick)
.padding(start = 4.dp, end = 12.dp)
.align(Alignment.CenterVertically)
.clickable(onClick = onJoinClick)
.padding(start = 4.dp, end = 12.dp)
.testTag(TestTags.callToAction.value)
)
} else {
Spacer(modifier = Modifier.width(24.dp))

32
features/roomdirectory/impl/src/test/kotlin/io/element/android/features/roomdirectory/impl/root/RoomDirectoryViewTest.kt

@ -17,16 +17,23 @@ @@ -17,16 +17,23 @@
package io.element.android.features.roomdirectory.impl.root
import androidx.activity.ComponentActivity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onAllNodesWithTag
import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onChild
import androidx.compose.ui.test.onFirst
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextInput
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.features.roomdirectory.api.RoomDescription
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.ui.strings.CommonStrings
import io.element.android.tests.testutils.EnsureNeverCalled
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
import io.element.android.tests.testutils.EventsRecorder
@ -55,7 +62,24 @@ class RoomDirectoryViewTest { @@ -55,7 +62,24 @@ class RoomDirectoryViewTest {
}
@Test
fun `clicking on room item emits the expected Event`() {
fun `clicking on room item then onResultClicked lambda is called once`() {
val eventsRecorder = EventsRecorder<RoomDirectoryEvents>()
val state = aRoomDirectoryState(
roomDescriptions = aRoomDescriptionList(),
eventSink = eventsRecorder,
)
val clickedRoom = state.roomDescriptions.first()
ensureCalledOnceWithParam(clickedRoom) { callback ->
rule.setRoomDirectoryView(
state = state,
onResultClicked = callback,
)
rule.onNodeWithText(clickedRoom.name).performClick()
}
}
@Test
fun `clicking on room item join cta emits the expected Event`() {
val eventsRecorder = EventsRecorder<RoomDirectoryEvents>()
val state = aRoomDirectoryState(
roomDescriptions = aRoomDescriptionList(),
@ -63,7 +87,7 @@ class RoomDirectoryViewTest { @@ -63,7 +87,7 @@ class RoomDirectoryViewTest {
)
rule.setRoomDirectoryView(state = state)
val clickedRoom = state.roomDescriptions.first()
rule.onNodeWithText(clickedRoom.name).performClick()
rule.onAllNodesWithTag(TestTags.callToAction.value).onFirst().performClick()
eventsRecorder.assertSingle(RoomDirectoryEvents.JoinRoom(clickedRoom.roomId))
}
@ -100,12 +124,14 @@ class RoomDirectoryViewTest { @@ -100,12 +124,14 @@ class RoomDirectoryViewTest {
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRoomDirectoryView(
state: RoomDirectoryState,
onBackPressed: () -> Unit = EnsureNeverCalled(),
onResultClicked: (RoomDescription) -> Unit = EnsureNeverCalledWithParam(),
onRoomJoined: (RoomId) -> Unit = EnsureNeverCalledWithParam(),
) {
setContent {
RoomDirectoryView(
state = state,
onRoomClicked = onRoomJoined,
onResultClicked = onResultClicked,
onRoomJoined = onRoomJoined,
onBackPressed = onBackPressed,
)
}

1
libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/MatrixClient.kt

@ -100,3 +100,4 @@ interface MatrixClient : Closeable { @@ -100,3 +100,4 @@ interface MatrixClient : Closeable {
suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit>
suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>>
}

12
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/FakeMatrixClient.kt

@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.api.notificationsettings.Notification @@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.api.notificationsettings.Notification
import io.element.android.libraries.matrix.api.oidc.AccountManagementAction
import io.element.android.libraries.matrix.api.pusher.PushersService
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
import io.element.android.libraries.matrix.api.roomlist.RoomListService
@ -51,7 +52,9 @@ import kotlinx.coroutines.CoroutineScope @@ -51,7 +52,9 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.TestScope
import java.util.Optional
class FakeMatrixClient(
override val sessionId: SessionId = A_SESSION_ID,
@ -94,10 +97,14 @@ class FakeMatrixClient( @@ -94,10 +97,14 @@ class FakeMatrixClient(
private var setDisplayNameResult: Result<Unit> = Result.success(Unit)
private var uploadAvatarResult: Result<Unit> = Result.success(Unit)
private var removeAvatarResult: Result<Unit> = Result.success(Unit)
var joinRoomLambda: suspend (RoomId) -> Result<RoomId> = {
var joinRoomLambda: (RoomId) -> Result<RoomId> = {
Result.success(it)
}
var getRoomInfoFlowLambda = { _: RoomId ->
flowOf<Optional<MatrixRoomInfo>>(Optional.empty())
}
override suspend fun getRoom(roomId: RoomId): MatrixRoom? {
return getRoomResults[roomId]
}
@ -267,4 +274,7 @@ class FakeMatrixClient( @@ -267,4 +274,7 @@ class FakeMatrixClient(
override suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>> {
return Result.success(visitedRoomsId)
}
override fun getRoomInfoFlow(roomId: RoomId) = getRoomInfoFlowLambda(roomId)
}

11
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/room/FakeMatrixRoom.kt

@ -182,7 +182,7 @@ class FakeMatrixRoom( @@ -182,7 +182,7 @@ class FakeMatrixRoom(
var removedAvatar: Boolean = false
private set
private var leaveRoomError: Throwable? = null
var leaveRoomLambda: (() -> Result<Unit>) = { Result.success(Unit) }
private val _roomInfoFlow: MutableSharedFlow<MatrixRoomInfo> = MutableSharedFlow(replay = 1)
override val roomInfoFlow: Flow<MatrixRoomInfo> = _roomInfoFlow
@ -315,8 +315,9 @@ class FakeMatrixRoom( @@ -315,8 +315,9 @@ class FakeMatrixRoom(
return Result.success(Unit)
}
override suspend fun leave(): Result<Unit> =
leaveRoomError?.let { Result.failure(it) } ?: Result.success(Unit)
override suspend fun leave(): Result<Unit> {
return leaveRoomLambda()
}
override suspend fun join(): Result<Unit> {
return joinRoomResult
@ -542,10 +543,6 @@ class FakeMatrixRoom( @@ -542,10 +543,6 @@ class FakeMatrixRoom(
override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver> = getWidgetDriverResult
fun givenLeaveRoomError(throwable: Throwable?) {
this.leaveRoomError = throwable
}
fun givenRoomMembersState(state: MatrixRoomMembersState) {
membersStateFlow.value = state
}

3
libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/roomlist/SimplePagedRoomList.kt

@ -21,6 +21,7 @@ import io.element.android.libraries.matrix.api.roomlist.RoomList @@ -21,6 +21,7 @@ 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.RoomSummary
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.getAndUpdate
@ -32,6 +33,8 @@ data class SimplePagedRoomList( @@ -32,6 +33,8 @@ data class SimplePagedRoomList(
override val pageSize: Int = Int.MAX_VALUE
override val loadedPages = MutableStateFlow(1)
override val filteredSummaries: SharedFlow<List<RoomSummary>> = summaries
override suspend fun loadMore() {
// No-op
loadedPages.getAndUpdate { it + 1 }

5
libraries/testtags/src/main/kotlin/io/element/android/libraries/testtags/TestTags.kt

@ -105,4 +105,9 @@ object TestTags { @@ -105,4 +105,9 @@ object TestTags {
* Search field.
*/
val searchTextField = TestTag("search_text_field")
/**
* Generic call to action
*/
val callToAction = TestTag("call_to_action")
}

Loading…
Cancel
Save