Merge branch 'develop' into feature/bma/removeExternalCallSupport
This commit is contained in:
commit
e21276f323
122 changed files with 2266 additions and 2352 deletions
|
|
@ -6,13 +6,15 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
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.longClick
|
||||
import androidx.compose.ui.test.onAllNodesWithContentDescription
|
||||
import androidx.compose.ui.test.onAllNodesWithTag
|
||||
|
|
@ -25,6 +27,7 @@ import androidx.compose.ui.test.onNodeWithText
|
|||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTouchInput
|
||||
import androidx.compose.ui.test.swipeRight
|
||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.emojibasebindings.Emoji
|
||||
|
|
@ -78,82 +81,78 @@ import io.element.android.tests.testutils.pressBack
|
|||
import io.element.android.tests.testutils.setSafeContent
|
||||
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
|
||||
import org.robolectric.annotation.Config
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class MessagesViewTest {
|
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `clicking on back invoke expected callback`() {
|
||||
fun `clicking on back invoke expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>(expectEvents = false)
|
||||
val state = aMessagesState(
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
onBackClick = callback,
|
||||
)
|
||||
rule.pressBack()
|
||||
pressBack()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on room name invoke expected callback`() {
|
||||
fun `clicking on room name invoke expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>(expectEvents = false)
|
||||
val state = aMessagesState(
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
onRoomDetailsClick = callback,
|
||||
)
|
||||
rule.onNodeWithText(state.roomName.orEmpty(), useUnmergedTree = true).performClick()
|
||||
onNodeWithText(state.roomName.orEmpty(), useUnmergedTree = true).performClick()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on join call invoke expected callback`() {
|
||||
fun `clicking on join call invoke expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>(expectEvents = false)
|
||||
val state = aMessagesState(
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
ensureCalledOnceWithParam(false) { callback ->
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
onJoinCallClick = callback,
|
||||
)
|
||||
val joinCallContentDescription = rule.activity.getString(CommonStrings.a11y_start_call)
|
||||
rule.onNodeWithContentDescription(joinCallContentDescription).performClick()
|
||||
val joinCallContentDescription = activity!!.getString(CommonStrings.a11y_start_call)
|
||||
onNodeWithContentDescription(joinCallContentDescription).performClick()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on join voice call invoke expected callback`() {
|
||||
fun `clicking on join voice call invoke expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>(expectEvents = false)
|
||||
val state = aMessagesState(
|
||||
eventSink = eventsRecorder,
|
||||
roomCallState = aStandByCallState(isDM = true)
|
||||
)
|
||||
ensureCalledOnceWithParam(true) { callback ->
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
onJoinCallClick = callback,
|
||||
)
|
||||
val joinVoiceCallContentDescription = rule.activity.getString(CommonStrings.a11y_start_voice_call)
|
||||
rule.onNodeWithContentDescription(joinVoiceCallContentDescription).performClick()
|
||||
val joinVoiceCallContentDescription = activity!!.getString(CommonStrings.a11y_start_voice_call)
|
||||
onNodeWithContentDescription(joinVoiceCallContentDescription).performClick()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on an Event invoke expected callback`() {
|
||||
fun `clicking on an Event invoke expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>(expectEvents = false)
|
||||
val state = aMessagesState(
|
||||
timelineState = aTimelineState(
|
||||
|
|
@ -167,12 +166,12 @@ class MessagesViewTest {
|
|||
expectedParam2 = timelineItem,
|
||||
result = true,
|
||||
)
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
onEventClick = callback,
|
||||
)
|
||||
// Cannot perform click on "Text", it's not detected. Use tag instead
|
||||
rule.onAllNodesWithTag(TestTags.messageBubble.value).onFirst().performClick()
|
||||
onAllNodesWithTag(TestTags.messageBubble.value).onFirst().performClick()
|
||||
callback.assertSuccess()
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +201,7 @@ class MessagesViewTest {
|
|||
userHasPermissionToRedactOther: Boolean = false,
|
||||
userHasPermissionToSendReaction: Boolean = false,
|
||||
userCanPinEvent: Boolean = false,
|
||||
) {
|
||||
) = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<ActionListEvent>()
|
||||
val state = aMessagesState(
|
||||
actionListState = anActionListState(
|
||||
|
|
@ -220,11 +219,11 @@ class MessagesViewTest {
|
|||
),
|
||||
)
|
||||
val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
)
|
||||
// Cannot perform click on "Text", it's not detected. Use tag instead
|
||||
rule.onAllNodesWithTag(TestTags.messageBubble.value).onFirst().performTouchInput { longClick() }
|
||||
onAllNodesWithTag(TestTags.messageBubble.value).onFirst().performTouchInput { longClick() }
|
||||
eventsRecorder.assertSingle(
|
||||
ActionListEvent.ComputeForMessage(
|
||||
event = timelineItem,
|
||||
|
|
@ -235,7 +234,7 @@ class MessagesViewTest {
|
|||
|
||||
@Test
|
||||
@Config(qualifiers = "h1024dp")
|
||||
fun `clicking on a read receipt list emits the expected Event`() {
|
||||
fun `clicking on a read receipt list emits the expected Event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<ReadReceiptBottomSheetEvent>()
|
||||
val state = aMessagesState(
|
||||
timelineState = aTimelineState(
|
||||
|
|
@ -255,10 +254,10 @@ class MessagesViewTest {
|
|||
),
|
||||
)
|
||||
val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
)
|
||||
rule.onNodeWithTag(TestTags.messageReadReceipts.value, useUnmergedTree = true).performClick()
|
||||
onNodeWithTag(TestTags.messageReadReceipts.value, useUnmergedTree = true).performClick()
|
||||
eventsRecorder.assertSingle(ReadReceiptBottomSheetEvent.EventSelected(timelineItem))
|
||||
}
|
||||
|
||||
|
|
@ -272,7 +271,7 @@ class MessagesViewTest {
|
|||
swipeTest(userHasPermissionToSendMessage = false)
|
||||
}
|
||||
|
||||
private fun swipeTest(userHasPermissionToSendMessage: Boolean) {
|
||||
private fun swipeTest(userHasPermissionToSendMessage: Boolean) = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>()
|
||||
val canBeRepliedEvent = aTimelineItemEvent(canBeRepliedTo = true)
|
||||
val cannotBeRepliedEvent = aTimelineItemEvent(canBeRepliedTo = false)
|
||||
|
|
@ -285,10 +284,10 @@ class MessagesViewTest {
|
|||
),
|
||||
eventSink = eventsRecorder,
|
||||
)
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
)
|
||||
rule.onAllNodesWithTag(TestTags.messageBubble.value).apply {
|
||||
onAllNodesWithTag(TestTags.messageBubble.value).apply {
|
||||
onFirst().performTouchInput { swipeRight(endX = 200f) }
|
||||
onLast().performTouchInput { swipeRight(endX = 200f) }
|
||||
}
|
||||
|
|
@ -300,7 +299,7 @@ class MessagesViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on send location invoke expected callback`() {
|
||||
fun `clicking on send location invoke expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>(expectEvents = false)
|
||||
val state = aMessagesState(
|
||||
composerState = aMessageComposerState(
|
||||
|
|
@ -309,16 +308,16 @@ class MessagesViewTest {
|
|||
eventSink = eventsRecorder
|
||||
)
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
onSendLocationClick = callback,
|
||||
)
|
||||
rule.clickOn(R.string.screen_room_attachment_source_location)
|
||||
clickOn(R.string.screen_room_attachment_source_location)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on create poll invoke expected callback`() {
|
||||
fun `clicking on create poll invoke expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>(expectEvents = false)
|
||||
val state = aMessagesState(
|
||||
composerState = aMessageComposerState(
|
||||
|
|
@ -327,25 +326,25 @@ class MessagesViewTest {
|
|||
eventSink = eventsRecorder
|
||||
)
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
onCreatePollClick = callback,
|
||||
)
|
||||
// Then click on the poll action
|
||||
rule.clickOn(R.string.screen_room_attachment_source_poll)
|
||||
clickOn(R.string.screen_room_attachment_source_poll)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Config(qualifiers = "h1024dp")
|
||||
fun `clicking on the avatar of the sender of an Event emits the expected event`() {
|
||||
fun `clicking on the avatar of the sender of an Event emits the expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>()
|
||||
val state = aMessagesState(
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
val timelineEvent = state.timelineState.timelineItems.filterIsInstance<TimelineItem.Event>().first()
|
||||
rule.setMessagesView(state = state)
|
||||
rule.onNodeWithTag(TestTags.timelineItemSenderAvatar.value, useUnmergedTree = true).performClick()
|
||||
setMessagesView(state = state)
|
||||
onNodeWithTag(TestTags.timelineItemSenderAvatar.value, useUnmergedTree = true).performClick()
|
||||
eventsRecorder.assertSingle(
|
||||
MessagesEvent.OnUserClicked(
|
||||
MatrixUser(
|
||||
|
|
@ -359,12 +358,12 @@ class MessagesViewTest {
|
|||
|
||||
@Test
|
||||
@Config(qualifiers = "h1024dp")
|
||||
fun `clicking on the display name of the sender of an Event emits expected event`() {
|
||||
fun `clicking on the display name of the sender of an Event emits expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>()
|
||||
val state = aMessagesState(eventSink = eventsRecorder)
|
||||
val timelineEvent = state.timelineState.timelineItems.filterIsInstance<TimelineItem.Event>().first()
|
||||
rule.setMessagesView(state = state)
|
||||
rule.onNodeWithTag(TestTags.timelineItemSenderAvatar.value, useUnmergedTree = true).performClick()
|
||||
setMessagesView(state = state)
|
||||
onNodeWithTag(TestTags.timelineItemSenderAvatar.value, useUnmergedTree = true).performClick()
|
||||
eventsRecorder.assertSingle(
|
||||
MessagesEvent.OnUserClicked(
|
||||
MatrixUser(
|
||||
|
|
@ -377,7 +376,7 @@ class MessagesViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `selecting a action on a message emits the expected Event`() {
|
||||
fun `selecting a action on a message emits the expected Event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>()
|
||||
val state = aMessagesState(
|
||||
eventSink = eventsRecorder
|
||||
|
|
@ -395,17 +394,17 @@ class MessagesViewTest {
|
|||
)
|
||||
),
|
||||
)
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = stateWithMessageAction,
|
||||
)
|
||||
rule.clickOn(CommonStrings.action_edit)
|
||||
clickOn(CommonStrings.action_edit)
|
||||
// Give time for the close animation to complete
|
||||
rule.mainClock.advanceTimeBy(milliseconds = 1_000)
|
||||
mainClock.advanceTimeBy(milliseconds = 1_000)
|
||||
eventsRecorder.assertSingle(MessagesEvent.HandleAction(TimelineItemAction.Edit, timelineItem))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on a reaction emits the expected Event`() {
|
||||
fun `clicking on a reaction emits the expected Event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>()
|
||||
val state = aMessagesState(
|
||||
timelineState = aTimelineState(
|
||||
|
|
@ -414,10 +413,10 @@ class MessagesViewTest {
|
|||
eventSink = eventsRecorder,
|
||||
)
|
||||
val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
)
|
||||
rule.onAllNodesWithText(
|
||||
onAllNodesWithText(
|
||||
text = "👍️",
|
||||
useUnmergedTree = true,
|
||||
).onFirst().performClick()
|
||||
|
|
@ -425,7 +424,7 @@ class MessagesViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `long clicking on a reaction emits the expected Event`() {
|
||||
fun `long clicking on a reaction emits the expected Event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<ReactionSummaryEvent>()
|
||||
val state = aMessagesState(
|
||||
timelineState = aTimelineState(
|
||||
|
|
@ -437,10 +436,10 @@ class MessagesViewTest {
|
|||
),
|
||||
)
|
||||
val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
)
|
||||
rule.onAllNodesWithText(
|
||||
onAllNodesWithText(
|
||||
text = "👍️",
|
||||
useUnmergedTree = true,
|
||||
).onFirst().performTouchInput { longClick() }
|
||||
|
|
@ -448,7 +447,7 @@ class MessagesViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on more reaction emits the expected Event`() {
|
||||
fun `clicking on more reaction emits the expected Event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<CustomReactionEvent>()
|
||||
val state = aMessagesState(
|
||||
timelineState = aTimelineState(
|
||||
|
|
@ -459,16 +458,16 @@ class MessagesViewTest {
|
|||
),
|
||||
)
|
||||
val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
)
|
||||
val moreReactionContentDescription = rule.activity.getString(R.string.screen_room_timeline_add_reaction)
|
||||
rule.onAllNodesWithContentDescription(moreReactionContentDescription).onFirst().performClick()
|
||||
val moreReactionContentDescription = activity!!.getString(R.string.screen_room_timeline_add_reaction)
|
||||
onAllNodesWithContentDescription(moreReactionContentDescription).onFirst().performClick()
|
||||
eventsRecorder.assertSingle(CustomReactionEvent.ShowCustomReactionSheet(timelineItem))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on more reaction from action list emits the expected Event`() {
|
||||
fun `clicking on more reaction from action list emits the expected Event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<CustomReactionEvent>()
|
||||
val state = aMessagesState(
|
||||
timelineState = aTimelineState(
|
||||
|
|
@ -491,18 +490,18 @@ class MessagesViewTest {
|
|||
eventSink = eventsRecorder
|
||||
),
|
||||
)
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = stateWithActionListState,
|
||||
)
|
||||
val moreReactionContentDescription = rule.activity.getString(CommonStrings.a11y_react_with_other_emojis)
|
||||
rule.onNodeWithContentDescription(moreReactionContentDescription).performClick()
|
||||
val moreReactionContentDescription = activity!!.getString(CommonStrings.a11y_react_with_other_emojis)
|
||||
onNodeWithContentDescription(moreReactionContentDescription).performClick()
|
||||
// Give time for the close animation to complete
|
||||
rule.mainClock.advanceTimeBy(milliseconds = 1_000)
|
||||
mainClock.advanceTimeBy(milliseconds = 1_000)
|
||||
eventsRecorder.assertSingle(CustomReactionEvent.ShowCustomReactionSheet(timelineItem))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on verified user send failure from action list emits the expected Event`() {
|
||||
fun `clicking on verified user send failure from action list emits the expected Event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
val state = aMessagesState()
|
||||
val timelineItem = state.timelineState.timelineItems.first() as TimelineItem.Event
|
||||
|
|
@ -519,21 +518,21 @@ class MessagesViewTest {
|
|||
),
|
||||
timelineState = aTimelineState(eventSink = eventsRecorder)
|
||||
)
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = stateWithActionListState,
|
||||
)
|
||||
// Clear initial 'LoadMore' event emitted when setting the state
|
||||
eventsRecorder.clear()
|
||||
|
||||
val verifiedUserSendFailure = rule.activity.getString(CommonStrings.screen_timeline_item_menu_send_failure_changed_identity, "Alice")
|
||||
rule.onNodeWithText(verifiedUserSendFailure).performClick()
|
||||
val verifiedUserSendFailure = activity!!.getString(CommonStrings.screen_timeline_item_menu_send_failure_changed_identity, "Alice")
|
||||
onNodeWithText(verifiedUserSendFailure).performClick()
|
||||
// Give time for the close animation to complete
|
||||
rule.mainClock.advanceTimeBy(milliseconds = 1_000)
|
||||
mainClock.advanceTimeBy(milliseconds = 1_000)
|
||||
eventsRecorder.assertSingle(TimelineEvent.ComputeVerifiedUserSendFailure(timelineItem))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on a custom emoji emits the expected Events`() {
|
||||
fun `clicking on a custom emoji emits the expected Events`() = runAndroidComposeUiTest {
|
||||
val aUnicode = "🙈"
|
||||
val customReactionStateEventsRecorder = EventsRecorder<CustomReactionEvent>()
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>()
|
||||
|
|
@ -563,18 +562,18 @@ class MessagesViewTest {
|
|||
eventSink = customReactionStateEventsRecorder
|
||||
),
|
||||
)
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = stateWithCustomReactionState,
|
||||
)
|
||||
rule.onNodeWithText(aUnicode, useUnmergedTree = true).performClick()
|
||||
onNodeWithText(aUnicode, useUnmergedTree = true).performClick()
|
||||
// Give time for the close animation to complete
|
||||
rule.mainClock.advanceTimeBy(milliseconds = 1_000)
|
||||
mainClock.advanceTimeBy(milliseconds = 1_000)
|
||||
customReactionStateEventsRecorder.assertSingle(CustomReactionEvent.DismissCustomReactionSheet)
|
||||
eventsRecorder.assertSingle(MessagesEvent.ToggleReaction(aUnicode, timelineItem.eventOrTransactionId))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on pinned messages banner emits the expected Event`() {
|
||||
fun `clicking on pinned messages banner emits the expected Event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
val state = aMessagesState(
|
||||
timelineState = aTimelineState(eventSink = eventsRecorder),
|
||||
|
|
@ -587,16 +586,16 @@ class MessagesViewTest {
|
|||
),
|
||||
),
|
||||
)
|
||||
rule.setMessagesView(state = state)
|
||||
setMessagesView(state = state)
|
||||
// Clear initial 'LoadMore' event emitted when setting the state
|
||||
eventsRecorder.clear()
|
||||
|
||||
rule.onNodeWithText("This is a pinned message").performClick()
|
||||
onNodeWithText("This is a pinned message").performClick()
|
||||
eventsRecorder.assertSingle(TimelineEvent.FocusOnEvent(AN_EVENT_ID, debounce = FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS.milliseconds))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on successor room button emits expected event`() {
|
||||
fun `clicking on successor room button emits expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
val successorRoomId = RoomId("!successor:server.org")
|
||||
val state = aMessagesState(
|
||||
|
|
@ -606,18 +605,18 @@ class MessagesViewTest {
|
|||
),
|
||||
timelineState = aTimelineState(eventSink = eventsRecorder)
|
||||
)
|
||||
rule.setMessagesView(state = state)
|
||||
setMessagesView(state = state)
|
||||
// Clear initial 'LoadMore' event emitted when setting the state
|
||||
eventsRecorder.clear()
|
||||
|
||||
val text = rule.activity.getString(R.string.screen_room_timeline_tombstoned_room_action)
|
||||
val text = activity!!.getString(R.string.screen_room_timeline_tombstoned_room_action)
|
||||
// The bottomsheet subcompose seems to make the node to appear twice
|
||||
rule.onAllNodesWithText(text).onFirst().performClick()
|
||||
onAllNodesWithText(text).onFirst().performClick()
|
||||
eventsRecorder.assertSingle(TimelineEvent.NavigateToPredecessorOrSuccessorRoom(successorRoomId))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on threads list button calls the expected function`() {
|
||||
fun `clicking on threads list button calls the expected function`() = runAndroidComposeUiTest {
|
||||
val state = aMessagesState(
|
||||
threads = MessagesState.Threads(
|
||||
hasThreads = true,
|
||||
|
|
@ -625,28 +624,28 @@ class MessagesViewTest {
|
|||
)
|
||||
)
|
||||
val onThreadsListClicked = lambdaRecorder<Unit> {}
|
||||
rule.setMessagesView(
|
||||
setMessagesView(
|
||||
state = state,
|
||||
onThreadsListClicked = onThreadsListClicked,
|
||||
)
|
||||
rule.onNodeWithContentDescription("Threads").performClick()
|
||||
onNodeWithContentDescription("Threads").performClick()
|
||||
onThreadsListClicked.assertions().isCalledOnce()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `no banner shown when there is no successor room`() {
|
||||
fun `no banner shown when there is no successor room`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<MessagesEvent>(expectEvents = false)
|
||||
val state = aMessagesState(
|
||||
successorRoom = null,
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
rule.setMessagesView(state = state)
|
||||
rule.assertNoNodeWithText(R.string.screen_room_timeline_tombstoned_room_message)
|
||||
rule.assertNoNodeWithText(R.string.screen_room_timeline_tombstoned_room_action)
|
||||
setMessagesView(state = state)
|
||||
assertNoNodeWithText(R.string.screen_room_timeline_tombstoned_room_message)
|
||||
assertNoNodeWithText(R.string.screen_room_timeline_tombstoned_room_action)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setMessagesView(
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setMessagesView(
|
||||
state: MessagesState,
|
||||
onBackClick: () -> Unit = EnsureNeverCalled(),
|
||||
onRoomDetailsClick: () -> Unit = EnsureNeverCalled(),
|
||||
|
|
|
|||
|
|
@ -6,12 +6,15 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.identity
|
||||
|
||||
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.v2.runAndroidComposeUiTest
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.libraries.designsystem.components.avatar.anAvatarData
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
|
|
@ -21,19 +24,15 @@ import io.element.android.libraries.matrix.ui.room.RoomMemberIdentityStateChange
|
|||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.tests.testutils.EventsRecorder
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class IdentityChangeStateViewTest {
|
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `show and resolve pin violation`() {
|
||||
fun `show and resolve pin violation`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<IdentityChangeEvent>()
|
||||
rule.setIdentityChangeStateView(
|
||||
setIdentityChangeStateView(
|
||||
state = anIdentityChangeState(
|
||||
listOf(
|
||||
RoomMemberIdentityStateChange(
|
||||
|
|
@ -45,18 +44,18 @@ class IdentityChangeStateViewTest {
|
|||
),
|
||||
)
|
||||
|
||||
rule.onNodeWithText("identity was reset", substring = true).assertExists("should display pin violation warning")
|
||||
rule.onNodeWithText("@alice:localhost", substring = true).assertExists("should display user mxid")
|
||||
rule.onNodeWithText("Alice", substring = true).assertExists("should display user displayname")
|
||||
onNodeWithText("identity was reset", substring = true).assertExists("should display pin violation warning")
|
||||
onNodeWithText("@alice:localhost", substring = true).assertExists("should display user mxid")
|
||||
onNodeWithText("Alice", substring = true).assertExists("should display user displayname")
|
||||
|
||||
rule.clickOn(res = CommonStrings.action_dismiss)
|
||||
clickOn(res = CommonStrings.action_dismiss)
|
||||
eventsRecorder.assertSingle(IdentityChangeEvent.PinIdentity(UserId("@alice:localhost")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `show and resolve verification violation`() {
|
||||
fun `show and resolve verification violation`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<IdentityChangeEvent>()
|
||||
rule.setIdentityChangeStateView(
|
||||
setIdentityChangeStateView(
|
||||
state = anIdentityChangeState(
|
||||
listOf(
|
||||
RoomMemberIdentityStateChange(
|
||||
|
|
@ -68,17 +67,17 @@ class IdentityChangeStateViewTest {
|
|||
),
|
||||
)
|
||||
|
||||
rule.onNodeWithText("identity was reset", substring = true).assertExists("should display verification violation warning")
|
||||
rule.onNodeWithText("@alice:localhost", substring = true).assertExists("should display user mxid")
|
||||
rule.onNodeWithText("Alice", substring = true).assertExists("should display user displayname")
|
||||
onNodeWithText("identity was reset", substring = true).assertExists("should display verification violation warning")
|
||||
onNodeWithText("@alice:localhost", substring = true).assertExists("should display user mxid")
|
||||
onNodeWithText("Alice", substring = true).assertExists("should display user displayname")
|
||||
|
||||
rule.clickOn(res = CommonStrings.crypto_identity_change_withdraw_verification_action)
|
||||
clickOn(res = CommonStrings.crypto_identity_change_withdraw_verification_action)
|
||||
eventsRecorder.assertSingle(IdentityChangeEvent.WithdrawVerification(UserId("@alice:localhost")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Should not show any banner if no violations`() {
|
||||
rule.setIdentityChangeStateView(
|
||||
fun `Should not show any banner if no violations`() = runAndroidComposeUiTest {
|
||||
setIdentityChangeStateView(
|
||||
state = anIdentityChangeState(
|
||||
listOf(
|
||||
RoomMemberIdentityStateChange(
|
||||
|
|
@ -93,10 +92,10 @@ class IdentityChangeStateViewTest {
|
|||
),
|
||||
)
|
||||
|
||||
rule.onNodeWithText("identity was reset", substring = true).assertDoesNotExist()
|
||||
onNodeWithText("identity was reset", substring = true).assertDoesNotExist()
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setIdentityChangeStateView(
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setIdentityChangeStateView(
|
||||
state: IdentityChangeState,
|
||||
) {
|
||||
setContent {
|
||||
|
|
|
|||
|
|
@ -6,54 +6,53 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl.crypto.sendfailure.resolve
|
||||
|
||||
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.v2.runAndroidComposeUiTest
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.tests.testutils.EventsRecorder
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.setSafeContent
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ResolveVerifiedUserSendFailureViewTest {
|
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `clicking on resolve and resend emit the expected event`() {
|
||||
fun `clicking on resolve and resend emit the expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<ResolveVerifiedUserSendFailureEvent>()
|
||||
rule.setResolveVerifiedUserSendFailureView(
|
||||
setResolveVerifiedUserSendFailureView(
|
||||
state = aResolveVerifiedUserSendFailureState(
|
||||
verifiedUserSendFailure = aChangedIdentitySendFailure(),
|
||||
eventSink = eventsRecorder,
|
||||
),
|
||||
)
|
||||
|
||||
rule.clickOn(res = CommonStrings.screen_resolve_send_failure_changed_identity_primary_button_title)
|
||||
clickOn(res = CommonStrings.screen_resolve_send_failure_changed_identity_primary_button_title)
|
||||
eventsRecorder.assertSingle(ResolveVerifiedUserSendFailureEvent.ResolveAndResend)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on retry emit the expected event`() {
|
||||
fun `clicking on retry emit the expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<ResolveVerifiedUserSendFailureEvent>()
|
||||
rule.setResolveVerifiedUserSendFailureView(
|
||||
setResolveVerifiedUserSendFailureView(
|
||||
state = aResolveVerifiedUserSendFailureState(
|
||||
verifiedUserSendFailure = aChangedIdentitySendFailure(),
|
||||
eventSink = eventsRecorder,
|
||||
),
|
||||
)
|
||||
|
||||
rule.clickOn(res = CommonStrings.action_retry)
|
||||
clickOn(res = CommonStrings.action_retry)
|
||||
eventsRecorder.assertSingle(ResolveVerifiedUserSendFailureEvent.Retry)
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setResolveVerifiedUserSendFailureView(
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setResolveVerifiedUserSendFailureView(
|
||||
state: ResolveVerifiedUserSendFailureState,
|
||||
) {
|
||||
setSafeContent {
|
||||
|
|
|
|||
|
|
@ -6,11 +6,14 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl.link
|
||||
|
||||
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.v2.runAndroidComposeUiTest
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
|
@ -19,51 +22,46 @@ import io.element.android.tests.testutils.EventsRecorder
|
|||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.ensureCalledOnceWithParam
|
||||
import io.element.android.wysiwyg.link.Link
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class LinkViewTest {
|
||||
@get:Rule
|
||||
val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `clicking on cancel emits the expected event`() {
|
||||
fun `clicking on cancel emits the expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<LinkEvent>()
|
||||
rule.setLinkView(
|
||||
setLinkView(
|
||||
aLinkState(
|
||||
linkClick = ConfirmingLinkClick(aLink),
|
||||
eventSink = eventsRecorder,
|
||||
),
|
||||
)
|
||||
rule.clickOn(CommonStrings.action_cancel)
|
||||
clickOn(CommonStrings.action_cancel)
|
||||
eventsRecorder.assertSingle(
|
||||
LinkEvent.Cancel
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on continue emits the expected event`() {
|
||||
fun `clicking on continue emits the expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<LinkEvent>()
|
||||
rule.setLinkView(
|
||||
setLinkView(
|
||||
aLinkState(
|
||||
linkClick = ConfirmingLinkClick(aLink),
|
||||
eventSink = eventsRecorder,
|
||||
),
|
||||
)
|
||||
rule.clickOn(CommonStrings.action_continue)
|
||||
clickOn(CommonStrings.action_continue)
|
||||
eventsRecorder.assertSingle(
|
||||
LinkEvent.Confirm
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `success state invokes the callback and emits the expected event`() {
|
||||
fun `success state invokes the callback and emits the expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<LinkEvent>()
|
||||
ensureCalledOnceWithParam(aLink) { callback ->
|
||||
rule.setLinkView(
|
||||
setLinkView(
|
||||
aLinkState(
|
||||
linkClick = AsyncAction.Success(aLink),
|
||||
eventSink = eventsRecorder,
|
||||
|
|
@ -77,7 +75,7 @@ class LinkViewTest {
|
|||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setLinkView(
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setLinkView(
|
||||
state: LinkState,
|
||||
onLinkValid: (Link) -> Unit = EnsureNeverCalledWithParam(),
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -6,13 +6,16 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl.pinned.banner
|
||||
|
||||
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.onRoot
|
||||
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.EventId
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
|
@ -22,49 +25,45 @@ 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.ensureCalledOnceWithParam
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class PinnedMessagesBannerViewTest {
|
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `clicking on the banner invoke expected callback`() {
|
||||
fun `clicking on the banner invoke expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<PinnedMessagesBannerEvent>()
|
||||
val state = aLoadedPinnedMessagesBannerState(
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
val pinnedEventId = state.currentPinnedMessage.eventId
|
||||
ensureCalledOnceWithParam(pinnedEventId) { callback ->
|
||||
rule.setPinnedMessagesBannerView(
|
||||
setPinnedMessagesBannerView(
|
||||
state = state,
|
||||
onClick = callback
|
||||
)
|
||||
rule.onRoot().performClick()
|
||||
onRoot().performClick()
|
||||
eventsRecorder.assertSingle(PinnedMessagesBannerEvent.MoveToNextPinned)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on view all emit the expected event`() {
|
||||
fun `clicking on view all emit the expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<PinnedMessagesBannerEvent>(expectEvents = true)
|
||||
val state = aLoadedPinnedMessagesBannerState(
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setPinnedMessagesBannerView(
|
||||
setPinnedMessagesBannerView(
|
||||
state = state,
|
||||
onViewAllClick = callback
|
||||
)
|
||||
rule.clickOn(CommonStrings.screen_room_pinned_banner_view_all_button_title)
|
||||
clickOn(CommonStrings.screen_room_pinned_banner_view_all_button_title)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setPinnedMessagesBannerView(
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setPinnedMessagesBannerView(
|
||||
state: PinnedMessagesBannerState,
|
||||
onClick: (EventId) -> Unit = EnsureNeverCalledWithParam(),
|
||||
onViewAllClick: () -> Unit = EnsureNeverCalled(),
|
||||
|
|
|
|||
|
|
@ -6,16 +6,19 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl.pinned.list
|
||||
|
||||
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.longClick
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onFirst
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performTouchInput
|
||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.features.messages.impl.actionlist.ActionListEvent
|
||||
import io.element.android.features.messages.impl.actionlist.anActionListState
|
||||
|
|
@ -31,33 +34,28 @@ import io.element.android.tests.testutils.ensureCalledOnceWithParam
|
|||
import io.element.android.tests.testutils.pressBack
|
||||
import io.element.android.tests.testutils.setSafeContent
|
||||
import io.element.android.wysiwyg.link.Link
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class PinnedMessagesListViewTest {
|
||||
@get:Rule
|
||||
val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `clicking on back calls the expected callback`() {
|
||||
fun `clicking on back calls the expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<PinnedMessagesListEvent>(expectEvents = false)
|
||||
val state = aLoadedPinnedMessagesListState(
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
ensureCalledOnce { callback ->
|
||||
rule.setPinnedMessagesListView(
|
||||
setPinnedMessagesListView(
|
||||
state = state,
|
||||
onBackClick = callback
|
||||
)
|
||||
rule.pressBack()
|
||||
pressBack()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `click on an event calls the expected callback`() {
|
||||
fun `click on an event calls the expected callback`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<PinnedMessagesListEvent>(expectEvents = false)
|
||||
val content = aTimelineItemFileContent()
|
||||
val state = aLoadedPinnedMessagesListState(
|
||||
|
|
@ -67,16 +65,16 @@ class PinnedMessagesListViewTest {
|
|||
|
||||
val event = state.timelineItems.first() as TimelineItem.Event
|
||||
ensureCalledOnceWithParam(event) { callback ->
|
||||
rule.setPinnedMessagesListView(
|
||||
setPinnedMessagesListView(
|
||||
state = state,
|
||||
onEventClick = callback
|
||||
)
|
||||
rule.onAllNodesWithText(content.filename).onFirst().performClick()
|
||||
onAllNodesWithText(content.filename).onFirst().performClick()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `long click on an event emits the expected event`() {
|
||||
fun `long click on an event emits the expected event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<ActionListEvent>(expectEvents = true)
|
||||
val content = aTimelineItemFileContent()
|
||||
val state = aLoadedPinnedMessagesListState(
|
||||
|
|
@ -84,10 +82,10 @@ class PinnedMessagesListViewTest {
|
|||
actionListState = anActionListState(eventSink = eventsRecorder)
|
||||
)
|
||||
|
||||
rule.setPinnedMessagesListView(
|
||||
setPinnedMessagesListView(
|
||||
state = state,
|
||||
)
|
||||
rule.onAllNodesWithText(content.filename).onFirst()
|
||||
onAllNodesWithText(content.filename).onFirst()
|
||||
.performTouchInput {
|
||||
longClick()
|
||||
}
|
||||
|
|
@ -96,7 +94,7 @@ class PinnedMessagesListViewTest {
|
|||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setPinnedMessagesListView(
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setPinnedMessagesListView(
|
||||
state: PinnedMessagesListState,
|
||||
onBackClick: () -> Unit = EnsureNeverCalled(),
|
||||
onEventClick: (event: TimelineItem.Event) -> Unit = EnsureNeverCalledWithParam(),
|
||||
|
|
|
|||
|
|
@ -6,11 +6,14 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl.timeline
|
||||
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.v2.runComposeUiTest
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.features.messages.impl.utils.FakeMentionSpanFormatter
|
||||
import io.element.android.libraries.core.extensions.runCatchingExceptions
|
||||
|
|
@ -18,15 +21,12 @@ import io.element.android.libraries.matrix.test.A_USER_ID
|
|||
import io.element.android.libraries.matrix.test.permalink.FakePermalinkParser
|
||||
import io.element.android.libraries.textcomposer.mentions.MentionSpanProvider
|
||||
import io.element.android.libraries.textcomposer.mentions.MentionSpanTheme
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class DefaultHtmlConverterProviderTest {
|
||||
@get:Rule val composeTestRule = createComposeRule()
|
||||
|
||||
private val provider = DefaultHtmlConverterProvider(
|
||||
mentionSpanProvider = MentionSpanProvider(
|
||||
permalinkParser = FakePermalinkParser(),
|
||||
|
|
@ -43,8 +43,8 @@ class DefaultHtmlConverterProviderTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `calling provide after calling Update first should return an HtmlConverter`() {
|
||||
composeTestRule.setContent {
|
||||
fun `calling provide after calling Update first should return an HtmlConverter`() = runComposeUiTest {
|
||||
setContent {
|
||||
CompositionLocalProvider(LocalInspectionMode provides true) {
|
||||
provider.Update()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,18 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl.timeline
|
||||
|
||||
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.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.compose.ui.test.performScrollToIndex
|
||||
import androidx.compose.ui.test.v2.runAndroidComposeUiTest
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.features.messages.impl.timeline.components.MessageShieldData
|
||||
import io.element.android.features.messages.impl.timeline.components.aCriticalShield
|
||||
|
|
@ -39,19 +42,15 @@ import io.element.android.wysiwyg.link.Link
|
|||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import org.junit.Ignore
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class TimelineViewTest {
|
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `reaching the end of the timeline with more events to load emits a LoadMore event`() {
|
||||
fun `reaching the end of the timeline with more events to load emits a LoadMore event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
rule.setTimelineView(
|
||||
setTimelineView(
|
||||
state = aTimelineState(
|
||||
timelineItems = persistentListOf<TimelineItem>(
|
||||
TimelineItem.Virtual(
|
||||
|
|
@ -66,9 +65,9 @@ class TimelineViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `reaching the end of the timeline does not send a LoadMore event`() {
|
||||
fun `reaching the end of the timeline does not send a LoadMore event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
rule.setTimelineView(
|
||||
setTimelineView(
|
||||
state = aTimelineState(
|
||||
timelineItems = persistentListOf(aTimelineItemEvent(content = aTimelineItemImageContent())),
|
||||
eventSink = eventsRecorder,
|
||||
|
|
@ -78,9 +77,9 @@ class TimelineViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `scroll to bottom on live timeline does not emit the Event`() {
|
||||
fun `scroll to bottom on live timeline does not emit the Event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
rule.setTimelineView(
|
||||
setTimelineView(
|
||||
state = aTimelineState(
|
||||
timelineItems = persistentListOf(aTimelineItemEvent(content = aTimelineItemImageContent())),
|
||||
isLive = true,
|
||||
|
|
@ -92,14 +91,14 @@ class TimelineViewTest {
|
|||
eventsRecorder.assertSingle(TimelineEvent.OnScrollFinished(firstIndex = 0))
|
||||
eventsRecorder.clear()
|
||||
|
||||
val contentDescription = rule.activity.getString(CommonStrings.a11y_jump_to_bottom)
|
||||
rule.onNodeWithContentDescription(contentDescription).performClick()
|
||||
val contentDescription = activity!!.getString(CommonStrings.a11y_jump_to_bottom)
|
||||
onNodeWithContentDescription(contentDescription).performClick()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `scroll to bottom on detached timeline emits the expected Event`() {
|
||||
fun `scroll to bottom on detached timeline emits the expected Event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
rule.setTimelineView(
|
||||
setTimelineView(
|
||||
state = aTimelineState(
|
||||
timelineItems = persistentListOf(aTimelineItemEvent(content = aTimelineItemImageContent())),
|
||||
isLive = false,
|
||||
|
|
@ -110,15 +109,15 @@ class TimelineViewTest {
|
|||
eventsRecorder.assertSingle(TimelineEvent.OnScrollFinished(firstIndex = 0))
|
||||
eventsRecorder.clear()
|
||||
|
||||
val contentDescription = rule.activity.getString(CommonStrings.a11y_jump_to_bottom)
|
||||
rule.onNodeWithContentDescription(contentDescription).performClick()
|
||||
val contentDescription = activity!!.getString(CommonStrings.a11y_jump_to_bottom)
|
||||
onNodeWithContentDescription(contentDescription).performClick()
|
||||
eventsRecorder.assertSingle(TimelineEvent.JumpToLive)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `an empty timeline triggers a prefetch`() {
|
||||
fun `an empty timeline triggers a prefetch`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
rule.setTimelineView(
|
||||
setTimelineView(
|
||||
state = aTimelineState(
|
||||
timelineItems = persistentListOf(),
|
||||
eventSink = eventsRecorder,
|
||||
|
|
@ -129,9 +128,9 @@ class TimelineViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `show shield dialog`() {
|
||||
fun `show shield dialog`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
rule.setTimelineView(
|
||||
setTimelineView(
|
||||
state = aTimelineState(
|
||||
timelineItems = persistentListOf<TimelineItem>(
|
||||
aTimelineItemEvent(
|
||||
|
|
@ -143,8 +142,8 @@ class TimelineViewTest {
|
|||
eventSink = eventsRecorder,
|
||||
),
|
||||
)
|
||||
val contentDescription = rule.activity.getString(CommonStrings.a11y_encryption_details)
|
||||
rule.onNodeWithContentDescription(contentDescription).performClick()
|
||||
val contentDescription = activity!!.getString(CommonStrings.a11y_encryption_details)
|
||||
onNodeWithContentDescription(contentDescription).performClick()
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
TimelineEvent.OnScrollFinished(0),
|
||||
|
|
@ -154,9 +153,9 @@ class TimelineViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `hide shield dialog`() {
|
||||
fun `hide shield dialog`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
rule.setTimelineView(
|
||||
setTimelineView(
|
||||
state = aTimelineState(
|
||||
timelineItems = persistentListOf(aTimelineItemEvent(content = aTimelineItemImageContent())),
|
||||
isLive = false,
|
||||
|
|
@ -167,16 +166,16 @@ class TimelineViewTest {
|
|||
eventsRecorder.assertSingle(TimelineEvent.OnScrollFinished(firstIndex = 0))
|
||||
eventsRecorder.clear()
|
||||
|
||||
rule.clickOn(CommonStrings.action_ok)
|
||||
clickOn(CommonStrings.action_ok)
|
||||
eventsRecorder.assertSingle(TimelineEvent.HideShieldDialog)
|
||||
}
|
||||
|
||||
@Ignore(
|
||||
"performScrollToIndex in compose tests no longer sets LazyListState.isScrollInProgress to true, so the LoadMore event is not emitted." +
|
||||
"This needs to be reworked to use a different approach to check the LoadMore event was emitted."
|
||||
"This needs to be reworked to use a different approach to check the LoadMore event was emitted."
|
||||
)
|
||||
@Test
|
||||
fun `scrolling near to the start of the loaded items triggers a pre-fetch`() {
|
||||
fun `scrolling near to the start of the loaded items triggers a pre-fetch`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent>()
|
||||
val items = List<TimelineItem>(200) {
|
||||
aTimelineItemEvent(
|
||||
|
|
@ -185,7 +184,7 @@ class TimelineViewTest {
|
|||
)
|
||||
}.toImmutableList()
|
||||
|
||||
rule.setTimelineView(
|
||||
setTimelineView(
|
||||
state = aTimelineState(
|
||||
timelineItems = items,
|
||||
eventSink = eventsRecorder,
|
||||
|
|
@ -194,9 +193,9 @@ class TimelineViewTest {
|
|||
),
|
||||
)
|
||||
|
||||
rule.onNodeWithTag("timeline").performScrollToIndex(180)
|
||||
onNodeWithTag("timeline").performScrollToIndex(180)
|
||||
|
||||
rule.mainClock.advanceTimeBy(1000)
|
||||
mainClock.advanceTimeBy(1000)
|
||||
|
||||
eventsRecorder.assertList(
|
||||
listOf(
|
||||
|
|
@ -207,7 +206,7 @@ class TimelineViewTest {
|
|||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setTimelineView(
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setTimelineView(
|
||||
state: TimelineState,
|
||||
timelineProtectionState: TimelineProtectionState = aTimelineProtectionState(),
|
||||
onUserDataClick: (MatrixUser) -> Unit = EnsureNeverCalledWithParam(),
|
||||
|
|
|
|||
|
|
@ -6,12 +6,15 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.event
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.ui.test.ExperimentalTestApi
|
||||
import androidx.compose.ui.test.hasText
|
||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||
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.messages.impl.timeline.TimelineEvent
|
||||
import io.element.android.features.messages.impl.timeline.model.event.aTimelineItemPollContent
|
||||
|
|
@ -20,14 +23,11 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
|||
import io.element.android.tests.testutils.EventsRecorder
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.pressTag
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class TimelineItemPollViewTest {
|
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `answering a poll with first answer should emit a PollAnswerSelected event`() {
|
||||
testAnswer(answerIndex = 0)
|
||||
|
|
@ -38,17 +38,17 @@ class TimelineItemPollViewTest {
|
|||
testAnswer(answerIndex = 1)
|
||||
}
|
||||
|
||||
private fun testAnswer(answerIndex: Int) {
|
||||
private fun testAnswer(answerIndex: Int) = runAndroidComposeUiTest<ComponentActivity> {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent.TimelineItemPollEvent>()
|
||||
val content = aTimelineItemPollContent()
|
||||
rule.setContent {
|
||||
setContent {
|
||||
TimelineItemPollView(
|
||||
content = content,
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
}
|
||||
val answer = content.answerItems[answerIndex].answer
|
||||
rule.onNode(
|
||||
onNode(
|
||||
matcher = hasText(answer.text),
|
||||
useUnmergedTree = true,
|
||||
).performClick()
|
||||
|
|
@ -56,38 +56,38 @@ class TimelineItemPollViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `editing a poll should emit a PollEditClicked event`() {
|
||||
fun `editing a poll should emit a PollEditClicked event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent.TimelineItemPollEvent>()
|
||||
val content = aTimelineItemPollContent(
|
||||
isMine = true,
|
||||
isEditable = true,
|
||||
)
|
||||
rule.setContent {
|
||||
setContent {
|
||||
TimelineItemPollView(
|
||||
content = content,
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
}
|
||||
rule.clickOn(CommonStrings.action_edit_poll)
|
||||
clickOn(CommonStrings.action_edit_poll)
|
||||
eventsRecorder.assertSingle(TimelineEvent.EditPoll(content.eventId!!))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `closing a poll should emit a PollEndClicked event`() {
|
||||
fun `closing a poll should emit a PollEndClicked event`() = runAndroidComposeUiTest {
|
||||
val eventsRecorder = EventsRecorder<TimelineEvent.TimelineItemPollEvent>()
|
||||
val content = aTimelineItemPollContent(
|
||||
isMine = true,
|
||||
)
|
||||
rule.setContent {
|
||||
setContent {
|
||||
TimelineItemPollView(
|
||||
content = content,
|
||||
eventSink = eventsRecorder
|
||||
)
|
||||
}
|
||||
rule.clickOn(CommonStrings.action_end_poll)
|
||||
clickOn(CommonStrings.action_end_poll)
|
||||
// A confirmation dialog should be shown
|
||||
eventsRecorder.assertEmpty()
|
||||
rule.pressTag(TestTags.dialogPositive.value)
|
||||
pressTag(TestTags.dialogPositive.value)
|
||||
eventsRecorder.assertSingle(TimelineEvent.EndPoll(content.eventId!!))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,14 +6,17 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.event
|
||||
|
||||
import android.text.SpannableString
|
||||
import android.text.SpannedString
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
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.v2.runAndroidComposeUiTest
|
||||
import androidx.core.text.buildSpannedString
|
||||
import androidx.core.text.inSpans
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
|
@ -38,45 +41,40 @@ import io.element.android.tests.testutils.lambda.assert
|
|||
import io.element.android.tests.testutils.lambda.lambdaRecorder
|
||||
import io.element.android.wysiwyg.view.spans.CustomMentionSpan
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class TimelineTextViewTest {
|
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
private val mentionSpanTheme = MentionSpanTheme(currentUserId = A_USER_ID)
|
||||
private val formatLambda = lambdaRecorder<MentionType, CharSequence> { mentionType -> mentionType.toString() }
|
||||
private val mentionSpanFormatter = FakeMentionSpanFormatter(formatLambda)
|
||||
|
||||
@Test
|
||||
fun `getTextWithResolvedMentions - does nothing for a non spannable CharSequence`() = runTest {
|
||||
fun `getTextWithResolvedMentions - does nothing for a non spannable CharSequence`() = runAndroidComposeUiTest {
|
||||
val charSequence = "Hello <a href=\"https://matrix.to/#/@alice:example.com\">@alice:example.com</a>"
|
||||
val mentionSpanUpdater = aMentionSpanUpdater()
|
||||
val result = rule.getText(mentionSpanUpdater, aTextContentWithFormattedBody(charSequence))
|
||||
val result = getText(mentionSpanUpdater, aTextContentWithFormattedBody(charSequence))
|
||||
|
||||
assertThat(result.getMentionSpans()).isEmpty()
|
||||
assert(formatLambda).isNeverCalled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getTextWithResolvedMentions - does nothing if there are no mentions`() = runTest {
|
||||
fun `getTextWithResolvedMentions - does nothing if there are no mentions`() = runAndroidComposeUiTest {
|
||||
val charSequence = SpannableString("Hello <a href=\"https://matrix.to/#/@alice:example.com\">@alice:example.com</a>")
|
||||
val mentionSpanUpdater = aMentionSpanUpdater()
|
||||
val result = rule.getText(mentionSpanUpdater, aTextContentWithFormattedBody(charSequence))
|
||||
val result = getText(mentionSpanUpdater, aTextContentWithFormattedBody(charSequence))
|
||||
|
||||
assertThat(result.getMentionSpans()).isEmpty()
|
||||
assert(formatLambda).isNeverCalled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `getTextWithResolvedMentions - just returns the body if there is no formattedBody`() = runTest {
|
||||
fun `getTextWithResolvedMentions - just returns the body if there is no formattedBody`() = runAndroidComposeUiTest {
|
||||
val charSequence = "Hello <a href=\"https://matrix.to/#/@alice:example.com\">@alice:example.com</a>"
|
||||
val mentionSpanUpdater = aMentionSpanUpdater()
|
||||
val result = rule.getText(mentionSpanUpdater, aTextContentWithFormattedBody(body = charSequence, formattedBody = null))
|
||||
val result = getText(mentionSpanUpdater, aTextContentWithFormattedBody(body = charSequence, formattedBody = null))
|
||||
|
||||
assertThat(result.getMentionSpans()).isEmpty()
|
||||
assertThat(result.toString()).isEqualTo(charSequence)
|
||||
|
|
@ -84,7 +82,7 @@ class TimelineTextViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `getTextWithResolvedMentions - with Room mention format correctly`() = runTest {
|
||||
fun `getTextWithResolvedMentions - with Room mention format correctly`() = runAndroidComposeUiTest {
|
||||
val mentionType = MentionType.Room(roomIdOrAlias = A_ROOM_ID_2.toRoomIdOrAlias())
|
||||
val charSequence = buildSpannedString {
|
||||
append("Hello ")
|
||||
|
|
@ -93,7 +91,7 @@ class TimelineTextViewTest {
|
|||
}
|
||||
}
|
||||
val mentionSpanUpdater = aMentionSpanUpdater()
|
||||
val result = rule.getText(mentionSpanUpdater, aTextContentWithFormattedBody(charSequence))
|
||||
val result = getText(mentionSpanUpdater, aTextContentWithFormattedBody(charSequence))
|
||||
|
||||
val expectedDisplayText = mentionType.toString()
|
||||
assertThat(result.getMentionSpans().firstOrNull()?.displayText.toString()).isEqualTo(expectedDisplayText)
|
||||
|
|
@ -102,7 +100,7 @@ class TimelineTextViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `getTextWithResolvedMentions - replaces MentionSpan's text`() = runTest {
|
||||
fun `getTextWithResolvedMentions - replaces MentionSpan's text`() = runAndroidComposeUiTest {
|
||||
val mentionType = MentionType.User(userId = A_USER_ID)
|
||||
val charSequence = buildSpannedString {
|
||||
append("Hello ")
|
||||
|
|
@ -111,7 +109,7 @@ class TimelineTextViewTest {
|
|||
}
|
||||
}
|
||||
val mentionSpanUpdater = aMentionSpanUpdater()
|
||||
val result = rule.getText(mentionSpanUpdater, aTextContentWithFormattedBody(charSequence))
|
||||
val result = getText(mentionSpanUpdater, aTextContentWithFormattedBody(charSequence))
|
||||
|
||||
val expectedDisplayText = mentionType.toString()
|
||||
assertThat(result.getMentionSpans().firstOrNull()?.displayText.toString()).isEqualTo(expectedDisplayText)
|
||||
|
|
@ -119,7 +117,7 @@ class TimelineTextViewTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `getTextWithResolvedMentions - replaces MentionSpan's text inside CustomMentionSpan`() = runTest {
|
||||
fun `getTextWithResolvedMentions - replaces MentionSpan's text inside CustomMentionSpan`() = runAndroidComposeUiTest {
|
||||
val mentionType = MentionType.User(userId = A_USER_ID)
|
||||
val charSequence = buildSpannedString {
|
||||
append("Hello ")
|
||||
|
|
@ -129,12 +127,12 @@ class TimelineTextViewTest {
|
|||
}
|
||||
val mentionSpanUpdater = aMentionSpanUpdater()
|
||||
val expectedDisplayText = mentionType.toString()
|
||||
val result = rule.getText(mentionSpanUpdater, aTextContentWithFormattedBody(charSequence))
|
||||
val result = getText(mentionSpanUpdater, aTextContentWithFormattedBody(charSequence))
|
||||
assertThat(result.getMentionSpans().firstOrNull()?.displayText.toString()).isEqualTo(expectedDisplayText)
|
||||
assert(formatLambda).isCalledOnce()
|
||||
}
|
||||
|
||||
private suspend fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.getText(
|
||||
private suspend fun AndroidComposeUiTest<ComponentActivity>.getText(
|
||||
mentionSpanUpdater: MentionSpanUpdater,
|
||||
content: TimelineItemTextBasedContent,
|
||||
): CharSequence {
|
||||
|
|
|
|||
|
|
@ -6,56 +6,55 @@
|
|||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalTestApi::class)
|
||||
|
||||
package io.element.android.features.messages.impl.timeline.protection
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.runtime.Composable
|
||||
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.v2.runAndroidComposeUiTest
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import io.element.android.tests.testutils.clickOn
|
||||
import io.element.android.tests.testutils.ensureCalledOnce
|
||||
import io.element.android.tests.testutils.lambda.lambdaError
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ProtectedViewTest {
|
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
@Test
|
||||
fun `when hideContent is false, the content is rendered`() {
|
||||
rule.setProtectedView(
|
||||
fun `when hideContent is false, the content is rendered`() = runAndroidComposeUiTest {
|
||||
setProtectedView(
|
||||
hideContent = false,
|
||||
content = {
|
||||
Text("Hello")
|
||||
}
|
||||
)
|
||||
rule.onNodeWithText("Hello").assertExists()
|
||||
onNodeWithText("Hello").assertExists()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `when hideContent is true, the content is not rendered, and user can reveal it`() {
|
||||
fun `when hideContent is true, the content is not rendered, and user can reveal it`() = runAndroidComposeUiTest {
|
||||
ensureCalledOnce {
|
||||
rule.setProtectedView(
|
||||
setProtectedView(
|
||||
hideContent = true,
|
||||
onShowClick = it,
|
||||
content = {
|
||||
Text("Hello")
|
||||
}
|
||||
)
|
||||
rule.onNodeWithText("Hello").assertDoesNotExist()
|
||||
rule.clickOn(CommonStrings.action_show)
|
||||
onNodeWithText("Hello").assertDoesNotExist()
|
||||
clickOn(CommonStrings.action_show)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setProtectedView(
|
||||
private fun AndroidComposeUiTest<ComponentActivity>.setProtectedView(
|
||||
hideContent: Boolean = false,
|
||||
onShowClick: () -> Unit = { lambdaError() },
|
||||
content: @Composable () -> Unit = {},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue