ganfra
4 months ago
13 changed files with 1 additions and 593 deletions
@ -1,26 +0,0 @@
@@ -1,26 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.retrysendmenu |
||||
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem |
||||
|
||||
sealed interface RetrySendMenuEvents { |
||||
data class EventSelected(val event: TimelineItem.Event) : RetrySendMenuEvents |
||||
data object Retry : RetrySendMenuEvents |
||||
data object Remove : RetrySendMenuEvents |
||||
data object Dismiss : RetrySendMenuEvents |
||||
} |
@ -1,71 +0,0 @@
@@ -1,71 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.retrysendmenu |
||||
|
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.runtime.getValue |
||||
import androidx.compose.runtime.mutableStateOf |
||||
import androidx.compose.runtime.remember |
||||
import androidx.compose.runtime.rememberCoroutineScope |
||||
import androidx.compose.runtime.setValue |
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem |
||||
import io.element.android.libraries.architecture.Presenter |
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom |
||||
import kotlinx.coroutines.launch |
||||
import javax.inject.Inject |
||||
|
||||
class RetrySendMenuPresenter @Inject constructor( |
||||
private val room: MatrixRoom, |
||||
) : Presenter<RetrySendMenuState> { |
||||
@Composable |
||||
override fun present(): RetrySendMenuState { |
||||
val coroutineScope = rememberCoroutineScope() |
||||
var selectedEvent: TimelineItem.Event? by remember { mutableStateOf(null) } |
||||
|
||||
fun handleEvent(event: RetrySendMenuEvents) { |
||||
when (event) { |
||||
is RetrySendMenuEvents.EventSelected -> { |
||||
selectedEvent = event.event |
||||
} |
||||
RetrySendMenuEvents.Retry -> { |
||||
coroutineScope.launch { |
||||
selectedEvent?.transactionId?.let { transactionId -> |
||||
room.retrySendMessage(transactionId) |
||||
} |
||||
selectedEvent = null |
||||
} |
||||
} |
||||
RetrySendMenuEvents.Remove -> { |
||||
coroutineScope.launch { |
||||
selectedEvent?.transactionId?.let { transactionId -> |
||||
room.cancelSend(transactionId) |
||||
} |
||||
selectedEvent = null |
||||
} |
||||
} |
||||
RetrySendMenuEvents.Dismiss -> { |
||||
selectedEvent = null |
||||
} |
||||
} |
||||
} |
||||
|
||||
return RetrySendMenuState( |
||||
selectedEvent = selectedEvent, |
||||
eventSink = { handleEvent(it) }, |
||||
) |
||||
} |
||||
} |
@ -1,26 +0,0 @@
@@ -1,26 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.retrysendmenu |
||||
|
||||
import androidx.compose.runtime.Immutable |
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem |
||||
|
||||
@Immutable |
||||
data class RetrySendMenuState( |
||||
val selectedEvent: TimelineItem.Event?, |
||||
val eventSink: (RetrySendMenuEvents) -> Unit, |
||||
) |
@ -1,36 +0,0 @@
@@ -1,36 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.retrysendmenu |
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider |
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent |
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem |
||||
|
||||
class RetrySendMenuStateProvider : PreviewParameterProvider<RetrySendMenuState> { |
||||
override val values: Sequence<RetrySendMenuState> = sequenceOf( |
||||
aRetrySendMenuState(), |
||||
aRetrySendMenuState(event = aTimelineItemEvent()), |
||||
) |
||||
} |
||||
|
||||
fun aRetrySendMenuState( |
||||
event: TimelineItem.Event? = null, |
||||
eventSink: (RetrySendMenuEvents) -> Unit = {}, |
||||
) = RetrySendMenuState( |
||||
selectedEvent = event, |
||||
eventSink = eventSink, |
||||
) |
@ -1,159 +0,0 @@
@@ -1,159 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.retrysendmenu |
||||
|
||||
import androidx.compose.foundation.clickable |
||||
import androidx.compose.foundation.layout.ColumnScope |
||||
import androidx.compose.foundation.layout.Spacer |
||||
import androidx.compose.foundation.layout.height |
||||
import androidx.compose.material3.ExperimentalMaterial3Api |
||||
import androidx.compose.material3.ListItem |
||||
import androidx.compose.material3.ListItemDefaults |
||||
import androidx.compose.material3.MaterialTheme |
||||
import androidx.compose.material3.SheetState |
||||
import androidx.compose.material3.rememberModalBottomSheetState |
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.runtime.rememberCoroutineScope |
||||
import androidx.compose.ui.Modifier |
||||
import androidx.compose.ui.res.stringResource |
||||
import androidx.compose.ui.tooling.preview.PreviewParameter |
||||
import androidx.compose.ui.unit.dp |
||||
import io.element.android.compound.theme.ElementTheme |
||||
import io.element.android.features.messages.impl.R |
||||
import io.element.android.libraries.designsystem.preview.ElementPreview |
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight |
||||
import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet |
||||
import io.element.android.libraries.designsystem.theme.components.Text |
||||
import io.element.android.libraries.ui.strings.CommonStrings |
||||
import kotlinx.coroutines.launch |
||||
|
||||
@Composable |
||||
internal fun RetrySendMessageMenu( |
||||
state: RetrySendMenuState, |
||||
modifier: Modifier = Modifier, |
||||
) { |
||||
val isVisible = state.selectedEvent != null |
||||
|
||||
fun onDismiss() { |
||||
state.eventSink(RetrySendMenuEvents.Dismiss) |
||||
} |
||||
|
||||
fun onRetry() { |
||||
state.eventSink(RetrySendMenuEvents.Retry) |
||||
} |
||||
|
||||
fun onRemove() { |
||||
state.eventSink(RetrySendMenuEvents.Remove) |
||||
} |
||||
|
||||
RetrySendMessageMenuBottomSheet( |
||||
modifier = modifier, |
||||
isVisible = isVisible, |
||||
onRetry = ::onRetry, |
||||
onRemove = ::onRemove, |
||||
onDismiss = ::onDismiss |
||||
) |
||||
} |
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class) |
||||
@Composable |
||||
private fun RetrySendMessageMenuBottomSheet( |
||||
isVisible: Boolean, |
||||
onRetry: () -> Unit, |
||||
onRemove: () -> Unit, |
||||
onDismiss: () -> Unit, |
||||
modifier: Modifier = Modifier, |
||||
) { |
||||
val sheetState = rememberModalBottomSheetState() |
||||
val coroutineScope = rememberCoroutineScope() |
||||
|
||||
if (isVisible) { |
||||
ModalBottomSheet( |
||||
modifier = modifier, |
||||
// modifier = modifier.navigationBarsPadding() - FIXME after https://issuetracker.google.com/issues/275849044 |
||||
// .imePadding() |
||||
sheetState = sheetState, |
||||
onDismissRequest = { |
||||
coroutineScope.launch { |
||||
sheetState.hide() |
||||
onDismiss() |
||||
} |
||||
} |
||||
) { |
||||
RetrySendMenuContents( |
||||
onRetry = onRetry, |
||||
onRemove = onRemove, |
||||
) |
||||
// FIXME remove after https://issuetracker.google.com/issues/275849044 |
||||
Spacer(modifier = Modifier.height(32.dp)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class) |
||||
@Composable |
||||
private fun ColumnScope.RetrySendMenuContents( |
||||
onRetry: () -> Unit, |
||||
onRemove: () -> Unit, |
||||
sheetState: SheetState = rememberModalBottomSheetState(), |
||||
) { |
||||
val coroutineScope = rememberCoroutineScope() |
||||
|
||||
ListItem(headlineContent = { |
||||
Text( |
||||
text = stringResource(R.string.screen_room_retry_send_menu_title), |
||||
style = ElementTheme.typography.fontBodyLgMedium, |
||||
) |
||||
}) |
||||
ListItem( |
||||
headlineContent = { |
||||
Text( |
||||
text = stringResource(R.string.screen_room_retry_send_menu_send_again_action), |
||||
style = ElementTheme.typography.fontBodyLgRegular, |
||||
) |
||||
}, |
||||
modifier = Modifier.clickable { |
||||
coroutineScope.launch { |
||||
sheetState.hide() |
||||
onRetry() |
||||
} |
||||
} |
||||
) |
||||
ListItem( |
||||
headlineContent = { |
||||
Text( |
||||
text = stringResource(CommonStrings.action_remove), |
||||
style = ElementTheme.typography.fontBodyLgRegular, |
||||
) |
||||
}, |
||||
colors = ListItemDefaults.colors(headlineColor = MaterialTheme.colorScheme.error), |
||||
modifier = Modifier.clickable { |
||||
coroutineScope.launch { |
||||
sheetState.hide() |
||||
onRemove() |
||||
} |
||||
} |
||||
) |
||||
} |
||||
|
||||
@PreviewsDayNight |
||||
@Composable |
||||
internal fun RetrySendMessageMenuPreview(@PreviewParameter(RetrySendMenuStateProvider::class) state: RetrySendMenuState) = ElementPreview { |
||||
RetrySendMessageMenu( |
||||
state = state, |
||||
) |
||||
} |
@ -1,163 +0,0 @@
@@ -1,163 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2023 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.retrysendmenu |
||||
|
||||
import app.cash.molecule.RecompositionMode |
||||
import app.cash.molecule.moleculeFlow |
||||
import app.cash.turbine.test |
||||
import com.google.common.truth.Truth.assertThat |
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent |
||||
import io.element.android.libraries.matrix.test.A_TRANSACTION_ID |
||||
import io.element.android.libraries.matrix.test.room.FakeMatrixRoom |
||||
import io.element.android.tests.testutils.WarmUpRule |
||||
import kotlinx.coroutines.test.runTest |
||||
import org.junit.Rule |
||||
import org.junit.Test |
||||
|
||||
class RetrySendMenuPresenterTest { |
||||
@get:Rule |
||||
val warmUpRule = WarmUpRule() |
||||
|
||||
private val room = FakeMatrixRoom() |
||||
private val presenter = RetrySendMenuPresenter(room) |
||||
|
||||
@Test |
||||
fun `present - handle event selected`() = runTest { |
||||
moleculeFlow(RecompositionMode.Immediate) { |
||||
presenter.present() |
||||
}.test { |
||||
val initialState = awaitItem() |
||||
val selectedEvent = aTimelineItemEvent() |
||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
||||
assertThat(awaitItem().selectedEvent).isSameInstanceAs(selectedEvent) |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun `present - handle dismiss`() = runTest { |
||||
moleculeFlow(RecompositionMode.Immediate) { |
||||
presenter.present() |
||||
}.test { |
||||
val initialState = awaitItem() |
||||
val selectedEvent = aTimelineItemEvent() |
||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
||||
skipItems(1) |
||||
initialState.eventSink(RetrySendMenuEvents.Dismiss) |
||||
assertThat(room.cancelSendCount).isEqualTo(0) |
||||
assertThat(room.retrySendMessageCount).isEqualTo(0) |
||||
assertThat(awaitItem().selectedEvent).isNull() |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun `present - handle resend with transactionId`() = runTest { |
||||
moleculeFlow(RecompositionMode.Immediate) { |
||||
presenter.present() |
||||
}.test { |
||||
val initialState = awaitItem() |
||||
val selectedEvent = aTimelineItemEvent(transactionId = A_TRANSACTION_ID) |
||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
||||
skipItems(1) |
||||
initialState.eventSink(RetrySendMenuEvents.Retry) |
||||
assertThat(room.cancelSendCount).isEqualTo(0) |
||||
assertThat(room.retrySendMessageCount).isEqualTo(1) |
||||
assertThat(awaitItem().selectedEvent).isNull() |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun `present - handle resend without transactionId`() = runTest { |
||||
moleculeFlow(RecompositionMode.Immediate) { |
||||
presenter.present() |
||||
}.test { |
||||
val initialState = awaitItem() |
||||
val selectedEvent = aTimelineItemEvent(transactionId = null) |
||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
||||
skipItems(1) |
||||
initialState.eventSink(RetrySendMenuEvents.Retry) |
||||
assertThat(room.cancelSendCount).isEqualTo(0) |
||||
assertThat(room.retrySendMessageCount).isEqualTo(0) |
||||
assertThat(awaitItem().selectedEvent).isNull() |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun `present - handle resend with error`() = runTest { |
||||
room.givenRetrySendMessageResult(Result.failure(IllegalStateException("An error"))) |
||||
moleculeFlow(RecompositionMode.Immediate) { |
||||
presenter.present() |
||||
}.test { |
||||
val initialState = awaitItem() |
||||
val selectedEvent = aTimelineItemEvent(transactionId = A_TRANSACTION_ID) |
||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
||||
skipItems(1) |
||||
initialState.eventSink(RetrySendMenuEvents.Retry) |
||||
assertThat(room.cancelSendCount).isEqualTo(0) |
||||
assertThat(room.retrySendMessageCount).isEqualTo(1) |
||||
assertThat(awaitItem().selectedEvent).isNull() |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun `present - handle remove failed message with transactionId`() = runTest { |
||||
moleculeFlow(RecompositionMode.Immediate) { |
||||
presenter.present() |
||||
}.test { |
||||
val initialState = awaitItem() |
||||
val selectedEvent = aTimelineItemEvent(transactionId = A_TRANSACTION_ID) |
||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
||||
skipItems(1) |
||||
initialState.eventSink(RetrySendMenuEvents.Remove) |
||||
assertThat(room.cancelSendCount).isEqualTo(1) |
||||
assertThat(room.retrySendMessageCount).isEqualTo(0) |
||||
assertThat(awaitItem().selectedEvent).isNull() |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun `present - handle remove failed message without transactionId`() = runTest { |
||||
moleculeFlow(RecompositionMode.Immediate) { |
||||
presenter.present() |
||||
}.test { |
||||
val initialState = awaitItem() |
||||
val selectedEvent = aTimelineItemEvent(transactionId = null) |
||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
||||
skipItems(1) |
||||
initialState.eventSink(RetrySendMenuEvents.Remove) |
||||
assertThat(room.cancelSendCount).isEqualTo(0) |
||||
assertThat(room.retrySendMessageCount).isEqualTo(0) |
||||
assertThat(awaitItem().selectedEvent).isNull() |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
fun `present - handle remove failed message with error`() = runTest { |
||||
room.givenRetrySendMessageResult(Result.failure(IllegalStateException("An error"))) |
||||
moleculeFlow(RecompositionMode.Immediate) { |
||||
presenter.present() |
||||
}.test { |
||||
val initialState = awaitItem() |
||||
val selectedEvent = aTimelineItemEvent(transactionId = A_TRANSACTION_ID) |
||||
initialState.eventSink(RetrySendMenuEvents.EventSelected(selectedEvent)) |
||||
skipItems(1) |
||||
initialState.eventSink(RetrySendMenuEvents.Remove) |
||||
assertThat(room.cancelSendCount).isEqualTo(1) |
||||
assertThat(room.retrySendMessageCount).isEqualTo(0) |
||||
assertThat(awaitItem().selectedEvent).isNull() |
||||
} |
||||
} |
||||
} |
@ -1,90 +0,0 @@
@@ -1,90 +0,0 @@
|
||||
/* |
||||
* Copyright (c) 2024 New Vector Ltd |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0 |
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.retrysendmenu |
||||
|
||||
import androidx.activity.ComponentActivity |
||||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule |
||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule |
||||
import androidx.test.ext.junit.runners.AndroidJUnit4 |
||||
import io.element.android.features.messages.impl.R |
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent |
||||
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.pressBackKey |
||||
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 RetrySendMessageMenuTest { |
||||
@get:Rule val rule = createAndroidComposeRule<ComponentActivity>() |
||||
|
||||
@Test |
||||
fun `dismiss the bottom sheet emits the expected event`() { |
||||
val eventsRecorder = EventsRecorder<RetrySendMenuEvents>() |
||||
rule.setRetrySendMessageMenu( |
||||
aRetrySendMenuState( |
||||
event = aTimelineItemEvent(), |
||||
eventSink = eventsRecorder |
||||
), |
||||
) |
||||
rule.pressBackKey() |
||||
// Cannot test this for now. |
||||
// eventsRecorder.assertSingle(RetrySendMenuEvents.Dismiss) |
||||
} |
||||
|
||||
@Config(qualifiers = "h1024dp") |
||||
@Test |
||||
fun `retry to send the event emits the expected event`() { |
||||
val eventsRecorder = EventsRecorder<RetrySendMenuEvents>() |
||||
rule.setRetrySendMessageMenu( |
||||
aRetrySendMenuState( |
||||
event = aTimelineItemEvent(), |
||||
eventSink = eventsRecorder |
||||
), |
||||
) |
||||
rule.clickOn(R.string.screen_room_retry_send_menu_send_again_action) |
||||
eventsRecorder.assertSingle(RetrySendMenuEvents.Retry) |
||||
} |
||||
|
||||
@Config(qualifiers = "h1024dp") |
||||
@Test |
||||
fun `remove the event emits the expected event`() { |
||||
val eventsRecorder = EventsRecorder<RetrySendMenuEvents>() |
||||
rule.setRetrySendMessageMenu( |
||||
aRetrySendMenuState( |
||||
event = aTimelineItemEvent(), |
||||
eventSink = eventsRecorder |
||||
), |
||||
) |
||||
rule.clickOn(CommonStrings.action_remove) |
||||
eventsRecorder.assertSingle(RetrySendMenuEvents.Remove) |
||||
} |
||||
} |
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRetrySendMessageMenu( |
||||
state: RetrySendMenuState, |
||||
) { |
||||
setContent { |
||||
RetrySendMessageMenu( |
||||
state = state, |
||||
) |
||||
} |
||||
} |
Loading…
Reference in new issue