Skip to content

Commit 04995cb

Browse files
committed
Pinned events : add some ui testing
1 parent c609a7d commit 04995cb

File tree

4 files changed

+118
-2
lines changed

4 files changed

+118
-2
lines changed

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesView.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import io.element.android.features.messages.impl.messagecomposer.MessageComposer
7474
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerState
7575
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerView
7676
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerViewDefaults
77+
import io.element.android.features.messages.impl.timeline.FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS
7778
import io.element.android.features.messages.impl.timeline.TimelineEvents
7879
import io.element.android.features.messages.impl.timeline.TimelineView
7980
import io.element.android.features.messages.impl.timeline.components.JoinCallMenuItem
@@ -401,13 +402,13 @@ private fun MessagesViewContent(
401402
nestedScrollConnection = scrollBehavior.nestedScrollConnection,
402403
)
403404
AnimatedVisibility(
404-
visible = state.pinnedMessagesBannerState != PinnedMessagesBannerState.Hidden && scrollBehavior.isVisible,
405+
visible = state.pinnedMessagesBannerState is PinnedMessagesBannerState.Visible && scrollBehavior.isVisible,
405406
enter = expandVertically(),
406407
exit = shrinkVertically(),
407408
) {
408409
fun focusOnPinnedEvent(eventId: EventId) {
409410
state.timelineState.eventSink(
410-
TimelineEvents.FocusOnEvent(eventId = eventId, debounce = 200.milliseconds)
411+
TimelineEvents.FocusOnEvent(eventId = eventId, debounce = FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS.milliseconds)
411412
)
412413
}
413414
PinnedMessagesBannerView(

features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelinePresenter.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ import kotlinx.coroutines.flow.onEach
5757
import kotlinx.coroutines.launch
5858
import kotlinx.coroutines.withContext
5959

60+
const val FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS = 200L
61+
6062
class TimelinePresenter @AssistedInject constructor(
6163
private val timelineItemsFactory: TimelineItemsFactory,
6264
private val timelineItemIndexer: TimelineItemIndexer,

features/messages/impl/src/test/kotlin/io/element/android/features/messages/impl/MessagesViewTest.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import androidx.compose.ui.test.onNodeWithText
3333
import androidx.compose.ui.test.performClick
3434
import androidx.compose.ui.test.performTouchInput
3535
import androidx.compose.ui.test.swipeRight
36+
import androidx.compose.ui.text.AnnotatedString
3637
import androidx.test.ext.junit.runners.AndroidJUnit4
3738
import io.element.android.emojibasebindings.Emoji
3839
import io.element.android.emojibasebindings.EmojibaseCategory
@@ -43,6 +44,10 @@ import io.element.android.features.messages.impl.actionlist.anActionListState
4344
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
4445
import io.element.android.features.messages.impl.attachments.Attachment
4546
import io.element.android.features.messages.impl.messagecomposer.aMessageComposerState
47+
import io.element.android.features.messages.impl.pinned.banner.PinnedMessagesBannerItem
48+
import io.element.android.features.messages.impl.pinned.banner.aLoadedPinnedMessagesBannerState
49+
import io.element.android.features.messages.impl.timeline.FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS
50+
import io.element.android.features.messages.impl.timeline.TimelineEvents
4651
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent
4752
import io.element.android.features.messages.impl.timeline.aTimelineItemReadReceipts
4853
import io.element.android.features.messages.impl.timeline.aTimelineRoomInfo
@@ -54,6 +59,7 @@ import io.element.android.features.messages.impl.timeline.components.receipt.aRe
5459
import io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet.ReadReceiptBottomSheetEvents
5560
import io.element.android.features.messages.impl.timeline.model.TimelineItem
5661
import io.element.android.libraries.matrix.api.core.UserId
62+
import io.element.android.libraries.matrix.test.AN_EVENT_ID
5763
import io.element.android.libraries.testtags.TestTags
5864
import io.element.android.libraries.ui.strings.CommonStrings
5965
import io.element.android.tests.testutils.EnsureCalledOnceWithParam
@@ -72,6 +78,7 @@ import org.junit.Test
7278
import org.junit.rules.TestRule
7379
import org.junit.runner.RunWith
7480
import org.robolectric.annotation.Config
81+
import kotlin.time.Duration.Companion.milliseconds
7582

7683
@RunWith(AndroidJUnit4::class)
7784
class MessagesViewTest {
@@ -458,6 +465,25 @@ class MessagesViewTest {
458465
customReactionStateEventsRecorder.assertSingle(CustomReactionEvents.DismissCustomReactionSheet)
459466
eventsRecorder.assertSingle(MessagesEvents.ToggleReaction(aUnicode, timelineItem.eventId!!))
460467
}
468+
469+
@Test
470+
fun `clicking on pinned messages banner emits the expected Event`() {
471+
val eventsRecorder = EventsRecorder<TimelineEvents>()
472+
val state = aMessagesState(
473+
timelineState = aTimelineState(eventSink = eventsRecorder),
474+
pinnedMessagesBannerState = aLoadedPinnedMessagesBannerState(
475+
knownPinnedMessagesCount = 2,
476+
currentPinnedMessageIndex = 0,
477+
currentPinnedMessage = PinnedMessagesBannerItem(
478+
eventId = AN_EVENT_ID,
479+
formatted = AnnotatedString("This is a pinned message")
480+
),
481+
),
482+
)
483+
rule.setMessagesView(state = state)
484+
rule.onNodeWithText("This is a pinned message").performClick()
485+
eventsRecorder.assertSingle(TimelineEvents.FocusOnEvent(AN_EVENT_ID, debounce = FOCUS_ON_PINNED_EVENT_DEBOUNCE_DURATION_IN_MILLIS.milliseconds))
486+
}
461487
}
462488

463489
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setMessagesView(
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2024 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.element.android.features.messages.impl.pinned.banner
18+
19+
import androidx.activity.ComponentActivity
20+
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
21+
import androidx.compose.ui.test.junit4.createAndroidComposeRule
22+
import androidx.compose.ui.test.onRoot
23+
import androidx.compose.ui.test.performClick
24+
import androidx.test.ext.junit.runners.AndroidJUnit4
25+
import io.element.android.libraries.matrix.api.core.EventId
26+
import io.element.android.libraries.ui.strings.CommonStrings
27+
import io.element.android.tests.testutils.EnsureNeverCalled
28+
import io.element.android.tests.testutils.EnsureNeverCalledWithParam
29+
import io.element.android.tests.testutils.EventsRecorder
30+
import io.element.android.tests.testutils.clickOn
31+
import io.element.android.tests.testutils.ensureCalledOnce
32+
import io.element.android.tests.testutils.ensureCalledOnceWithParam
33+
import org.junit.Rule
34+
import org.junit.Test
35+
import org.junit.rules.TestRule
36+
import org.junit.runner.RunWith
37+
38+
@RunWith(AndroidJUnit4::class)
39+
class PinnedMessagesBannerViewTest {
40+
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>()
41+
42+
@Test
43+
fun `clicking on the banner invoke expected callback`() {
44+
val eventsRecorder = EventsRecorder<PinnedMessagesBannerEvents>()
45+
val state = aLoadedPinnedMessagesBannerState(
46+
eventSink = eventsRecorder
47+
)
48+
val pinnedEventId = state.currentPinnedMessage.eventId
49+
ensureCalledOnceWithParam(pinnedEventId) { callback ->
50+
rule.setPinnedMessagesBannerView(
51+
state = state,
52+
onClick = callback
53+
)
54+
rule.onRoot().performClick()
55+
eventsRecorder.assertSingle(PinnedMessagesBannerEvents.MoveToNextPinned)
56+
}
57+
}
58+
59+
@Test
60+
fun `clicking on view all emit the expected event`() {
61+
val eventsRecorder = EventsRecorder<PinnedMessagesBannerEvents>(expectEvents = true)
62+
val state = aLoadedPinnedMessagesBannerState(
63+
eventSink = eventsRecorder
64+
)
65+
ensureCalledOnce { callback ->
66+
rule.setPinnedMessagesBannerView(
67+
state = state,
68+
onViewAllClick = callback
69+
)
70+
rule.clickOn(CommonStrings.screen_room_pinned_banner_view_all_button_title)
71+
}
72+
}
73+
}
74+
75+
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setPinnedMessagesBannerView(
76+
state: PinnedMessagesBannerState,
77+
onClick: (EventId) -> Unit = EnsureNeverCalledWithParam(),
78+
onViewAllClick: () -> Unit = EnsureNeverCalled(),
79+
) {
80+
setContent {
81+
PinnedMessagesBannerView(
82+
state = state,
83+
onClick = onClick,
84+
onViewAllClick = onViewAllClick
85+
)
86+
}
87+
}

0 commit comments

Comments
 (0)