revert(chat): remove busy-send panel and composer queue button (#1308)
This commit is contained in:
9 files changed
+2
-520
No files matched your search
@@ -10,13 +10,11 @@ import androidx.core.content.ContextCompat
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import com.m57.hermescontrol.data.model.Attachment
|
||||
import com.m57.hermescontrol.data.model.BusySendMode
|
||||
import com.m57.hermescontrol.data.ws.ConnectionStatus
|
||||
import com.m57.hermescontrol.ui.common.ActionProgressController
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -128,37 +126,4 @@ class ChatScreenTest {
|
||||
composeTestRule.onNodeWithTag("chat_input").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag("send_button").assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun chatScreen_primarySendUsesSavedBusyDefault() {
|
||||
val uiState =
|
||||
ChatUiState(
|
||||
connectionStatus = ConnectionStatus.CONNECTED,
|
||||
isSessionReady = true,
|
||||
busySendMode = BusySendMode.QUEUE,
|
||||
)
|
||||
val mockViewModel = mockk<ChatViewModel>(relaxed = true)
|
||||
every { mockViewModel.uiState } returns MutableStateFlow(uiState).asStateFlow()
|
||||
every { mockViewModel.streamingState } returns MutableStateFlow(StreamingState()).asStateFlow()
|
||||
every { mockViewModel.timelineState } returns MutableStateFlow(ChatTimelineState()).asStateFlow()
|
||||
every { mockViewModel.connectionOperationState } returns
|
||||
MutableStateFlow(ConnectionOperationUiState()).asStateFlow()
|
||||
every { mockViewModel.actionProgress } returns
|
||||
ActionProgressController(scope = CoroutineScope(Dispatchers.Main))
|
||||
every { mockViewModel.sendMessage(any(), any()) } returns true
|
||||
|
||||
composeTestRule.setContent {
|
||||
ChatScreen(
|
||||
onOpenDrawer = {},
|
||||
sessionId = null,
|
||||
viewModel = mockViewModel,
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag("chat_input").performTextInput("Use my saved default")
|
||||
composeTestRule.onNodeWithTag("send_button").performClick()
|
||||
|
||||
verify(exactly = 1) { mockViewModel.sendMessage("Use my saved default", null) }
|
||||
verify(exactly = 0) { mockViewModel.sendMessage("Use my saved default", BusySendMode.CORRECT) }
|
||||
}
|
||||
}
|
||||
-153
@@ -32,7 +32,6 @@ import androidx.test.filters.MediumTest
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import com.m57.hermescontrol.R
|
||||
import com.m57.hermescontrol.data.model.Attachment
|
||||
import com.m57.hermescontrol.data.model.BusySendMode
|
||||
import com.m57.hermescontrol.data.ws.CommandCatalog
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
@@ -58,158 +57,6 @@ class ComposerInteractionTest {
|
||||
private var photosTaps = 0
|
||||
private var fileTaps = 0
|
||||
|
||||
private fun setContextualComposer(
|
||||
text: String,
|
||||
isMainTurnBusy: Boolean,
|
||||
attachments: List<Attachment> = emptyList(),
|
||||
onSend: () -> Unit = {},
|
||||
onBusySend: (BusySendMode) -> Unit = {},
|
||||
isConnected: Boolean = true,
|
||||
pendingReasoningLevel: String? = null,
|
||||
) {
|
||||
composeTestRule.setContent {
|
||||
ChatInputBar(
|
||||
inputFieldValue = TextFieldValue(text),
|
||||
onInputChange = {},
|
||||
onSend = onSend,
|
||||
onBusySend = onBusySend,
|
||||
onMicTap = {},
|
||||
isListening = false,
|
||||
isAgentTyping = isMainTurnBusy,
|
||||
isMainTurnBusy = isMainTurnBusy,
|
||||
isConnected = isConnected,
|
||||
commandCatalog = CommandCatalog(),
|
||||
isSessionReady = true,
|
||||
pendingAttachments = attachments,
|
||||
pendingReasoningLevel = pendingReasoningLevel,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun idleDraft_showsRegularSendWithoutBusyActions() {
|
||||
setContextualComposer(text = "hello", isMainTurnBusy = false)
|
||||
|
||||
composeTestRule.onNodeWithTag("send_button").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag("queue_button").assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun busyBlankDraft_hidesBusyActions() {
|
||||
setContextualComposer(text = "", isMainTurnBusy = true)
|
||||
|
||||
composeTestRule.onNodeWithTag("send_button").assertDoesNotExist()
|
||||
composeTestRule.onNodeWithTag("queue_button").assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun busyTextDraft_showsSendAndQueueAndRoutesCallbacks() {
|
||||
var regularSends = 0
|
||||
val selected = mutableListOf<BusySendMode>()
|
||||
setContextualComposer(
|
||||
text = "change course",
|
||||
isMainTurnBusy = true,
|
||||
onSend = { regularSends++ },
|
||||
onBusySend = selected::add,
|
||||
)
|
||||
|
||||
composeTestRule.onNodeWithTag("send_button").assertIsDisplayed().performClick()
|
||||
composeTestRule.onNodeWithTag("queue_button").assertIsDisplayed().performClick()
|
||||
|
||||
composeTestRule.runOnIdle {
|
||||
assertEquals(1, regularSends)
|
||||
assertEquals(listOf(BusySendMode.QUEUE), selected)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun busyAttachmentOnly_showsSendAndQueue() {
|
||||
val attachment = Attachment("content://document/1", "notes.txt", "text/plain")
|
||||
setContextualComposer(text = "", isMainTurnBusy = true, attachments = listOf(attachment))
|
||||
|
||||
composeTestRule.onNodeWithTag("send_button").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag("queue_button").assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun busyDisconnectedDraft_disablesSendAndQueue() {
|
||||
setContextualComposer(text = "hello", isMainTurnBusy = true, isConnected = false)
|
||||
composeTestRule.onNodeWithTag("send_button").assertIsNotEnabled()
|
||||
composeTestRule.onNodeWithTag("queue_button").assertIsNotEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun busyPendingReasoning_disablesSendAndQueue() {
|
||||
setContextualComposer(text = "hello", isMainTurnBusy = true, pendingReasoningLevel = "high")
|
||||
composeTestRule.onNodeWithTag("send_button").assertIsNotEnabled()
|
||||
composeTestRule.onNodeWithTag("queue_button").assertIsNotEnabled()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun busySlashDraft_usesRegularSendWithoutBusyActions() {
|
||||
var regularSends = 0
|
||||
setContextualComposer(
|
||||
text = "/stop",
|
||||
isMainTurnBusy = true,
|
||||
onSend = { regularSends++ },
|
||||
)
|
||||
|
||||
composeTestRule.onNodeWithTag("queue_button").assertDoesNotExist()
|
||||
composeTestRule.onNodeWithTag("send_button").performClick()
|
||||
composeTestRule.runOnIdle { assertEquals(1, regularSends) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun busyBecomesIdle_hidesQueueAndPreservesTypedDraft() {
|
||||
val busy = mutableStateOf(true)
|
||||
composeTestRule.setContent {
|
||||
var input by remember { mutableStateOf(TextFieldValue("draft in progress")) }
|
||||
ChatInputBar(
|
||||
inputFieldValue = input,
|
||||
onInputChange = { input = it },
|
||||
onSend = {},
|
||||
onBusySend = {},
|
||||
onMicTap = {},
|
||||
isListening = false,
|
||||
isAgentTyping = busy.value,
|
||||
isMainTurnBusy = busy.value,
|
||||
isConnected = true,
|
||||
commandCatalog = CommandCatalog(),
|
||||
isSessionReady = true,
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag("queue_button").assertIsDisplayed()
|
||||
composeTestRule.runOnUiThread { busy.value = false }
|
||||
composeTestRule.onNodeWithTag("queue_button").assertDoesNotExist()
|
||||
composeTestRule.onNodeWithTag("chat_input").assertTextEquals("draft in progress")
|
||||
composeTestRule.onNodeWithTag("send_button").assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun busyDraft_narrowWidthKeepsSendAndQueueAccessible() {
|
||||
composeTestRule.setContent {
|
||||
Box(Modifier.width(220.dp)) {
|
||||
ChatInputBar(
|
||||
inputFieldValue = TextFieldValue("change course"),
|
||||
onInputChange = {},
|
||||
onSend = {},
|
||||
onBusySend = {},
|
||||
onMicTap = {},
|
||||
isListening = false,
|
||||
isAgentTyping = true,
|
||||
isMainTurnBusy = true,
|
||||
isConnected = true,
|
||||
commandCatalog = CommandCatalog(),
|
||||
isSessionReady = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag("queue_button").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithTag("send_button").assertIsDisplayed()
|
||||
}
|
||||
|
||||
/** Renders the real input bar with live text and a mic that toggles like ChatMediaLaunchers. */
|
||||
private fun setComposer(
|
||||
reasoningLevel: String? = "medium",
|
||||
|
||||
-98
@@ -1,98 +0,0 @@
|
||||
package com.m57.hermescontrol.ui.chat.components
|
||||
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.m57.hermescontrol.R
|
||||
import com.m57.hermescontrol.data.model.BusySendMode
|
||||
import com.m57.hermescontrol.ui.chat.PendingSend
|
||||
import com.m57.hermescontrol.ui.chat.PendingSendState
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class PendingSendPanelTest {
|
||||
@get:Rule
|
||||
val compose = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
private fun row(state: PendingSendState) =
|
||||
PendingSend("receipt", "scope", "session", "My message", mode = BusySendMode.CORRECT, state = state)
|
||||
|
||||
@Test
|
||||
fun ordinarySendNeverShowsDeliveryPanel() {
|
||||
val state = mutableStateOf(PendingSendState.SENDING)
|
||||
compose.setContent { PendingSendPanel(listOf(row(state.value)), mainTurnBusy = false, onSendNow = {}) }
|
||||
compose.onNodeWithText("My message").assertDoesNotExist()
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_pending_sends)).assertDoesNotExist()
|
||||
compose.runOnIdle { state.value = PendingSendState.ACCEPTED }
|
||||
compose.onNodeWithText("My message").assertDoesNotExist()
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_pending_accepted)).assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun queueDisappearsWhenDispatchedWithoutAwaitingLabel() {
|
||||
val state = mutableStateOf(PendingSendState.QUEUED)
|
||||
compose.setContent { PendingSendPanel(listOf(row(state.value)), mainTurnBusy = false, onSendNow = {}) }
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_pending_queued)).assertIsDisplayed()
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_pending_send_now_warning)).assertDoesNotExist()
|
||||
compose.runOnIdle { state.value = PendingSendState.SENDING }
|
||||
compose.onNodeWithText("My message").assertDoesNotExist()
|
||||
compose.runOnIdle { state.value = PendingSendState.ACCEPTED }
|
||||
compose.onNodeWithText("My message").assertDoesNotExist()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun failedAndUncertainDeliveryRemainRecoverable() {
|
||||
val state = mutableStateOf(PendingSendState.REJECTED)
|
||||
var retried: String? = null
|
||||
compose.setContent {
|
||||
PendingSendPanel(
|
||||
listOf(row(state.value)),
|
||||
mainTurnBusy = false,
|
||||
onSendNow = { retried = it },
|
||||
)
|
||||
}
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_pending_rejected)).assertIsDisplayed()
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_pending_send_now)).performClick()
|
||||
compose.runOnIdle {
|
||||
assertEquals("receipt", retried)
|
||||
state.value = PendingSendState.UNKNOWN
|
||||
}
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_pending_unknown)).assertIsDisplayed()
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_pending_send_now_warning)).assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun busyPanelWarnsAndLabelsEveryRecoverableActionAsStopAndSend() {
|
||||
val state = mutableStateOf(PendingSendState.QUEUED)
|
||||
compose.setContent {
|
||||
PendingSendPanel(
|
||||
sends = listOf(row(state.value)),
|
||||
mainTurnBusy = true,
|
||||
onSendNow = {},
|
||||
)
|
||||
}
|
||||
|
||||
listOf(
|
||||
PendingSendState.QUEUED,
|
||||
PendingSendState.PARKED,
|
||||
PendingSendState.REJECTED,
|
||||
PendingSendState.UNKNOWN,
|
||||
).forEach { pendingState ->
|
||||
compose.runOnIdle { state.value = pendingState }
|
||||
compose
|
||||
.onNodeWithText(
|
||||
compose.activity.getString(R.string.chat_pending_send_now_warning),
|
||||
).assertIsDisplayed()
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_busy_stop_and_send)).assertIsDisplayed()
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_pending_send_now)).assertDoesNotExist()
|
||||
compose.onNodeWithText(compose.activity.getString(R.string.chat_pending_send_again)).assertDoesNotExist()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user