quality(roles and permissions): fix tests

This commit is contained in:
ganfra
2025-11-05 17:54:02 +01:00
parent fca62a333e
commit 5f007fd50c
5 changed files with 70 additions and 113 deletions

View File

@@ -74,6 +74,7 @@ fun ChangeRoomPermissionsView(
selectedOption = state.selectedRoleForType(permissionType),
options = SelectableRole.entries.toImmutableList(),
onSelectOption = { role ->
println("Selected $role for $permissionType")
state.eventSink(
ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(
action = permissionType,

View File

@@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.roomdetails.impl.rolesandpermissions.permissions
package io.element.android.features.rolesandpermissions.impl.permissions
import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
@@ -17,7 +17,6 @@ import im.vector.app.features.analytics.plan.RoomModeration
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.room.RoomMember.Role.Admin
import io.element.android.libraries.matrix.api.room.RoomMember.Role.Moderator
import io.element.android.libraries.matrix.api.room.RoomMember.Role.User
import io.element.android.libraries.matrix.api.room.powerlevels.RoomPowerLevelsValues
import io.element.android.libraries.matrix.test.room.FakeBaseRoom
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
@@ -26,19 +25,17 @@ import io.element.android.services.analytics.test.FakeAnalyticsService
import kotlinx.coroutines.test.runTest
import org.junit.Test
class ChangeBaseRoomPermissionsPresenterTest {
class ChangeRoomPermissionsPresenterTest {
@Test
fun `present - initial state`() = runTest {
val section = ChangeRoomPermissionsSection.RoomDetails
val presenter = createChangeRoomPermissionsPresenter(section = section)
val presenter = createChangeRoomPermissionsPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
// Initial state, no permissions loaded
awaitItem().run {
assertThat(this.section).isEqualTo(section)
assertThat(this.currentPermissions).isNull()
assertThat(this.items).isNotEmpty()
assertThat(this.itemsBySection).isNotEmpty()
assertThat(this.hasChanges).isFalse()
assertThat(this.saveAction).isEqualTo(AsyncAction.Uninitialized)
assertThat(this.confirmExitAction).isEqualTo(AsyncAction.Uninitialized)
@@ -50,42 +47,22 @@ class ChangeBaseRoomPermissionsPresenterTest {
}
@Test
fun `present - RoomDetails section contains the right items`() = runTest {
val section = ChangeRoomPermissionsSection.RoomDetails
val presenter = createChangeRoomPermissionsPresenter(section = section)
fun `present - items by section are correct for room`() = runTest {
val presenter = createChangeRoomPermissionsPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
assertThat(awaitUpdatedItem().items).containsExactly(
val itemsBySection = awaitUpdatedItem().itemsBySection
assertThat(itemsBySection[RoomPermissionsSection.RoomDetails]).containsExactly(
RoomPermissionType.ROOM_NAME,
RoomPermissionType.ROOM_AVATAR,
RoomPermissionType.ROOM_TOPIC,
)
}
}
@Test
fun `present - MessagesAndContent section contains the right items`() = runTest {
val section = ChangeRoomPermissionsSection.MessagesAndContent
val presenter = createChangeRoomPermissionsPresenter(section = section)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
assertThat(awaitUpdatedItem().items).containsExactly(
assertThat(itemsBySection[RoomPermissionsSection.MessagesAndContent]).containsExactly(
RoomPermissionType.SEND_EVENTS,
RoomPermissionType.REDACT_EVENTS,
)
}
}
@Test
fun `present - MembershipModeration section contains the right items`() = runTest {
val section = ChangeRoomPermissionsSection.MembershipModeration
val presenter = createChangeRoomPermissionsPresenter(section = section)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
assertThat(awaitUpdatedItem().items).containsExactly(
assertThat(itemsBySection[RoomPermissionsSection.MembershipModeration]).containsExactly(
RoomPermissionType.INVITE,
RoomPermissionType.KICK,
RoomPermissionType.BAN,
@@ -103,7 +80,7 @@ class ChangeBaseRoomPermissionsPresenterTest {
assertThat(state.currentPermissions?.roomName).isEqualTo(Admin.powerLevel)
assertThat(state.hasChanges).isFalse()
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, SelectableRole.Moderator))
awaitItem().run {
assertThat(currentPermissions?.roomName).isEqualTo(Moderator.powerLevel)
@@ -120,18 +97,18 @@ class ChangeBaseRoomPermissionsPresenterTest {
}.test {
val state = awaitUpdatedItem()
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.INVITE, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.KICK, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.BAN, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.SEND_EVENTS, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.REDACT_EVENTS, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_AVATAR, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_TOPIC, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.INVITE, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.KICK, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.BAN, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.SEND_EVENTS, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.REDACT_EVENTS, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_AVATAR, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_TOPIC, SelectableRole.Moderator))
val items = cancelAndConsumeRemainingEvents()
val itemsBySection = cancelAndConsumeRemainingEvents()
(items.last() as? Event.Item<ChangeRoomPermissionsState>)?.value?.run {
(itemsBySection.last() as? Event.Item<ChangeRoomPermissionsState>)?.value?.run {
assertThat(currentPermissions).isEqualTo(
RoomPowerLevelsValues(
invite = Moderator.powerLevel,
@@ -165,14 +142,14 @@ class ChangeBaseRoomPermissionsPresenterTest {
assertThat(state.currentPermissions?.roomName).isEqualTo(Admin.powerLevel)
assertThat(state.hasChanges).isFalse()
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_AVATAR, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_TOPIC, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.SEND_EVENTS, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.REDACT_EVENTS, User))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.KICK, Admin))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.BAN, Admin))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.INVITE, Admin))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_AVATAR, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_TOPIC, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.SEND_EVENTS, SelectableRole.Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.REDACT_EVENTS, SelectableRole.Everyone))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.KICK, SelectableRole.Admin))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.BAN, SelectableRole.Admin))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.INVITE, SelectableRole.Admin))
skipItems(7)
assertThat(awaitItem().hasChanges).isTrue()
@@ -230,7 +207,7 @@ class ChangeBaseRoomPermissionsPresenterTest {
assertThat(state.currentPermissions?.roomName).isEqualTo(Admin.powerLevel)
assertThat(state.hasChanges).isFalse()
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, SelectableRole.Moderator))
assertThat(awaitItem().hasChanges).isTrue()
state.eventSink(ChangeRoomPermissionsEvent.Save)
@@ -259,7 +236,7 @@ class ChangeBaseRoomPermissionsPresenterTest {
presenter.present()
}.test {
val state = awaitUpdatedItem()
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, Moderator))
state.eventSink(ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, SelectableRole.Moderator))
assertThat(awaitItem().hasChanges).isTrue()
state.eventSink(ChangeRoomPermissionsEvent.Exit)
@@ -285,13 +262,11 @@ class ChangeBaseRoomPermissionsPresenterTest {
}
private fun createChangeRoomPermissionsPresenter(
section: ChangeRoomPermissionsSection = ChangeRoomPermissionsSection.RoomDetails,
room: FakeJoinedRoom = FakeJoinedRoom(
baseRoom = FakeBaseRoom(powerLevelsResult = { Result.success(defaultPermissions()) }),
),
analyticsService: FakeAnalyticsService = FakeAnalyticsService(),
) = ChangeRoomPermissionsPresenter(
section = section,
room = room,
analyticsService = analyticsService,
)

View File

@@ -5,40 +5,40 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.roomdetails.impl.rolesandpermissions.permissions
package io.element.android.features.rolesandpermissions.impl.permissions
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onFirst
import androidx.compose.ui.test.performClick
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.features.roomdetails.impl.R
import io.element.android.features.rolesandpermissions.impl.R
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.room.RoomMember
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
import io.element.android.tests.testutils.clickOn
import io.element.android.tests.testutils.clickOnFirst
import io.element.android.tests.testutils.ensureCalledOnce
import io.element.android.tests.testutils.ensureCalledOnceWithParam
import io.element.android.tests.testutils.pressBack
import io.element.android.tests.testutils.pressBackKey
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.persistentMapOf
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ChangeBaseRoomPermissionsViewTest {
class ChangeRoomPermissionsViewTest {
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
@Test
fun `click on back icon invokes Exit`() {
val recorder = EventsRecorder<ChangeRoomPermissionsEvent>()
rule.setChangeRoomPermissionsRule(
eventsRecorder = recorder,
state = aChangeRoomPermissionsState(
eventSink = recorder
)
)
rule.pressBack()
recorder.assertSingle(ChangeRoomPermissionsEvent.Exit)
@@ -48,7 +48,9 @@ class ChangeBaseRoomPermissionsViewTest {
fun `click on back key invokes Exit`() {
val recorder = EventsRecorder<ChangeRoomPermissionsEvent>()
rule.setChangeRoomPermissionsRule(
eventsRecorder = recorder,
state = aChangeRoomPermissionsState(
eventSink = recorder
)
)
rule.pressBackKey()
recorder.assertSingle(ChangeRoomPermissionsEvent.Exit)
@@ -59,11 +61,9 @@ class ChangeBaseRoomPermissionsViewTest {
val recorder = EventsRecorder<ChangeRoomPermissionsEvent>()
rule.setChangeRoomPermissionsRule(
state = aChangeRoomPermissionsState(
section = ChangeRoomPermissionsSection.RoomDetails,
hasChanges = true,
eventSink = recorder,
),
eventsRecorder = recorder,
)
rule.pressBackKey()
recorder.assertSingle(ChangeRoomPermissionsEvent.Exit)
@@ -74,12 +74,10 @@ class ChangeBaseRoomPermissionsViewTest {
val recorder = EventsRecorder<ChangeRoomPermissionsEvent>()
rule.setChangeRoomPermissionsRule(
state = aChangeRoomPermissionsState(
section = ChangeRoomPermissionsSection.RoomDetails,
hasChanges = true,
confirmExitAction = AsyncAction.ConfirmingNoParams,
eventSink = recorder,
),
eventsRecorder = recorder,
)
rule.clickOn(CommonStrings.action_discard)
recorder.assertSingle(ChangeRoomPermissionsEvent.Exit)
@@ -90,12 +88,10 @@ class ChangeBaseRoomPermissionsViewTest {
val recorder = EventsRecorder<ChangeRoomPermissionsEvent>()
rule.setChangeRoomPermissionsRule(
state = aChangeRoomPermissionsState(
section = ChangeRoomPermissionsSection.RoomDetails,
hasChanges = true,
confirmExitAction = AsyncAction.ConfirmingNoParams,
eventSink = recorder,
),
eventsRecorder = recorder,
)
rule.clickOnFirst(CommonStrings.action_save)
recorder.assertSingle(ChangeRoomPermissionsEvent.Save)
@@ -105,21 +101,19 @@ class ChangeBaseRoomPermissionsViewTest {
fun `click on a role item triggers ChangeRole event`() {
val recorder = EventsRecorder<ChangeRoomPermissionsEvent>()
rule.setChangeRoomPermissionsRule(
eventsRecorder = recorder,
)
val admins = rule.activity.getText(R.string.screen_room_change_permissions_administrators).toString()
val moderators = rule.activity.getText(R.string.screen_room_change_permissions_moderators).toString()
val users = rule.activity.getText(R.string.screen_room_change_permissions_everyone).toString()
rule.onAllNodesWithText(admins).onFirst().performClick()
rule.onAllNodesWithText(moderators).onFirst().performClick()
rule.onAllNodesWithText(users).onFirst().performClick()
recorder.assertList(
listOf(
ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, RoomMember.Role.Admin),
ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, RoomMember.Role.Moderator),
ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, RoomMember.Role.User),
state = aChangeRoomPermissionsState(
itemsBySection = persistentMapOf(
// Makes sure there is only one item to click on
RoomPermissionsSection.RoomDetails to persistentListOf(RoomPermissionType.ROOM_NAME)
),
eventSink = recorder,
)
)
rule.clickOn(R.string.screen_room_change_permissions_room_name)
rule.clickOn(R.string.screen_room_change_permissions_everyone)
recorder.assertSingle(
ChangeRoomPermissionsEvent.ChangeMinimumRoleForAction(RoomPermissionType.ROOM_NAME, SelectableRole.Everyone),
)
}
@Test
@@ -127,11 +121,9 @@ class ChangeBaseRoomPermissionsViewTest {
val recorder = EventsRecorder<ChangeRoomPermissionsEvent>()
rule.setChangeRoomPermissionsRule(
state = aChangeRoomPermissionsState(
section = ChangeRoomPermissionsSection.RoomDetails,
hasChanges = true,
eventSink = recorder,
),
eventsRecorder = recorder,
)
rule.clickOn(CommonStrings.action_save)
recorder.assertSingle(ChangeRoomPermissionsEvent.Save)
@@ -139,14 +131,13 @@ class ChangeBaseRoomPermissionsViewTest {
@Test
fun `a successful save exits the screen`() {
ensureCalledOnce { callback ->
ensureCalledOnceWithParam(true) { callback ->
rule.setChangeRoomPermissionsRule(
state = aChangeRoomPermissionsState(
section = ChangeRoomPermissionsSection.RoomDetails,
hasChanges = true,
saveAction = AsyncAction.Success(Unit),
),
onBackClick = callback
onComplete = callback
)
rule.clickOn(CommonStrings.action_save)
}
@@ -157,12 +148,10 @@ class ChangeBaseRoomPermissionsViewTest {
val recorder = EventsRecorder<ChangeRoomPermissionsEvent>()
rule.setChangeRoomPermissionsRule(
state = aChangeRoomPermissionsState(
section = ChangeRoomPermissionsSection.RoomDetails,
hasChanges = true,
saveAction = AsyncAction.Failure(IllegalStateException("Failed to set room power levels")),
eventSink = recorder,
),
eventsRecorder = recorder,
)
rule.clickOn(CommonStrings.action_ok)
recorder.assertSingle(ChangeRoomPermissionsEvent.ResetPendingActions)
@@ -170,17 +159,13 @@ class ChangeBaseRoomPermissionsViewTest {
}
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setChangeRoomPermissionsRule(
eventsRecorder: EventsRecorder<ChangeRoomPermissionsEvent> = EventsRecorder(expectEvents = false),
state: ChangeRoomPermissionsState = aChangeRoomPermissionsState(
section = ChangeRoomPermissionsSection.RoomDetails,
eventSink = eventsRecorder,
),
onBackClick: () -> Unit = EnsureNeverCalled(),
state: ChangeRoomPermissionsState = aChangeRoomPermissionsState(),
onComplete: (Boolean) -> Unit = EnsureNeverCalledWithParam(),
) {
setContent {
ChangeRoomPermissionsView(
state = state,
onBackClick = onBackClick,
onComplete = onComplete,
)
}
}

View File

@@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.roomdetails.impl.rolesandpermissions
package io.element.android.features.rolesandpermissions.impl.root
import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow

View File

@@ -5,13 +5,13 @@
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.features.roomdetails.impl.rolesandpermissions
package io.element.android.features.rolesandpermissions.impl.root
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.features.roomdetails.impl.R
import io.element.android.features.rolesandpermissions.impl.R
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.api.room.RoomMember
import io.element.android.libraries.ui.strings.CommonStrings
@@ -83,14 +83,12 @@ class RolesAndPermissionsViewTest {
@Test
@Config(qualifiers = "h640dp")
fun `tapping on any of the permission items open the change permissions screen`() {
ensureCalledTimes(3) { callback ->
fun `tapping permission item open the change permissions screen`() {
ensureCalledTimes(1) { callback ->
rule.setRolesAndPermissionsView(
openPermissionScreens = callback,
openEditPermissions = callback,
)
rule.clickOn(R.string.screen_room_roles_and_permissions_room_details)
rule.clickOn(R.string.screen_room_roles_and_permissions_messages_and_content)
rule.clickOn(R.string.screen_room_roles_and_permissions_member_moderation)
rule.clickOn(R.string.screen_room_roles_and_permissions_permissions_header)
}
}
@@ -184,7 +182,7 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRoles
goBack: () -> Unit = EnsureNeverCalled(),
openAdminList: () -> Unit = EnsureNeverCalled(),
openModeratorList: () -> Unit = EnsureNeverCalled(),
openPermissionScreens: () -> Unit = EnsureNeverCalled(),
openEditPermissions: () -> Unit = EnsureNeverCalled(),
) {
setSafeContent {
RolesAndPermissionsView(
@@ -193,9 +191,7 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRoles
override fun onBackClick() = goBack()
override fun openAdminList() = openAdminList()
override fun openModeratorList() = openModeratorList()
override fun openEditRoomDetailsPermissions() = openPermissionScreens()
override fun openModerationPermissions() = openPermissionScreens()
override fun openMessagesAndContentPermissions() = openPermissionScreens()
override fun openEditPermissions() = openEditPermissions()
}
)
}