From 36fb3e251dab4840a879f7a6ebb2403a2ababce6 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 4 Feb 2026 14:42:57 +0100 Subject: [PATCH] Add tests for SpaceFiltersPresenter and SpaceFiltersView and fix quality --- .../android/features/home/impl/HomeState.kt | 2 +- .../home/impl/components/HomeTopBar.kt | 46 ++-- .../features/home/impl/di/RoomListModule.kt | 5 + .../home/impl/roomlist/RoomListPresenter.kt | 2 - .../spacefilters/SpaceFiltersPresenter.kt | 5 +- .../impl/spacefilters/SpaceFiltersState.kt | 3 +- .../filters/RoomListFiltersPresenterTest.kt | 21 +- .../spacefilters/SpaceFiltersPresenterTest.kt | 223 ++++++++++++++++++ .../impl/spacefilters/SpaceFiltersViewTest.kt | 80 +++++++ .../matrix/api/roomlist/RoomListFilter.kt | 4 +- .../matrix/test/spaces/FakeSpaceService.kt | 6 +- .../tests/konsist/KonsistPreviewTest.kt | 1 + 12 files changed, 345 insertions(+), 53 deletions(-) create mode 100644 features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersPresenterTest.kt create mode 100644 features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersViewTest.kt diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt index e27ccb72ae..dbb994e23e 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/HomeState.kt @@ -32,7 +32,7 @@ data class HomeState( val directLogoutState: DirectLogoutState, val eventSink: (HomeEvent) -> Unit, ) { - val isBackHandlerEnabled = currentHomeNavigationBarItem != HomeNavigationBarItem.Chats || roomListState.spaceFiltersState is SpaceFiltersState.Selected + val isBackHandlerEnabled = currentHomeNavigationBarItem != HomeNavigationBarItem.Chats || roomListState.spaceFiltersState is SpaceFiltersState.Selected val displayActions = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats val displayRoomListFilters = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats && roomListState.displayFilters val showNavigationBar = homeSpacesState.canCreateSpaces || homeSpacesState.spaceRooms.isNotEmpty() diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt index fb7388e9e8..f8786c544c 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/components/HomeTopBar.kt @@ -375,6 +375,29 @@ internal fun HomeTopBarPreview() = ElementPreview { ) } +@OptIn(ExperimentalMaterial3Api::class) +@PreviewsDayNight +@Composable +internal fun HomeTopBarSpaceFiltersSelectedPreview() = ElementPreview { + HomeTopBar( + selectedNavigationItem = HomeNavigationBarItem.Chats, + currentUserAndNeighbors = persistentListOf(MatrixUser(UserId("@id:domain"), "Alice")), + showAvatarIndicator = false, + areSearchResultsDisplayed = false, + scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()), + onOpenSettings = {}, + onAccountSwitch = {}, + onToggleSearch = {}, + onCreateSpace = {}, + canCreateSpaces = true, + canReportBug = true, + displayFilters = true, + filtersState = aRoomListFiltersState(), + spaceFiltersState = aSelectedSpaceFiltersState(), + onMenuActionClick = {}, + ) +} + @OptIn(ExperimentalMaterial3Api::class) @PreviewsDayNight @Composable @@ -443,26 +466,3 @@ internal fun HomeTopBarMultiAccountPreview() = ElementPreview { onMenuActionClick = {}, ) } - -@OptIn(ExperimentalMaterial3Api::class) -@PreviewsDayNight -@Composable -internal fun HomeTopSpaceFiltersSelectedPreview() = ElementPreview { - HomeTopBar( - selectedNavigationItem = HomeNavigationBarItem.Chats, - currentUserAndNeighbors = persistentListOf(MatrixUser(UserId("@id:domain"), "Alice")), - showAvatarIndicator = false, - areSearchResultsDisplayed = false, - scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()), - onOpenSettings = {}, - onAccountSwitch = {}, - onToggleSearch = {}, - onCreateSpace = {}, - canCreateSpaces = true, - canReportBug = true, - displayFilters = true, - filtersState = aRoomListFiltersState(), - spaceFiltersState = aSelectedSpaceFiltersState(), - onMenuActionClick = {}, - ) -} diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/di/RoomListModule.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/di/RoomListModule.kt index ea80c1b3cb..1eeba4fff7 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/di/RoomListModule.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/di/RoomListModule.kt @@ -17,6 +17,8 @@ import io.element.android.features.home.impl.roomlist.RoomListPresenter import io.element.android.features.home.impl.roomlist.RoomListState import io.element.android.features.home.impl.search.RoomListSearchPresenter import io.element.android.features.home.impl.search.RoomListSearchState +import io.element.android.features.home.impl.spacefilters.SpaceFiltersPresenter +import io.element.android.features.home.impl.spacefilters.SpaceFiltersState import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.di.SessionScope @@ -31,4 +33,7 @@ interface RoomListModule { @Binds fun bindFiltersPresenter(presenter: RoomListFiltersPresenter): Presenter + + @Binds + fun bindSpaceFiltersPresenter(presenter: SpaceFiltersPresenter): Presenter } diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt index ae016a31c1..2010555cd7 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/roomlist/RoomListPresenter.kt @@ -28,9 +28,7 @@ import im.vector.app.features.analytics.plan.Interaction import io.element.android.features.announcement.api.Announcement import io.element.android.features.announcement.api.AnnouncementService import io.element.android.features.home.impl.datasource.RoomListDataSource -import io.element.android.features.home.impl.filters.RoomListFilter.People import io.element.android.features.home.impl.filters.RoomListFilter.Rooms -import io.element.android.features.home.impl.filters.RoomListFiltersEvent import io.element.android.features.home.impl.filters.RoomListFiltersState import io.element.android.features.home.impl.filters.into import io.element.android.features.home.impl.search.RoomListSearchEvent diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersPresenter.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersPresenter.kt index 3b1eaddd30..a3e283b341 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersPresenter.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersPresenter.kt @@ -15,9 +15,8 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import dev.zacsweers.metro.ContributesBinding +import dev.zacsweers.metro.Inject import io.element.android.libraries.architecture.Presenter -import io.element.android.libraries.di.SessionScope import io.element.android.libraries.featureflag.api.FeatureFlagService import io.element.android.libraries.featureflag.api.FeatureFlags import io.element.android.libraries.matrix.api.MatrixClient @@ -26,7 +25,7 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.map -@ContributesBinding(SessionScope::class) +@Inject class SpaceFiltersPresenter( private val featureFlagService: FeatureFlagService, private val matrixClient: MatrixClient, diff --git a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersState.kt b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersState.kt index bef781ae1e..347439e853 100644 --- a/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersState.kt +++ b/features/home/impl/src/main/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersState.kt @@ -8,11 +8,13 @@ package io.element.android.features.home.impl.spacefilters import androidx.compose.foundation.text.input.TextFieldState +import androidx.compose.runtime.Immutable import io.element.android.libraries.matrix.api.roomlist.RoomListFilter import io.element.android.libraries.matrix.api.spaces.SpaceServiceFilter import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList +@Immutable sealed interface SpaceFiltersState { data object Disabled : SpaceFiltersState @@ -52,4 +54,3 @@ fun SpaceFiltersState.selectedFilter(): SpaceServiceFilter? { fun SpaceServiceFilter?.into(): RoomListFilter? { return this?.let { RoomListFilter.Identifiers(descendants) } } - diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersPresenterTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersPresenterTest.kt index bb00a9edac..9fb87c0eec 100644 --- a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersPresenterTest.kt +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/filters/RoomListFiltersPresenterTest.kt @@ -11,14 +11,6 @@ package io.element.android.features.home.impl.filters import com.google.common.truth.Truth.assertThat import io.element.android.features.home.impl.filters.selection.DefaultFilterSelectionStrategy import io.element.android.features.home.impl.filters.selection.FilterSelectionState -import io.element.android.libraries.dateformatter.api.DateFormatter -import io.element.android.libraries.dateformatter.test.FakeDateFormatter -import io.element.android.libraries.eventformatter.api.RoomLatestEventFormatter -import io.element.android.libraries.eventformatter.test.FakeRoomLatestEventFormatter -import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService -import io.element.android.libraries.matrix.api.roomlist.RoomListService -import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService -import io.element.android.libraries.matrix.test.roomlist.FakeRoomListService import io.element.android.tests.testutils.awaitLastSequentialItem import io.element.android.tests.testutils.test import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -49,8 +41,7 @@ class RoomListFiltersPresenterTest { @Test @OptIn(ExperimentalCoroutinesApi::class) fun `present - toggle rooms filter`() = runTest { - val roomListService = FakeRoomListService() - val presenter = createRoomListFiltersPresenter(roomListService) + val presenter = createRoomListFiltersPresenter() presenter.test { awaitItem().eventSink.invoke(RoomListFiltersEvent.ToggleFilter(RoomListFilter.Rooms)) awaitLastSequentialItem().let { state -> @@ -84,8 +75,7 @@ class RoomListFiltersPresenterTest { @Test @OptIn(ExperimentalCoroutinesApi::class) fun `present - clear filters event`() = runTest { - val roomListService = FakeRoomListService() - val presenter = createRoomListFiltersPresenter(roomListService) + val presenter = createRoomListFiltersPresenter() presenter.test { awaitItem().eventSink.invoke(RoomListFiltersEvent.ToggleFilter(RoomListFilter.Rooms)) awaitLastSequentialItem().let { state -> @@ -105,12 +95,7 @@ private fun filterSelectionState(filter: RoomListFilter, selected: Boolean) = Fi isSelected = selected, ) -private fun TestScope.createRoomListFiltersPresenter( - roomListService: RoomListService = FakeRoomListService(), - notificationSettingsService: NotificationSettingsService = FakeNotificationSettingsService(), - dateFormatter: DateFormatter = FakeDateFormatter(), - roomLatestEventFormatter: RoomLatestEventFormatter = FakeRoomLatestEventFormatter(), -): RoomListFiltersPresenter { +private fun TestScope.createRoomListFiltersPresenter(): RoomListFiltersPresenter { return RoomListFiltersPresenter( filterSelectionStrategy = DefaultFilterSelectionStrategy(), ) diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersPresenterTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersPresenterTest.kt new file mode 100644 index 0000000000..8621721e2a --- /dev/null +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersPresenterTest.kt @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.home.impl.spacefilters + +import com.google.common.truth.Truth.assertThat +import io.element.android.libraries.featureflag.api.FeatureFlags +import io.element.android.libraries.featureflag.test.FakeFeatureFlagService +import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.matrix.test.FakeMatrixClient +import io.element.android.libraries.matrix.test.spaces.FakeSpaceService +import io.element.android.tests.testutils.awaitLastSequentialItem +import io.element.android.tests.testutils.test +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Test + +@OptIn(ExperimentalCoroutinesApi::class) +class SpaceFiltersPresenterTest { + @Test + fun `present - when feature flag is disabled returns Disabled state`() = runTest { + val presenter = createSpaceFiltersPresenter( + featureFlagService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.RoomListSpaceFilters.key to false) + ) + ) + presenter.test { + val state = awaitItem() + assertThat(state).isEqualTo(SpaceFiltersState.Disabled) + } + } + + @Test + fun `present - when feature flag is enabled returns Unselected state initially`() = runTest { + val presenter = createSpaceFiltersPresenter( + featureFlagService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.RoomListSpaceFilters.key to true) + ) + ) + presenter.test { + val state = awaitLastSequentialItem() + assertThat(state).isInstanceOf(SpaceFiltersState.Unselected::class.java) + } + } + + @Test + fun `present - ShowFilters event transitions from Unselected to Selecting`() = runTest { + val presenter = createSpaceFiltersPresenter( + featureFlagService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.RoomListSpaceFilters.key to true) + ) + ) + presenter.test { + val unselectedState = awaitLastSequentialItem() as SpaceFiltersState.Unselected + unselectedState.eventSink(SpaceFiltersEvent.Unselected.ShowFilters) + + val selectingState = awaitLastSequentialItem() + assertThat(selectingState).isInstanceOf(SpaceFiltersState.Selecting::class.java) + } + } + + @Test + fun `present - Cancel event in Selecting state transitions back to Unselected`() = runTest { + val presenter = createSpaceFiltersPresenter( + featureFlagService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.RoomListSpaceFilters.key to true) + ) + ) + presenter.test { + // Start in Unselected + val unselectedState = awaitLastSequentialItem() as SpaceFiltersState.Unselected + unselectedState.eventSink(SpaceFiltersEvent.Unselected.ShowFilters) + + // Now in Selecting + val selectingState = awaitLastSequentialItem() as SpaceFiltersState.Selecting + selectingState.eventSink(SpaceFiltersEvent.Selecting.Cancel) + + // Back to Unselected + val finalState = awaitLastSequentialItem() + assertThat(finalState).isInstanceOf(SpaceFiltersState.Unselected::class.java) + } + } + + @Test + fun `present - SelectFilter event in Selecting state transitions to Selected`() = runTest { + val spaceFilter = aSpaceServiceFilter(displayName = "Test Space") + val presenter = createSpaceFiltersPresenter( + featureFlagService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.RoomListSpaceFilters.key to true) + ) + ) + presenter.test { + // Start in Unselected + val unselectedState = awaitLastSequentialItem() as SpaceFiltersState.Unselected + unselectedState.eventSink(SpaceFiltersEvent.Unselected.ShowFilters) + + // Now in Selecting + val selectingState = awaitLastSequentialItem() as SpaceFiltersState.Selecting + selectingState.eventSink(SpaceFiltersEvent.Selecting.SelectFilter(spaceFilter)) + + // Now in Selected + val selectedState = awaitLastSequentialItem() as SpaceFiltersState.Selected + assertThat(selectedState.selectedFilter).isEqualTo(spaceFilter) + } + } + + @Test + fun `present - ClearSelection event in Selected state transitions back to Unselected`() = runTest { + val spaceFilter = aSpaceServiceFilter(displayName = "Test Space") + val presenter = createSpaceFiltersPresenter( + featureFlagService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.RoomListSpaceFilters.key to true) + ) + ) + presenter.test { + // Start in Unselected + val unselectedState = awaitLastSequentialItem() as SpaceFiltersState.Unselected + unselectedState.eventSink(SpaceFiltersEvent.Unselected.ShowFilters) + + // Now in Selecting + val selectingState = awaitLastSequentialItem() as SpaceFiltersState.Selecting + selectingState.eventSink(SpaceFiltersEvent.Selecting.SelectFilter(spaceFilter)) + + // Now in Selected + val selectedState = awaitLastSequentialItem() as SpaceFiltersState.Selected + selectedState.eventSink(SpaceFiltersEvent.Selected.ClearSelection) + + // Back to Unselected + val finalState = awaitLastSequentialItem() + assertThat(finalState).isInstanceOf(SpaceFiltersState.Unselected::class.java) + } + } + + @Test + fun `present - available filters are passed from SpaceService`() = runTest { + val spaceFilter1 = aSpaceServiceFilter(displayName = "Work", roomId = RoomId("!work:example.com")) + val spaceFilter2 = aSpaceServiceFilter(displayName = "Personal", roomId = RoomId("!personal:example.com")) + val spaceFilters = listOf(spaceFilter1, spaceFilter2) + + val spaceService = FakeSpaceService() + val matrixClient = FakeMatrixClient(spaceService = spaceService) + + val presenter = createSpaceFiltersPresenter( + featureFlagService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.RoomListSpaceFilters.key to true) + ), + matrixClient = matrixClient, + ) + presenter.test { + // Start in Unselected + val unselectedState = awaitLastSequentialItem() as SpaceFiltersState.Unselected + unselectedState.eventSink(SpaceFiltersEvent.Unselected.ShowFilters) + + // Emit space filters + spaceService.emitSpaceFilters(spaceFilters) + + // Now in Selecting with available filters + val selectingState = awaitLastSequentialItem() as SpaceFiltersState.Selecting + assertThat(selectingState.availableFilters).containsExactly(spaceFilter1, spaceFilter2).inOrder() + } + } + + @Test + fun `present - selected filter stays in sync when available filters update`() = runTest { + val originalFilter = aSpaceServiceFilter( + displayName = "Work", + roomId = RoomId("!work:example.com"), + descendants = listOf(RoomId("!room1:example.com")) + ) + val updatedFilter = aSpaceServiceFilter( + displayName = "Work", + roomId = RoomId("!work:example.com"), + descendants = listOf(RoomId("!room1:example.com"), RoomId("!room2:example.com")) + ) + + val spaceService = FakeSpaceService() + val matrixClient = FakeMatrixClient(spaceService = spaceService) + + val presenter = createSpaceFiltersPresenter( + featureFlagService = FakeFeatureFlagService( + initialState = mapOf(FeatureFlags.RoomListSpaceFilters.key to true) + ), + matrixClient = matrixClient, + ) + presenter.test { + // Start in Unselected + val unselectedState = awaitLastSequentialItem() as SpaceFiltersState.Unselected + unselectedState.eventSink(SpaceFiltersEvent.Unselected.ShowFilters) + + // Emit initial space filters + spaceService.emitSpaceFilters(listOf(originalFilter)) + + // Now in Selecting + val selectingState = awaitLastSequentialItem() as SpaceFiltersState.Selecting + selectingState.eventSink(SpaceFiltersEvent.Selecting.SelectFilter(originalFilter)) + + // Now in Selected + val selectedState = awaitLastSequentialItem() as SpaceFiltersState.Selected + assertThat(selectedState.selectedFilter.descendants).hasSize(1) + + // Emit updated space filters + spaceService.emitSpaceFilters(listOf(updatedFilter)) + + // Selected filter should be updated + val updatedSelectedState = awaitLastSequentialItem() as SpaceFiltersState.Selected + assertThat(updatedSelectedState.selectedFilter.descendants).hasSize(2) + } + } + + private fun createSpaceFiltersPresenter( + featureFlagService: FakeFeatureFlagService = FakeFeatureFlagService(), + matrixClient: FakeMatrixClient = FakeMatrixClient(), + ): SpaceFiltersPresenter { + return SpaceFiltersPresenter( + featureFlagService = featureFlagService, + matrixClient = matrixClient, + ) + } +} diff --git a/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersViewTest.kt b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersViewTest.kt new file mode 100644 index 0000000000..5c1325b107 --- /dev/null +++ b/features/home/impl/src/test/kotlin/io/element/android/features/home/impl/spacefilters/SpaceFiltersViewTest.kt @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.home.impl.spacefilters + +import androidx.activity.ComponentActivity +import androidx.compose.ui.test.junit4.AndroidComposeTestRule +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.test.ext.junit.runners.AndroidJUnit4 +import io.element.android.libraries.matrix.test.A_ROOM_ALIAS +import io.element.android.tests.testutils.EventsRecorder +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TestRule +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class SpaceFiltersViewTest { + @get:Rule + val rule = createAndroidComposeRule() + + @Test + fun `clicking on a filter with alias shows display name and alias`() { + val filter = aSpaceServiceFilter( + displayName = "Test Space", + canonicalAlias = A_ROOM_ALIAS, + ) + val eventsRecorder = EventsRecorder() + rule.setSpaceFiltersView( + state = aSelectingSpaceFiltersState( + availableFilters = listOf(filter), + eventSink = eventsRecorder, + ) + ) + + // Both display name and alias should be visible + rule.onNodeWithText(filter.spaceRoom.displayName).assertExists() + rule.onNodeWithText(A_ROOM_ALIAS.value).assertExists() + + rule.onNodeWithText(filter.spaceRoom.displayName).performClick() + + eventsRecorder.assertSingle(SpaceFiltersEvent.Selecting.SelectFilter(filter)) + } + + @Test + fun `multiple filters are displayed and clickable`() { + val filter1 = aSpaceServiceFilter(displayName = "Space One") + val filter2 = aSpaceServiceFilter(displayName = "Space Two") + val eventsRecorder = EventsRecorder() + rule.setSpaceFiltersView( + state = aSelectingSpaceFiltersState( + availableFilters = listOf(filter1, filter2), + eventSink = eventsRecorder, + ) + ) + + // Both filters should be visible + rule.onNodeWithText(filter1.spaceRoom.displayName).assertExists() + rule.onNodeWithText(filter2.spaceRoom.displayName).assertExists() + + // Click on second filter + rule.onNodeWithText(filter2.spaceRoom.displayName).performClick() + + eventsRecorder.assertSingle(SpaceFiltersEvent.Selecting.SelectFilter(filter2)) + } +} + +private fun AndroidComposeTestRule.setSpaceFiltersView( + state: SpaceFiltersState, +) { + setContent { + SpaceFiltersView(state = state) + } +} diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListFilter.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListFilter.kt index b4abedd75d..11eed2128b 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListFilter.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/roomlist/RoomListFilter.kt @@ -44,8 +44,8 @@ sealed interface RoomListFilter { ) : RoomListFilter data class Identifiers( - val values : List, - ): RoomListFilter + val values: List, + ) : RoomListFilter /** * A filter that matches rooms that are unread. diff --git a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/spaces/FakeSpaceService.kt b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/spaces/FakeSpaceService.kt index e4c1c9475d..f6deef5c9a 100644 --- a/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/spaces/FakeSpaceService.kt +++ b/libraries/matrix/test/src/main/kotlin/io/element/android/libraries/matrix/test/spaces/FakeSpaceService.kt @@ -37,12 +37,12 @@ class FakeSpaceService( _topLevelSpacesFlow.emit(value) } - private val _spaceServiceFiltersFlow = MutableSharedFlow>() + private val _spaceFiltersFlow = MutableSharedFlow>() override val spaceFiltersFlow: SharedFlow> - get() = _spaceServiceFiltersFlow.asSharedFlow() + get() = _spaceFiltersFlow.asSharedFlow() suspend fun emitSpaceFilters(value: List) { - _spaceServiceFiltersFlow.emit(value) + _spaceFiltersFlow.emit(value) } override suspend fun joinedParents(spaceId: RoomId): Result> { diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt index 245f841d1a..261ec3834d 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt @@ -89,6 +89,7 @@ class KonsistPreviewTest { "GradientFloatingActionButtonCircleShapePreview", "HeaderFooterPageScrollablePreview", "HomeTopBarMultiAccountPreview", + "HomeTopBarSpaceFiltersSelectedPreview", "HomeTopBarSpacesPreview", "HomeTopBarWithIndicatorPreview", "IconsOtherPreview",