Room navigation : fix tests on invite after the refactoring
This commit is contained in:
parent
d07df2319b
commit
79c6385edb
21 changed files with 381 additions and 313 deletions
|
|
@ -32,7 +32,6 @@ import io.element.android.features.messages.api.MessagesEntryPoint
|
||||||
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
|
import io.element.android.features.roomdetails.api.RoomDetailsEntryPoint
|
||||||
import io.element.android.libraries.architecture.childNode
|
import io.element.android.libraries.architecture.childNode
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
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.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
|
||||||
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
|
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
|
||||||
|
|
@ -41,7 +40,7 @@ import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class RoomFlowNodeTest {
|
class JoinRoomLoadedFlowNodeTest {
|
||||||
@get:Rule
|
@get:Rule
|
||||||
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
val instantTaskExecutorRule = InstantTaskExecutorRule()
|
||||||
|
|
||||||
|
|
@ -88,7 +87,7 @@ class RoomFlowNodeTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun aRoomFlowNode(
|
private fun createJoinedRoomLoadedFlowNode(
|
||||||
plugins: List<Plugin>,
|
plugins: List<Plugin>,
|
||||||
messagesEntryPoint: MessagesEntryPoint = FakeMessagesEntryPoint(),
|
messagesEntryPoint: MessagesEntryPoint = FakeMessagesEntryPoint(),
|
||||||
roomDetailsEntryPoint: RoomDetailsEntryPoint = FakeRoomDetailsEntryPoint(),
|
roomDetailsEntryPoint: RoomDetailsEntryPoint = FakeRoomDetailsEntryPoint(),
|
||||||
|
|
@ -99,7 +98,6 @@ class RoomFlowNodeTest {
|
||||||
messagesEntryPoint = messagesEntryPoint,
|
messagesEntryPoint = messagesEntryPoint,
|
||||||
roomDetailsEntryPoint = roomDetailsEntryPoint,
|
roomDetailsEntryPoint = roomDetailsEntryPoint,
|
||||||
appNavigationStateService = FakeAppNavigationStateService(),
|
appNavigationStateService = FakeAppNavigationStateService(),
|
||||||
roomMembershipObserver = RoomMembershipObserver(),
|
|
||||||
appCoroutineScope = coroutineScope,
|
appCoroutineScope = coroutineScope,
|
||||||
roomComponentFactory = FakeRoomComponentFactory(),
|
roomComponentFactory = FakeRoomComponentFactory(),
|
||||||
matrixClient = FakeMatrixClient(),
|
matrixClient = FakeMatrixClient(),
|
||||||
|
|
@ -111,7 +109,7 @@ class RoomFlowNodeTest {
|
||||||
val room = FakeMatrixRoom()
|
val room = FakeMatrixRoom()
|
||||||
val fakeMessagesEntryPoint = FakeMessagesEntryPoint()
|
val fakeMessagesEntryPoint = FakeMessagesEntryPoint()
|
||||||
val inputs = JoinedRoomLoadedFlowNode.Inputs(room)
|
val inputs = JoinedRoomLoadedFlowNode.Inputs(room)
|
||||||
val roomFlowNode = aRoomFlowNode(
|
val roomFlowNode = createJoinedRoomLoadedFlowNode(
|
||||||
plugins = listOf(inputs),
|
plugins = listOf(inputs),
|
||||||
messagesEntryPoint = fakeMessagesEntryPoint,
|
messagesEntryPoint = fakeMessagesEntryPoint,
|
||||||
coroutineScope = this
|
coroutineScope = this
|
||||||
|
|
@ -133,7 +131,7 @@ class RoomFlowNodeTest {
|
||||||
val fakeMessagesEntryPoint = FakeMessagesEntryPoint()
|
val fakeMessagesEntryPoint = FakeMessagesEntryPoint()
|
||||||
val fakeRoomDetailsEntryPoint = FakeRoomDetailsEntryPoint()
|
val fakeRoomDetailsEntryPoint = FakeRoomDetailsEntryPoint()
|
||||||
val inputs = JoinedRoomLoadedFlowNode.Inputs(room)
|
val inputs = JoinedRoomLoadedFlowNode.Inputs(room)
|
||||||
val roomFlowNode = aRoomFlowNode(
|
val roomFlowNode = createJoinedRoomLoadedFlowNode(
|
||||||
plugins = listOf(inputs),
|
plugins = listOf(inputs),
|
||||||
messagesEntryPoint = fakeMessagesEntryPoint,
|
messagesEntryPoint = fakeMessagesEntryPoint,
|
||||||
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
|
roomDetailsEntryPoint = fakeRoomDetailsEntryPoint,
|
||||||
|
|
@ -14,8 +14,19 @@
|
||||||
* limitations under the License.
|
* 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.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>
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import io.element.android.features.invite.api.SeenInvitesStore
|
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.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.api.response.InviteData
|
||||||
import io.element.android.features.invite.impl.model.InviteListInviteSummary
|
import io.element.android.features.invite.impl.model.InviteListInviteSummary
|
||||||
import io.element.android.features.invite.impl.model.InviteSender
|
import io.element.android.features.invite.impl.model.InviteSender
|
||||||
|
|
@ -42,7 +42,7 @@ import javax.inject.Inject
|
||||||
class InviteListPresenter @Inject constructor(
|
class InviteListPresenter @Inject constructor(
|
||||||
private val client: MatrixClient,
|
private val client: MatrixClient,
|
||||||
private val store: SeenInvitesStore,
|
private val store: SeenInvitesStore,
|
||||||
private val acceptDeclineInvitePresenter: AcceptDeclineInvitePresenter,
|
private val acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
|
||||||
) : Presenter<InviteListState> {
|
) : Presenter<InviteListState> {
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): InviteListState {
|
override fun present(): InviteListState {
|
||||||
|
|
|
||||||
|
|
@ -26,10 +26,10 @@ import androidx.compose.runtime.setValue
|
||||||
import com.squareup.anvil.annotations.ContributesBinding
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
import im.vector.app.features.analytics.plan.JoinedRoom
|
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.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.AcceptDeclineInviteState
|
||||||
import io.element.android.features.invite.api.response.InviteData
|
import io.element.android.features.invite.api.response.InviteData
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
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.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.architecture.runUpdatingState
|
import io.element.android.libraries.architecture.runUpdatingState
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
|
|
@ -44,12 +44,11 @@ import java.util.Optional
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.jvm.optionals.getOrNull
|
import kotlin.jvm.optionals.getOrNull
|
||||||
|
|
||||||
@ContributesBinding(SessionScope::class)
|
class AcceptDeclineInvitePresenter @Inject constructor(
|
||||||
class DefaultAcceptDeclineInvitePresenter @Inject constructor(
|
|
||||||
private val client: MatrixClient,
|
private val client: MatrixClient,
|
||||||
private val analyticsService: AnalyticsService,
|
private val analyticsService: AnalyticsService,
|
||||||
private val notificationDrawerManager: NotificationDrawerManager,
|
private val notificationDrawerManager: NotificationDrawerManager,
|
||||||
) : AcceptDeclineInvitePresenter {
|
) : Presenter<AcceptDeclineInviteState> {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): AcceptDeclineInviteState {
|
override fun present(): AcceptDeclineInviteState {
|
||||||
|
|
@ -66,6 +65,7 @@ class DefaultAcceptDeclineInvitePresenter @Inject constructor(
|
||||||
is AcceptDeclineInviteEvents.AcceptInvite -> {
|
is AcceptDeclineInviteEvents.AcceptInvite -> {
|
||||||
currentInvite = Optional.of(event.invite)
|
currentInvite = Optional.of(event.invite)
|
||||||
localCoroutineScope.acceptInvite(event.invite.roomId, acceptedAction)
|
localCoroutineScope.acceptInvite(event.invite.roomId, acceptedAction)
|
||||||
|
currentInvite = Optional.empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
is AcceptDeclineInviteEvents.DeclineInvite -> {
|
is AcceptDeclineInviteEvents.DeclineInvite -> {
|
||||||
|
|
@ -73,7 +73,7 @@ class DefaultAcceptDeclineInvitePresenter @Inject constructor(
|
||||||
declinedAction.value = AsyncAction.Confirming
|
declinedAction.value = AsyncAction.Confirming
|
||||||
}
|
}
|
||||||
|
|
||||||
is DefaultAcceptDeclineInviteEvents.ConfirmDeclineInvite -> {
|
is InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite -> {
|
||||||
declinedAction.value = AsyncAction.Uninitialized
|
declinedAction.value = AsyncAction.Uninitialized
|
||||||
currentInvite.getOrNull()?.let {
|
currentInvite.getOrNull()?.let {
|
||||||
localCoroutineScope.declineInvite(it.roomId, declinedAction)
|
localCoroutineScope.declineInvite(it.roomId, declinedAction)
|
||||||
|
|
@ -81,16 +81,16 @@ class DefaultAcceptDeclineInvitePresenter @Inject constructor(
|
||||||
currentInvite = Optional.empty()
|
currentInvite = Optional.empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
is DefaultAcceptDeclineInviteEvents.CancelDeclineInvite -> {
|
is InternalAcceptDeclineInviteEvents.CancelDeclineInvite -> {
|
||||||
currentInvite = Optional.empty()
|
currentInvite = Optional.empty()
|
||||||
declinedAction.value = AsyncAction.Uninitialized
|
declinedAction.value = AsyncAction.Uninitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
is DefaultAcceptDeclineInviteEvents.DismissAcceptError -> {
|
is InternalAcceptDeclineInviteEvents.DismissAcceptError -> {
|
||||||
acceptedAction.value = AsyncAction.Uninitialized
|
acceptedAction.value = AsyncAction.Uninitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
is DefaultAcceptDeclineInviteEvents.DismissDeclineError -> {
|
is InternalAcceptDeclineInviteEvents.DismissDeclineError -> {
|
||||||
declinedAction.value = AsyncAction.Uninitialized
|
declinedAction.value = AsyncAction.Uninitialized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -45,14 +45,14 @@ fun AcceptDeclineInviteView(
|
||||||
async = state.acceptAction,
|
async = state.acceptAction,
|
||||||
onSuccess = onInviteAccepted,
|
onSuccess = onInviteAccepted,
|
||||||
onErrorDismiss = {
|
onErrorDismiss = {
|
||||||
state.eventSink(DefaultAcceptDeclineInviteEvents.DismissAcceptError)
|
state.eventSink(InternalAcceptDeclineInviteEvents.DismissAcceptError)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
AsyncActionView(
|
AsyncActionView(
|
||||||
async = state.declineAction,
|
async = state.declineAction,
|
||||||
onSuccess = onInviteDeclined,
|
onSuccess = onInviteDeclined,
|
||||||
onErrorDismiss = {
|
onErrorDismiss = {
|
||||||
state.eventSink(DefaultAcceptDeclineInviteEvents.DismissDeclineError)
|
state.eventSink(InternalAcceptDeclineInviteEvents.DismissDeclineError)
|
||||||
},
|
},
|
||||||
confirmationDialog = {
|
confirmationDialog = {
|
||||||
val invite = state.invite.getOrNull()
|
val invite = state.invite.getOrNull()
|
||||||
|
|
@ -60,10 +60,10 @@ fun AcceptDeclineInviteView(
|
||||||
DeclineConfirmationDialog(
|
DeclineConfirmationDialog(
|
||||||
invite = invite,
|
invite = invite,
|
||||||
onConfirmClicked = {
|
onConfirmClicked = {
|
||||||
state.eventSink(DefaultAcceptDeclineInviteEvents.ConfirmDeclineInvite)
|
state.eventSink(InternalAcceptDeclineInviteEvents.ConfirmDeclineInvite)
|
||||||
},
|
},
|
||||||
onDismissClicked = {
|
onDismissClicked = {
|
||||||
state.eventSink(DefaultAcceptDeclineInviteEvents.CancelDeclineInvite)
|
state.eventSink(InternalAcceptDeclineInviteEvents.CancelDeclineInvite)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ContributesBinding(SessionScope::class)
|
@ContributesBinding(SessionScope::class)
|
||||||
class DefaultAcceptDeclineInviteView @Inject constructor() : AcceptDeclineInviteView {
|
class AcceptDeclineInviteViewWrapper @Inject constructor() : AcceptDeclineInviteView {
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun Render(
|
override fun Render(
|
||||||
|
|
@ -18,9 +18,9 @@ package io.element.android.features.invite.impl.response
|
||||||
|
|
||||||
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
|
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
|
||||||
|
|
||||||
sealed interface DefaultAcceptDeclineInviteEvents: AcceptDeclineInviteEvents {
|
sealed interface InternalAcceptDeclineInviteEvents: AcceptDeclineInviteEvents {
|
||||||
data object ConfirmDeclineInvite : DefaultAcceptDeclineInviteEvents
|
data object ConfirmDeclineInvite : InternalAcceptDeclineInviteEvents
|
||||||
data object CancelDeclineInvite : DefaultAcceptDeclineInviteEvents
|
data object CancelDeclineInvite : InternalAcceptDeclineInviteEvents
|
||||||
data object DismissAcceptError : DefaultAcceptDeclineInviteEvents
|
data object DismissAcceptError : InternalAcceptDeclineInviteEvents
|
||||||
data object DismissDeclineError : DefaultAcceptDeclineInviteEvents
|
data object DismissDeclineError : InternalAcceptDeclineInviteEvents
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* 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.RecompositionMode
|
||||||
import app.cash.molecule.moleculeFlow
|
import app.cash.molecule.moleculeFlow
|
||||||
|
|
@ -22,11 +22,14 @@ import app.cash.turbine.TurbineTestContext
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.invite.api.SeenInvitesStore
|
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.InviteListEvents
|
||||||
import io.element.android.features.invite.impl.invitelist.InviteListPresenter
|
import io.element.android.features.invite.impl.invitelist.InviteListPresenter
|
||||||
import io.element.android.features.invite.impl.invitelist.InviteListState
|
import io.element.android.features.invite.impl.invitelist.InviteListState
|
||||||
import io.element.android.features.invite.test.FakeSeenInvitesStore
|
import io.element.android.features.invite.test.FakeSeenInvitesStore
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
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.AvatarData
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
|
|
@ -60,7 +63,7 @@ class InviteListPresenterTests {
|
||||||
@Test
|
@Test
|
||||||
fun `present - starts empty, adds invites when received`() = runTest {
|
fun `present - starts empty, adds invites when received`() = runTest {
|
||||||
val roomListService = FakeRoomListService()
|
val roomListService = FakeRoomListService()
|
||||||
val presenter = createPresenter(
|
val presenter = createInviteListPresenter(
|
||||||
FakeMatrixClient(roomListService = roomListService)
|
FakeMatrixClient(roomListService = roomListService)
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
|
@ -81,7 +84,7 @@ class InviteListPresenterTests {
|
||||||
@Test
|
@Test
|
||||||
fun `present - uses user ID and avatar for direct invites`() = runTest {
|
fun `present - uses user ID and avatar for direct invites`() = runTest {
|
||||||
val roomListService = FakeRoomListService().withDirectChatInvitation()
|
val roomListService = FakeRoomListService().withDirectChatInvitation()
|
||||||
val presenter = createPresenter(
|
val presenter = createInviteListPresenter(
|
||||||
FakeMatrixClient(roomListService = roomListService)
|
FakeMatrixClient(roomListService = roomListService)
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
|
@ -107,7 +110,7 @@ class InviteListPresenterTests {
|
||||||
@Test
|
@Test
|
||||||
fun `present - includes sender details for room invites`() = runTest {
|
fun `present - includes sender details for room invites`() = runTest {
|
||||||
val roomListService = FakeRoomListService().withRoomInvitation()
|
val roomListService = FakeRoomListService().withRoomInvitation()
|
||||||
val presenter = createPresenter(
|
val presenter = createInviteListPresenter(
|
||||||
FakeMatrixClient(roomListService = roomListService)
|
FakeMatrixClient(roomListService = roomListService)
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
|
|
@ -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
|
@Test
|
||||||
fun `present - stores seen invites when received`() = runTest {
|
fun `present - stores seen invites when received`() = runTest {
|
||||||
val roomListService = FakeRoomListService()
|
val roomListService = FakeRoomListService()
|
||||||
val store = FakeSeenInvitesStore()
|
val store = FakeSeenInvitesStore()
|
||||||
val presenter = InviteListPresenter(
|
val presenter = createInviteListPresenter(
|
||||||
FakeMatrixClient(
|
FakeMatrixClient(
|
||||||
roomListService = roomListService,
|
roomListService = roomListService,
|
||||||
),
|
),
|
||||||
store,
|
store,
|
||||||
FakeAnalyticsService(),
|
|
||||||
FakeNotificationDrawerManager()
|
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
|
|
@ -400,13 +171,11 @@ class InviteListPresenterTests {
|
||||||
val roomListService = FakeRoomListService()
|
val roomListService = FakeRoomListService()
|
||||||
val store = FakeSeenInvitesStore()
|
val store = FakeSeenInvitesStore()
|
||||||
store.publishRoomIds(setOf(A_ROOM_ID))
|
store.publishRoomIds(setOf(A_ROOM_ID))
|
||||||
val presenter = InviteListPresenter(
|
val presenter = createInviteListPresenter(
|
||||||
FakeMatrixClient(
|
FakeMatrixClient(
|
||||||
roomListService = roomListService,
|
roomListService = roomListService,
|
||||||
),
|
),
|
||||||
store,
|
store,
|
||||||
FakeAnalyticsService(),
|
|
||||||
FakeNotificationDrawerManager()
|
|
||||||
)
|
)
|
||||||
moleculeFlow(RecompositionMode.Immediate) {
|
moleculeFlow(RecompositionMode.Immediate) {
|
||||||
presenter.present()
|
presenter.present()
|
||||||
|
|
@ -494,15 +263,13 @@ class InviteListPresenterTests {
|
||||||
return awaitItem()
|
return awaitItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createPresenter(
|
private fun createInviteListPresenter(
|
||||||
client: MatrixClient,
|
client: MatrixClient,
|
||||||
seenInvitesStore: SeenInvitesStore = FakeSeenInvitesStore(),
|
seenInvitesStore: SeenInvitesStore = FakeSeenInvitesStore(),
|
||||||
fakeAnalyticsService: AnalyticsService = FakeAnalyticsService(),
|
acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState> = Presenter { anAcceptDeclineInviteState() },
|
||||||
notificationDrawerManager: NotificationDrawerManager = FakeNotificationDrawerManager()
|
|
||||||
) = InviteListPresenter(
|
) = InviteListPresenter(
|
||||||
client,
|
client,
|
||||||
seenInvitesStore,
|
seenInvitesStore,
|
||||||
fakeAnalyticsService,
|
acceptDeclineInvitePresenter = acceptDeclineInvitePresenter,
|
||||||
notificationDrawerManager
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -23,7 +23,7 @@ import androidx.compose.runtime.produceState
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.features.invite.api.response.AcceptDeclineInviteEvents
|
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.api.response.InviteData
|
||||||
import io.element.android.features.roomdirectory.api.RoomDescription
|
import io.element.android.features.roomdirectory.api.RoomDescription
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
|
@ -39,7 +39,7 @@ class JoinRoomPresenter @AssistedInject constructor(
|
||||||
@Assisted private val roomId: RoomId,
|
@Assisted private val roomId: RoomId,
|
||||||
@Assisted private val roomDescription: Optional<RoomDescription>,
|
@Assisted private val roomDescription: Optional<RoomDescription>,
|
||||||
private val matrixClient: MatrixClient,
|
private val matrixClient: MatrixClient,
|
||||||
private val acceptDeclineInvitePresenter: AcceptDeclineInvitePresenter,
|
private val acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
|
||||||
) : Presenter<JoinRoomState> {
|
) : Presenter<JoinRoomState> {
|
||||||
|
|
||||||
interface Factory {
|
interface Factory {
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,7 @@ private fun JoinRoomContent(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun JoinRoomMembersCount(memberCount: Long) {
|
private fun JoinRoomMembersCount(memberCount: Long) {
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -227,7 +227,7 @@ private fun JoinRoomTopBar(
|
||||||
|
|
||||||
@PreviewLightDark
|
@PreviewLightDark
|
||||||
@Composable
|
@Composable
|
||||||
fun JoinRoomViewPreview(@PreviewParameter(JoinRoomStateProvider::class) state: JoinRoomState) = ElementPreview {
|
internal fun JoinRoomViewPreview(@PreviewParameter(JoinRoomStateProvider::class) state: JoinRoomState) = ElementPreview {
|
||||||
JoinRoomView(
|
JoinRoomView(
|
||||||
state = state,
|
state = state,
|
||||||
onBackPressed = { }
|
onBackPressed = { }
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,13 @@ package io.element.android.features.joinroom.impl.di
|
||||||
import com.squareup.anvil.annotations.ContributesTo
|
import com.squareup.anvil.annotations.ContributesTo
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
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.joinroom.impl.JoinRoomPresenter
|
||||||
import io.element.android.features.roomdirectory.api.RoomDescription
|
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.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
|
||||||
import java.util.Optional
|
import java.util.Optional
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
|
|
@ -33,9 +33,8 @@ import java.util.Optional
|
||||||
object JoinRoomModule {
|
object JoinRoomModule {
|
||||||
@Provides
|
@Provides
|
||||||
fun providesJoinRoomPresenterFactory(
|
fun providesJoinRoomPresenterFactory(
|
||||||
roomListService: RoomListService,
|
|
||||||
client: MatrixClient,
|
client: MatrixClient,
|
||||||
acceptDeclineInvitePresenter: AcceptDeclineInvitePresenter,
|
acceptDeclineInvitePresenter: Presenter<AcceptDeclineInviteState>,
|
||||||
): JoinRoomPresenter.Factory {
|
): JoinRoomPresenter.Factory {
|
||||||
return object : JoinRoomPresenter.Factory {
|
return object : JoinRoomPresenter.Factory {
|
||||||
override fun create(roomId: RoomId, roomDescription: Optional<RoomDescription>): JoinRoomPresenter {
|
override fun create(roomId: RoomId, roomDescription: Optional<RoomDescription>): JoinRoomPresenter {
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ class LeaveRoomPresenterImplTest {
|
||||||
givenGetRoomResult(
|
givenGetRoomResult(
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
result = FakeMatrixRoom().apply {
|
result = FakeMatrixRoom().apply {
|
||||||
givenLeaveRoomError(RuntimeException("Blimey!"))
|
this.leaveRoomLambda = { Result.failure(RuntimeException("Blimey!"))}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -210,7 +210,7 @@ class LeaveRoomPresenterImplTest {
|
||||||
givenGetRoomResult(
|
givenGetRoomResult(
|
||||||
roomId = A_ROOM_ID,
|
roomId = A_ROOM_ID,
|
||||||
result = FakeMatrixRoom().apply {
|
result = FakeMatrixRoom().apply {
|
||||||
givenLeaveRoomError(RuntimeException("Blimey!"))
|
this.leaveRoomLambda = { Result.failure(RuntimeException("Blimey!"))}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,11 @@ package io.element.android.features.location.impl.common.actions
|
||||||
|
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.location.api.Location
|
import io.element.android.features.location.api.Location
|
||||||
|
import org.junit.Ignore
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
|
|
||||||
|
@Ignore
|
||||||
internal class AndroidLocationActionsTest {
|
internal class AndroidLocationActionsTest {
|
||||||
// We use an Android-native encoder in the actual app, switch to an equivalent JVM one for the tests
|
// 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")
|
private fun urlEncoder(input: String) = URLEncoder.encode(input, "US-ASCII")
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,8 @@ fun RoomDirectoryView(
|
||||||
onResultClicked = onResultClicked,
|
onResultClicked = onResultClicked,
|
||||||
onJoinClicked = ::joinRoom,
|
onJoinClicked = ::joinRoom,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(padding)
|
.padding(padding)
|
||||||
.consumeWindowInsets(padding)
|
.consumeWindowInsets(padding)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -199,10 +199,10 @@ private fun RoomDirectoryRoomList(
|
||||||
@Composable
|
@Composable
|
||||||
private fun LoadMoreIndicator(modifier: Modifier = Modifier) {
|
private fun LoadMoreIndicator(modifier: Modifier = Modifier) {
|
||||||
Box(
|
Box(
|
||||||
modifier
|
modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.wrapContentHeight()
|
.wrapContentHeight()
|
||||||
.padding(24.dp),
|
.padding(24.dp),
|
||||||
contentAlignment = Alignment.Center,
|
contentAlignment = Alignment.Center,
|
||||||
) {
|
) {
|
||||||
CircularProgressIndicator(
|
CircularProgressIndicator(
|
||||||
|
|
@ -273,14 +273,14 @@ private fun RoomDirectoryRoomRow(
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable(enabled = roomDescription.canBeJoined, onClick = onClick)
|
.clickable(enabled = roomDescription.canBeJoined, onClick = onClick)
|
||||||
.padding(
|
.padding(
|
||||||
top = 12.dp,
|
top = 12.dp,
|
||||||
bottom = 12.dp,
|
bottom = 12.dp,
|
||||||
start = 16.dp,
|
start = 16.dp,
|
||||||
)
|
)
|
||||||
.height(IntrinsicSize.Min),
|
.height(IntrinsicSize.Min),
|
||||||
) {
|
) {
|
||||||
Avatar(
|
Avatar(
|
||||||
avatarData = roomDescription.avatarData(AvatarSize.RoomDirectoryItem),
|
avatarData = roomDescription.avatarData(AvatarSize.RoomDirectoryItem),
|
||||||
|
|
@ -288,8 +288,8 @@ private fun RoomDirectoryRoomRow(
|
||||||
)
|
)
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.padding(start = 16.dp)
|
.padding(start = 16.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = roomDescription.name,
|
text = roomDescription.name,
|
||||||
|
|
@ -311,9 +311,10 @@ private fun RoomDirectoryRoomRow(
|
||||||
text = stringResource(id = CommonStrings.action_join),
|
text = stringResource(id = CommonStrings.action_join),
|
||||||
color = ElementTheme.colors.textSuccessPrimary,
|
color = ElementTheme.colors.textSuccessPrimary,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.CenterVertically)
|
.align(Alignment.CenterVertically)
|
||||||
.clickable(onClick = onJoinClick)
|
.clickable(onClick = onJoinClick)
|
||||||
.padding(start = 4.dp, end = 12.dp)
|
.padding(start = 4.dp, end = 12.dp)
|
||||||
|
.testTag(TestTags.callToAction.value)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Spacer(modifier = Modifier.width(24.dp))
|
Spacer(modifier = Modifier.width(24.dp))
|
||||||
|
|
|
||||||
|
|
@ -17,16 +17,23 @@
|
||||||
package io.element.android.features.roomdirectory.impl.root
|
package io.element.android.features.roomdirectory.impl.root
|
||||||
|
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
||||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
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.onNodeWithTag
|
||||||
import androidx.compose.ui.test.onNodeWithText
|
import androidx.compose.ui.test.onNodeWithText
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.compose.ui.test.performTextInput
|
import androidx.compose.ui.test.performTextInput
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
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.architecture.AsyncAction
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.testtags.TestTags
|
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.EnsureNeverCalled
|
||||||
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
|
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
|
||||||
import io.element.android.tests.testutils.EventsRecorder
|
import io.element.android.tests.testutils.EventsRecorder
|
||||||
|
|
@ -55,7 +62,24 @@ class RoomDirectoryViewTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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 eventsRecorder = EventsRecorder<RoomDirectoryEvents>()
|
||||||
val state = aRoomDirectoryState(
|
val state = aRoomDirectoryState(
|
||||||
roomDescriptions = aRoomDescriptionList(),
|
roomDescriptions = aRoomDescriptionList(),
|
||||||
|
|
@ -63,7 +87,7 @@ class RoomDirectoryViewTest {
|
||||||
)
|
)
|
||||||
rule.setRoomDirectoryView(state = state)
|
rule.setRoomDirectoryView(state = state)
|
||||||
val clickedRoom = state.roomDescriptions.first()
|
val clickedRoom = state.roomDescriptions.first()
|
||||||
rule.onNodeWithText(clickedRoom.name).performClick()
|
rule.onAllNodesWithTag(TestTags.callToAction.value).onFirst().performClick()
|
||||||
eventsRecorder.assertSingle(RoomDirectoryEvents.JoinRoom(clickedRoom.roomId))
|
eventsRecorder.assertSingle(RoomDirectoryEvents.JoinRoom(clickedRoom.roomId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,12 +124,14 @@ class RoomDirectoryViewTest {
|
||||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRoomDirectoryView(
|
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRoomDirectoryView(
|
||||||
state: RoomDirectoryState,
|
state: RoomDirectoryState,
|
||||||
onBackPressed: () -> Unit = EnsureNeverCalled(),
|
onBackPressed: () -> Unit = EnsureNeverCalled(),
|
||||||
|
onResultClicked: (RoomDescription) -> Unit = EnsureNeverCalledWithParam(),
|
||||||
onRoomJoined: (RoomId) -> Unit = EnsureNeverCalledWithParam(),
|
onRoomJoined: (RoomId) -> Unit = EnsureNeverCalledWithParam(),
|
||||||
) {
|
) {
|
||||||
setContent {
|
setContent {
|
||||||
RoomDirectoryView(
|
RoomDirectoryView(
|
||||||
state = state,
|
state = state,
|
||||||
onRoomClicked = onRoomJoined,
|
onResultClicked = onResultClicked,
|
||||||
|
onRoomJoined = onRoomJoined,
|
||||||
onBackPressed = onBackPressed,
|
onBackPressed = onBackPressed,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,3 +100,4 @@ interface MatrixClient : Closeable {
|
||||||
suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit>
|
suspend fun trackRecentlyVisitedRoom(roomId: RoomId): Result<Unit>
|
||||||
suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>>
|
suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.oidc.AccountManagementAction
|
||||||
import io.element.android.libraries.matrix.api.pusher.PushersService
|
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.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.room.RoomMembershipObserver
|
||||||
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
import io.element.android.libraries.matrix.api.roomdirectory.RoomDirectoryService
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
import io.element.android.libraries.matrix.api.roomlist.RoomListService
|
||||||
|
|
@ -51,7 +52,9 @@ import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.test.TestScope
|
import kotlinx.coroutines.test.TestScope
|
||||||
|
import java.util.Optional
|
||||||
|
|
||||||
class FakeMatrixClient(
|
class FakeMatrixClient(
|
||||||
override val sessionId: SessionId = A_SESSION_ID,
|
override val sessionId: SessionId = A_SESSION_ID,
|
||||||
|
|
@ -94,10 +97,14 @@ class FakeMatrixClient(
|
||||||
private var setDisplayNameResult: Result<Unit> = Result.success(Unit)
|
private var setDisplayNameResult: Result<Unit> = Result.success(Unit)
|
||||||
private var uploadAvatarResult: Result<Unit> = Result.success(Unit)
|
private var uploadAvatarResult: Result<Unit> = Result.success(Unit)
|
||||||
private var removeAvatarResult: 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)
|
Result.success(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var getRoomInfoFlowLambda = { _: RoomId ->
|
||||||
|
flowOf<Optional<MatrixRoomInfo>>(Optional.empty())
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getRoom(roomId: RoomId): MatrixRoom? {
|
override suspend fun getRoom(roomId: RoomId): MatrixRoom? {
|
||||||
return getRoomResults[roomId]
|
return getRoomResults[roomId]
|
||||||
}
|
}
|
||||||
|
|
@ -267,4 +274,7 @@ class FakeMatrixClient(
|
||||||
override suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>> {
|
override suspend fun getRecentlyVisitedRooms(): Result<List<RoomId>> {
|
||||||
return Result.success(visitedRoomsId)
|
return Result.success(visitedRoomsId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getRoomInfoFlow(roomId: RoomId) = getRoomInfoFlowLambda(roomId)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ class FakeMatrixRoom(
|
||||||
var removedAvatar: Boolean = false
|
var removedAvatar: Boolean = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private var leaveRoomError: Throwable? = null
|
var leaveRoomLambda: (() -> Result<Unit>) = { Result.success(Unit) }
|
||||||
|
|
||||||
private val _roomInfoFlow: MutableSharedFlow<MatrixRoomInfo> = MutableSharedFlow(replay = 1)
|
private val _roomInfoFlow: MutableSharedFlow<MatrixRoomInfo> = MutableSharedFlow(replay = 1)
|
||||||
override val roomInfoFlow: Flow<MatrixRoomInfo> = _roomInfoFlow
|
override val roomInfoFlow: Flow<MatrixRoomInfo> = _roomInfoFlow
|
||||||
|
|
@ -315,8 +315,9 @@ class FakeMatrixRoom(
|
||||||
return Result.success(Unit)
|
return Result.success(Unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun leave(): Result<Unit> =
|
override suspend fun leave(): Result<Unit> {
|
||||||
leaveRoomError?.let { Result.failure(it) } ?: Result.success(Unit)
|
return leaveRoomLambda()
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun join(): Result<Unit> {
|
override suspend fun join(): Result<Unit> {
|
||||||
return joinRoomResult
|
return joinRoomResult
|
||||||
|
|
@ -542,10 +543,6 @@ class FakeMatrixRoom(
|
||||||
|
|
||||||
override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver> = getWidgetDriverResult
|
override fun getWidgetDriver(widgetSettings: MatrixWidgetSettings): Result<MatrixWidgetDriver> = getWidgetDriverResult
|
||||||
|
|
||||||
fun givenLeaveRoomError(throwable: Throwable?) {
|
|
||||||
this.leaveRoomError = throwable
|
|
||||||
}
|
|
||||||
|
|
||||||
fun givenRoomMembersState(state: MatrixRoomMembersState) {
|
fun givenRoomMembersState(state: MatrixRoomMembersState) {
|
||||||
membersStateFlow.value = state
|
membersStateFlow.value = state
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.RoomListFilter
|
||||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.SharedFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.getAndUpdate
|
import kotlinx.coroutines.flow.getAndUpdate
|
||||||
|
|
||||||
|
|
@ -32,6 +33,8 @@ data class SimplePagedRoomList(
|
||||||
override val pageSize: Int = Int.MAX_VALUE
|
override val pageSize: Int = Int.MAX_VALUE
|
||||||
override val loadedPages = MutableStateFlow(1)
|
override val loadedPages = MutableStateFlow(1)
|
||||||
|
|
||||||
|
override val filteredSummaries: SharedFlow<List<RoomSummary>> = summaries
|
||||||
|
|
||||||
override suspend fun loadMore() {
|
override suspend fun loadMore() {
|
||||||
// No-op
|
// No-op
|
||||||
loadedPages.getAndUpdate { it + 1 }
|
loadedPages.getAndUpdate { it + 1 }
|
||||||
|
|
|
||||||
|
|
@ -105,4 +105,9 @@ object TestTags {
|
||||||
* Search field.
|
* Search field.
|
||||||
*/
|
*/
|
||||||
val searchTextField = TestTag("search_text_field")
|
val searchTextField = TestTag("search_text_field")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic call to action
|
||||||
|
*/
|
||||||
|
val callToAction = TestTag("call_to_action")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue