feat(chat): show read and write file contents in code viewer card (#1238)
This commit is contained in:
11 files changed
+681
-346
No files matched your search
@@ -0,0 +1,95 @@
|
||||
package com.m57.hermescontrol.ui.chat
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import com.m57.hermescontrol.theme.HermesControlTheme
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class FileToolBubbleTest {
|
||||
@get:Rule
|
||||
val composeRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun tappingReadFileBubbleShowsFileViewCardWithSyntaxViewer() {
|
||||
val payload =
|
||||
"""
|
||||
{
|
||||
"args": {"path": "/repo/src/Main.kt", "offset": 1, "limit": 2},
|
||||
"result": {"content": "1|fun main() {\n2| println(\"hi\")\n3|}"}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
showBubble("read_file", payload)
|
||||
|
||||
composeRule.onNodeWithText("Read Main.kt L1-2", substring = true).performClick()
|
||||
composeRule.onNodeWithTag("file_view_card", useUnmergedTree = true).assertExists()
|
||||
composeRule.onNodeWithText("/repo/src/Main.kt", useUnmergedTree = true).assertExists()
|
||||
composeRule.onNodeWithText("3 lines", useUnmergedTree = true).assertExists()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tappingWriteFileBubbleShowsFileViewCardWhenNoDiff() {
|
||||
val payload =
|
||||
"""
|
||||
{
|
||||
"args": {
|
||||
"path": "/repo/src/Config.json",
|
||||
"content": "{\n \"enabled\": true\n}"
|
||||
},
|
||||
"result": {"verified": true, "success": true}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
showBubble("write_file", payload)
|
||||
|
||||
composeRule.onNodeWithText("Config.json", substring = true).performClick()
|
||||
composeRule.onNodeWithTag("file_view_card", useUnmergedTree = true).assertExists()
|
||||
composeRule.onNodeWithText("/repo/src/Config.json", useUnmergedTree = true).assertExists()
|
||||
composeRule.onNodeWithText("3 lines", useUnmergedTree = true).assertExists()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun tappingWriteFileWithDiffShowsDiffViewCard() {
|
||||
val payload =
|
||||
"""
|
||||
{
|
||||
"args": {"path": "/repo/src/Utils.kt"},
|
||||
"result": {
|
||||
"inline_diff": "--- a/Utils.kt\n+++ b/Utils.kt\n@@ -1,1 +1,1 @@\n-old\n+new"
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
showBubble("write_file", payload)
|
||||
|
||||
composeRule.onNodeWithText("Utils.kt", substring = true).performClick()
|
||||
composeRule.onNodeWithTag("diff_view_card", useUnmergedTree = true).assertExists()
|
||||
composeRule.onNodeWithText("Utils.kt", useUnmergedTree = true).assertExists()
|
||||
}
|
||||
|
||||
private fun showBubble(
|
||||
name: String,
|
||||
content: String,
|
||||
) {
|
||||
composeRule.setContent {
|
||||
HermesControlTheme {
|
||||
ToolBubble(
|
||||
ChatMessage(
|
||||
role = MessageRole.TOOL,
|
||||
content = content,
|
||||
toolName = name,
|
||||
toolStatus = ToolStatus.COMPLETED,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.m57.hermescontrol.ui.chat.components
|
||||
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithTag
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
class FileViewCardTest {
|
||||
@get:Rule
|
||||
val composeTestRule = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun shortFile_displaysPathLineCountAndFullContentWithoutExpandButton() {
|
||||
val content = "fun hello() = println(\"world\")\nval x = 42"
|
||||
var copiedText = ""
|
||||
|
||||
composeTestRule.setContent {
|
||||
FileViewCard(
|
||||
content = content,
|
||||
filePath = "src/main/Test.kt",
|
||||
onCopy = { copiedText = it },
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithTag("file_view_card").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText("src/main/Test.kt").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText("2 lines").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText("Show full file (2 lines)").assertDoesNotExist()
|
||||
|
||||
composeTestRule.onNodeWithTag("file_view_card").assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun longFile_showsExpandButtonAndTogglesFullFile() {
|
||||
val lines = (1..25).map { "line $it: println($it)" }
|
||||
val content = lines.joinToString("\n")
|
||||
|
||||
composeTestRule.setContent {
|
||||
FileViewCard(
|
||||
content = content,
|
||||
filePath = "src/Big.kt",
|
||||
)
|
||||
}
|
||||
|
||||
composeTestRule.onNodeWithText("Show full file (25 lines)").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText("Show full file (25 lines)").performClick()
|
||||
composeTestRule.onNodeWithText("Collapse file").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithText("Collapse file").performClick()
|
||||
composeTestRule.onNodeWithText("Show full file (25 lines)").assertIsDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun copyButton_invokesCallbackWithFullContent() {
|
||||
val content = "1|fun main() = Unit"
|
||||
var copied = ""
|
||||
|
||||
composeTestRule.setContent {
|
||||
FileViewCard(
|
||||
content = content,
|
||||
filePath = "src/App.kt",
|
||||
onCopy = { copied = it },
|
||||
)
|
||||
}
|
||||
composeTestRule.onNodeWithText("src/App.kt").assertIsDisplayed()
|
||||
composeTestRule.onNodeWithContentDescription("Copy file content").performClick()
|
||||
assertEquals(content, copied)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user