Migrate to v2 testing APIs

This commit is contained in:
Benoit Marty 2026-04-30 15:54:33 +02:00
parent da36323006
commit 11b9efa2c9
83 changed files with 2197 additions and 2320 deletions

View file

@ -6,13 +6,16 @@
* Please see LICENSE files in the repository root for full details.
*/
@file:OptIn(ExperimentalTestApi::class)
package io.element.android.features.securityandprivacy.impl.editroomaddress
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.AndroidComposeUiTest
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performTextInput
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.matrix.ui.room.address.RoomAddressValidity
@ -23,86 +26,82 @@ import io.element.android.tests.testutils.EventsRecorder
import io.element.android.tests.testutils.clickOn
import io.element.android.tests.testutils.ensureCalledOnce
import io.element.android.tests.testutils.pressBack
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class EditRoomAddressViewTest {
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
@Test
fun `click on back invokes expected callback`() {
fun `click on back invokes expected callback`() = runAndroidComposeUiTest {
ensureCalledOnce { callback ->
rule.setEditRoomAddressView(onBackClick = callback)
rule.pressBack()
setEditRoomAddressView(onBackClick = callback)
pressBack()
}
}
@Test
fun `click on disabled save doesn't emit event`() {
fun `click on disabled save doesn't emit event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<EditRoomAddressEvents>(expectEvents = false)
val state = anEditRoomAddressState(eventSink = recorder)
rule.setEditRoomAddressView(state)
rule.clickOn(CommonStrings.action_save)
setEditRoomAddressView(state)
clickOn(CommonStrings.action_save)
recorder.assertEmpty()
}
@Test
fun `click on enabled save emits the expected event`() {
fun `click on enabled save emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<EditRoomAddressEvents>()
val state = anEditRoomAddressState(
roomAddress = "room",
roomAddressValidity = RoomAddressValidity.Valid,
eventSink = recorder
)
rule.setEditRoomAddressView(state)
rule.clickOn(CommonStrings.action_save)
setEditRoomAddressView(state)
clickOn(CommonStrings.action_save)
recorder.assertSingle(EditRoomAddressEvents.Save)
}
@Test
fun `text changes on text field emits the expected event`() {
fun `text changes on text field emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<EditRoomAddressEvents>()
val state = anEditRoomAddressState(
roomAddress = "",
eventSink = recorder
)
rule.setEditRoomAddressView(state)
setEditRoomAddressView(state)
rule.onNodeWithTag(TestTags.roomAddressField.value).performTextInput("alias")
onNodeWithTag(TestTags.roomAddressField.value).performTextInput("alias")
recorder.assertSingle(EditRoomAddressEvents.RoomAddressChanged("alias"))
}
@Test
fun `click on dismiss error emits the expected event`() {
fun `click on dismiss error emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<EditRoomAddressEvents>()
val state = anEditRoomAddressState(
roomAddress = "",
saveAction = AsyncAction.Failure(IllegalStateException()),
eventSink = recorder
)
rule.setEditRoomAddressView(state)
rule.clickOn(CommonStrings.action_cancel)
setEditRoomAddressView(state)
clickOn(CommonStrings.action_cancel)
recorder.assertSingle(EditRoomAddressEvents.DismissError)
}
@Test
fun `click on retry error emits the expected event`() {
fun `click on retry error emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<EditRoomAddressEvents>()
val state = anEditRoomAddressState(
roomAddress = "",
saveAction = AsyncAction.Failure(IllegalStateException()),
eventSink = recorder
)
rule.setEditRoomAddressView(state)
rule.clickOn(CommonStrings.action_retry)
setEditRoomAddressView(state)
clickOn(CommonStrings.action_retry)
recorder.assertSingle(EditRoomAddressEvents.Save)
}
}
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setEditRoomAddressView(
private fun AndroidComposeUiTest<ComponentActivity>.setEditRoomAddressView(
state: EditRoomAddressState = anEditRoomAddressState(
eventSink = EventsRecorder(expectEvents = false),
),

View file

@ -6,13 +6,16 @@
* Please see LICENSE files in the repository root for full details.
*/
@file:OptIn(ExperimentalTestApi::class)
package io.element.android.features.securityandprivacy.impl.manageauthorizedspaces
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.AndroidComposeUiTest
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.spaces.SpaceRoom
@ -24,26 +27,22 @@ import io.element.android.tests.testutils.clickOn
import io.element.android.tests.testutils.pressBack
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toImmutableSet
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ManageAuthorizedSpacesViewTest {
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
@Test
fun `clicking back emits Cancel event`() {
fun `clicking back emits Cancel event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<ManageAuthorizedSpacesEvent>()
val state = aManageAuthorizedSpacesState(eventSink = recorder)
rule.setManageAuthorizedSpacesView(state)
rule.pressBack()
setManageAuthorizedSpacesView(state)
pressBack()
recorder.assertSingle(ManageAuthorizedSpacesEvent.Cancel)
}
@Test
fun `clicking space checkbox emits ToggleSpace event`() {
fun `clicking space checkbox emits ToggleSpace event`() = runAndroidComposeUiTest {
val roomId = A_ROOM_ID
val space = aSpaceRoom(roomId = roomId, displayName = "Test Space")
val recorder = EventsRecorder<ManageAuthorizedSpacesEvent>()
@ -51,37 +50,37 @@ class ManageAuthorizedSpacesViewTest {
selectableSpaces = listOf(space),
eventSink = recorder
)
rule.setManageAuthorizedSpacesView(state)
rule.onNodeWithText("Test Space").performClick()
setManageAuthorizedSpacesView(state)
onNodeWithText("Test Space").performClick()
recorder.assertSingle(ManageAuthorizedSpacesEvent.ToggleSpace(roomId))
}
@Test
fun `clicking done button emits Done event`() {
fun `clicking done button emits Done event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<ManageAuthorizedSpacesEvent>()
val state = aManageAuthorizedSpacesState(
selectedIds = listOf(A_ROOM_ID),
eventSink = recorder
)
rule.setManageAuthorizedSpacesView(state)
rule.clickOn(CommonStrings.action_done)
setManageAuthorizedSpacesView(state)
clickOn(CommonStrings.action_done)
recorder.assertSingle(ManageAuthorizedSpacesEvent.Done)
}
@Test
fun `done button is disabled when no spaces selected`() {
fun `done button is disabled when no spaces selected`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<ManageAuthorizedSpacesEvent>(expectEvents = false)
val state = aManageAuthorizedSpacesState(
selectedIds = emptyList(),
eventSink = recorder
)
rule.setManageAuthorizedSpacesView(state)
rule.clickOn(CommonStrings.action_done)
setManageAuthorizedSpacesView(state)
clickOn(CommonStrings.action_done)
recorder.assertEmpty()
}
}
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setManageAuthorizedSpacesView(
private fun AndroidComposeUiTest<ComponentActivity>.setManageAuthorizedSpacesView(
state: ManageAuthorizedSpacesState = aManageAuthorizedSpacesState(
eventSink = EventsRecorder(expectEvents = false)
),

View file

@ -5,13 +5,16 @@
* Please see LICENSE files in the repository root for full details.
*/
@file:OptIn(ExperimentalTestApi::class)
package io.element.android.features.securityandprivacy.impl.root
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.AndroidComposeUiTest
import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import io.element.android.features.securityandprivacy.impl.R
import io.element.android.libraries.architecture.AsyncAction
@ -23,73 +26,69 @@ import io.element.android.tests.testutils.EventsRecorder
import io.element.android.tests.testutils.clickOn
import io.element.android.tests.testutils.pressBack
import kotlinx.collections.immutable.persistentListOf
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TestRule
import org.junit.runner.RunWith
import org.robolectric.annotation.Config
@RunWith(AndroidJUnit4::class)
class SecurityAndPrivacyViewTest {
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
@Test
fun `click on back invokes emits the expected event`() {
fun `click on back invokes emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
eventSink = recorder,
)
rule.setSecurityAndPrivacyView(state)
rule.pressBack()
setSecurityAndPrivacyView(state)
pressBack()
recorder.assertSingle(SecurityAndPrivacyEvent.Exit)
}
@Test
fun `discard cancellation emits the expected event`() {
fun `discard cancellation emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
saveAction = AsyncAction.ConfirmingCancellation,
eventSink = recorder,
)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(CommonStrings.action_discard)
setSecurityAndPrivacyView(state)
clickOn(CommonStrings.action_discard)
recorder.assertSingle(SecurityAndPrivacyEvent.Exit)
}
@Test
fun `save cancellation confirmation emits the expected event`() {
fun `save cancellation confirmation emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
saveAction = AsyncAction.ConfirmingCancellation,
eventSink = recorder,
)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(CommonStrings.action_save, inDialog = true)
setSecurityAndPrivacyView(state)
clickOn(CommonStrings.action_save, inDialog = true)
recorder.assertSingle(SecurityAndPrivacyEvent.Save)
}
@Test
fun `click on room access item emits the expected event`() {
fun `click on room access item emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
eventSink = recorder,
)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(R.string.screen_security_and_privacy_room_access_invite_only_option_title)
setSecurityAndPrivacyView(state)
clickOn(R.string.screen_security_and_privacy_room_access_invite_only_option_title)
recorder.assertSingle(SecurityAndPrivacyEvent.ChangeRoomAccess(SecurityAndPrivacyRoomAccess.InviteOnly))
}
@Test
fun `click on disabled save doesn't emit event`() {
fun `click on disabled save doesn't emit event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>(expectEvents = false)
val state = aSecurityAndPrivacyState(eventSink = recorder)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(CommonStrings.action_save)
setSecurityAndPrivacyView(state)
clickOn(CommonStrings.action_save)
recorder.assertEmpty()
}
@Test
fun `click on enabled save emits the expected event`() {
fun `click on enabled save emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
eventSink = recorder,
@ -97,14 +96,14 @@ class SecurityAndPrivacyViewTest {
roomAccess = SecurityAndPrivacyRoomAccess.Anyone,
)
)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(CommonStrings.action_save)
setSecurityAndPrivacyView(state)
clickOn(CommonStrings.action_save)
recorder.assertSingle(SecurityAndPrivacyEvent.Save)
}
@Test
@Config(qualifiers = "h640dp")
fun `click on room address item emits the expected event`() {
fun `click on room address item emits the expected event`() = runAndroidComposeUiTest {
val address = "@alias:matrix.org"
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
@ -114,14 +113,14 @@ class SecurityAndPrivacyViewTest {
roomAccess = SecurityAndPrivacyRoomAccess.Anyone,
),
)
rule.setSecurityAndPrivacyView(state)
rule.onNodeWithText(address).performClick()
setSecurityAndPrivacyView(state)
onNodeWithText(address).performClick()
recorder.assertSingle(SecurityAndPrivacyEvent.EditRoomAddress)
}
@Test
@Config(qualifiers = "h1024dp")
fun `click on room visibility item emits the expected event`() {
fun `click on room visibility item emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
eventSink = recorder,
@ -130,14 +129,14 @@ class SecurityAndPrivacyViewTest {
isVisibleInRoomDirectory = AsyncData.Success(false),
),
)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(R.string.screen_security_and_privacy_room_directory_visibility_toggle_title)
setSecurityAndPrivacyView(state)
clickOn(R.string.screen_security_and_privacy_room_directory_visibility_toggle_title)
recorder.assertSingle(SecurityAndPrivacyEvent.ToggleRoomVisibility)
}
@Test
@Config(qualifiers = "h1024dp")
fun `click on history visibility item emits the expected event`() {
fun `click on history visibility item emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
eventSink = recorder,
@ -145,65 +144,65 @@ class SecurityAndPrivacyViewTest {
historyVisibility = SecurityAndPrivacyHistoryVisibility.Invited,
),
)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(R.string.screen_security_and_privacy_room_history_since_invite_option_title)
setSecurityAndPrivacyView(state)
clickOn(R.string.screen_security_and_privacy_room_history_since_invite_option_title)
recorder.assertSingle(SecurityAndPrivacyEvent.ChangeHistoryVisibility(SecurityAndPrivacyHistoryVisibility.Invited))
}
@Test
@Config(qualifiers = "h1024dp")
fun `click on encryption item emits the expected event`() {
fun `click on encryption item emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
eventSink = recorder,
savedSettings = aSecurityAndPrivacySettings(isEncrypted = false),
)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(R.string.screen_security_and_privacy_encryption_toggle_title)
setSecurityAndPrivacyView(state)
clickOn(R.string.screen_security_and_privacy_encryption_toggle_title)
recorder.assertSingle(SecurityAndPrivacyEvent.ToggleEncryptionState)
}
@Test
fun `click on encryption confirm emits the expected event`() {
fun `click on encryption confirm emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
eventSink = recorder,
showEncryptionConfirmation = true,
)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(R.string.screen_security_and_privacy_enable_encryption_alert_confirm_button_title)
setSecurityAndPrivacyView(state)
clickOn(R.string.screen_security_and_privacy_enable_encryption_alert_confirm_button_title)
recorder.assertSingle(SecurityAndPrivacyEvent.ConfirmEnableEncryption)
}
@Test
@Config(qualifiers = "h1024dp")
fun `click on space member access emits the expected event`() {
fun `click on space member access emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
eventSink = recorder,
spaceSelectionMode = SpaceSelectionMode.Single(A_ROOM_ID, null),
)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(R.string.screen_security_and_privacy_room_access_space_members_option_title)
setSecurityAndPrivacyView(state)
clickOn(R.string.screen_security_and_privacy_room_access_space_members_option_title)
recorder.assertSingle(SecurityAndPrivacyEvent.SelectSpaceMemberAccess)
}
@Test
@Config(qualifiers = "h1024dp")
fun `click on ask to join with space members emits the expected event`() {
fun `click on ask to join with space members emits the expected event`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>()
val state = aSecurityAndPrivacyState(
eventSink = recorder,
spaceSelectionMode = SpaceSelectionMode.Single(A_ROOM_ID, null),
)
rule.setSecurityAndPrivacyView(state)
rule.clickOn(R.string.screen_security_and_privacy_ask_to_join_option_title)
setSecurityAndPrivacyView(state)
clickOn(R.string.screen_security_and_privacy_ask_to_join_option_title)
recorder.assertSingle(SecurityAndPrivacyEvent.SelectAskToJoinWithSpaceMembersAccess)
}
@Test
@Config(qualifiers = "h1024dp")
fun `manage spaces footer is shown when space member access is selected`() {
fun `manage spaces footer is shown when space member access is selected`() = runAndroidComposeUiTest {
val recorder = EventsRecorder<SecurityAndPrivacyEvent>(expectEvents = false)
val state = aSecurityAndPrivacyState(
eventSink = recorder,
@ -212,15 +211,16 @@ class SecurityAndPrivacyViewTest {
roomAccess = SecurityAndPrivacyRoomAccess.SpaceMember(persistentListOf(A_ROOM_ID)),
),
)
rule.setSecurityAndPrivacyView(state)
setSecurityAndPrivacyView(state)
// The footer text uses AnnotatedString with a link. Verify the footer text is displayed.
val actionFooterText = rule.activity.getString(R.string.screen_security_and_privacy_room_access_footer_manage_spaces_action)
val footerText = rule.activity.getString(R.string.screen_security_and_privacy_room_access_footer, actionFooterText)
rule.onNodeWithText(footerText).assertExists()
val resources = activity!!.resources
val actionFooterText = resources.getString(R.string.screen_security_and_privacy_room_access_footer_manage_spaces_action)
val footerText = resources.getString(R.string.screen_security_and_privacy_room_access_footer, actionFooterText)
onNodeWithText(footerText).assertExists()
}
}
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setSecurityAndPrivacyView(
private fun AndroidComposeUiTest<ComponentActivity>.setSecurityAndPrivacyView(
state: SecurityAndPrivacyState = aSecurityAndPrivacyState(
eventSink = EventsRecorder(expectEvents = false),
),