|
|
@@ -1,9 +1,14 @@
|
|
|
+// npx jest src/components/chat/__tests__/ChatView.test.tsx
|
|
|
+
|
|
|
import React from "react"
|
|
|
import { render, waitFor, act } from "@testing-library/react"
|
|
|
-import ChatView from "../ChatView"
|
|
|
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
|
|
|
+
|
|
|
import { ExtensionStateContextProvider } from "@src/context/ExtensionStateContext"
|
|
|
import { vscode } from "@src/utils/vscode"
|
|
|
|
|
|
+import ChatView, { ChatViewProps } from "../ChatView"
|
|
|
+
|
|
|
// Define minimal types needed for testing
|
|
|
interface ClineMessage {
|
|
|
type: "say" | "ask"
|
|
|
@@ -85,13 +90,6 @@ jest.mock("../ChatTextArea", () => {
|
|
|
}
|
|
|
})
|
|
|
|
|
|
-jest.mock("../TaskHeader", () => ({
|
|
|
- __esModule: true,
|
|
|
- default: function MockTaskHeader({ task }: { task: ClineMessage }) {
|
|
|
- return <div data-testid="task-header">{JSON.stringify(task)}</div>
|
|
|
- },
|
|
|
-}))
|
|
|
-
|
|
|
// Mock VSCode components
|
|
|
jest.mock("@vscode/webview-ui-toolkit/react", () => ({
|
|
|
VSCodeButton: function MockVSCodeButton({
|
|
|
@@ -151,22 +149,30 @@ const mockPostMessage = (state: Partial<ExtensionState>) => {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
+const defaultProps: ChatViewProps = {
|
|
|
+ isHidden: false,
|
|
|
+ showAnnouncement: false,
|
|
|
+ hideAnnouncement: () => {},
|
|
|
+ showHistoryView: () => {},
|
|
|
+}
|
|
|
+
|
|
|
+const queryClient = new QueryClient()
|
|
|
+
|
|
|
+const renderChatView = (props: Partial<ChatViewProps> = {}) => {
|
|
|
+ return render(
|
|
|
+ <ExtensionStateContextProvider>
|
|
|
+ <QueryClientProvider client={queryClient}>
|
|
|
+ <ChatView {...defaultProps} {...props} />
|
|
|
+ </QueryClientProvider>
|
|
|
+ </ExtensionStateContextProvider>,
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
describe("ChatView - Auto Approval Tests", () => {
|
|
|
- beforeEach(() => {
|
|
|
- jest.clearAllMocks()
|
|
|
- })
|
|
|
+ beforeEach(() => jest.clearAllMocks())
|
|
|
|
|
|
it("does not auto-approve any actions when autoApprovalEnabled is false", () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task
|
|
|
mockPostMessage({
|
|
|
@@ -240,16 +246,7 @@ describe("ChatView - Auto Approval Tests", () => {
|
|
|
})
|
|
|
|
|
|
it("auto-approves browser actions when alwaysAllowBrowser is enabled", async () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task
|
|
|
mockPostMessage({
|
|
|
@@ -296,16 +293,7 @@ describe("ChatView - Auto Approval Tests", () => {
|
|
|
})
|
|
|
|
|
|
it("auto-approves read-only tools when alwaysAllowReadOnly is enabled", async () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task
|
|
|
mockPostMessage({
|
|
|
@@ -353,16 +341,7 @@ describe("ChatView - Auto Approval Tests", () => {
|
|
|
|
|
|
describe("Write Tool Auto-Approval Tests", () => {
|
|
|
it("auto-approves write tools when alwaysAllowWrite is enabled and message is a tool request", async () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task
|
|
|
mockPostMessage({
|
|
|
@@ -411,16 +390,7 @@ describe("ChatView - Auto Approval Tests", () => {
|
|
|
})
|
|
|
|
|
|
it("does not auto-approve write operations when alwaysAllowWrite is enabled but message is not a tool request", () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task
|
|
|
mockPostMessage({
|
|
|
@@ -466,16 +436,7 @@ describe("ChatView - Auto Approval Tests", () => {
|
|
|
})
|
|
|
|
|
|
it("auto-approves allowed commands when alwaysAllowExecute is enabled", async () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task
|
|
|
mockPostMessage({
|
|
|
@@ -524,16 +485,7 @@ describe("ChatView - Auto Approval Tests", () => {
|
|
|
})
|
|
|
|
|
|
it("does not auto-approve disallowed commands even when alwaysAllowExecute is enabled", () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task
|
|
|
mockPostMessage({
|
|
|
@@ -581,16 +533,7 @@ describe("ChatView - Auto Approval Tests", () => {
|
|
|
|
|
|
describe("Command Chaining Tests", () => {
|
|
|
it("auto-approves chained commands when all parts are allowed", async () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// Test various allowed command chaining scenarios
|
|
|
const allowedChainedCommands = [
|
|
|
@@ -656,16 +599,7 @@ describe("ChatView - Auto Approval Tests", () => {
|
|
|
})
|
|
|
|
|
|
it("does not auto-approve chained commands when any part is disallowed", () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// Test various command chaining scenarios with disallowed parts
|
|
|
const disallowedChainedCommands = [
|
|
|
@@ -728,16 +662,7 @@ describe("ChatView - Auto Approval Tests", () => {
|
|
|
})
|
|
|
|
|
|
it("handles complex PowerShell command chains correctly", async () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// Test PowerShell specific command chains
|
|
|
const powershellCommands = {
|
|
|
@@ -849,21 +774,10 @@ describe("ChatView - Auto Approval Tests", () => {
|
|
|
})
|
|
|
|
|
|
describe("ChatView - Sound Playing Tests", () => {
|
|
|
- beforeEach(() => {
|
|
|
- jest.clearAllMocks()
|
|
|
- })
|
|
|
+ beforeEach(() => jest.clearAllMocks())
|
|
|
|
|
|
it("does not play sound for auto-approved browser actions", async () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task and streaming
|
|
|
mockPostMessage({
|
|
|
@@ -915,16 +829,7 @@ describe("ChatView - Sound Playing Tests", () => {
|
|
|
})
|
|
|
|
|
|
it("plays notification sound for non-auto-approved browser actions", async () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task and streaming
|
|
|
mockPostMessage({
|
|
|
@@ -978,16 +883,7 @@ describe("ChatView - Sound Playing Tests", () => {
|
|
|
})
|
|
|
|
|
|
it("plays celebration sound for completion results", async () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task and streaming
|
|
|
mockPostMessage({
|
|
|
@@ -1037,16 +933,7 @@ describe("ChatView - Sound Playing Tests", () => {
|
|
|
})
|
|
|
|
|
|
it("plays progress_loop sound for api failures", async () => {
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task and streaming
|
|
|
mockPostMessage({
|
|
|
@@ -1097,9 +984,7 @@ describe("ChatView - Sound Playing Tests", () => {
|
|
|
})
|
|
|
|
|
|
describe("ChatView - Focus Grabbing Tests", () => {
|
|
|
- beforeEach(() => {
|
|
|
- jest.clearAllMocks()
|
|
|
- })
|
|
|
+ beforeEach(() => jest.clearAllMocks())
|
|
|
|
|
|
it("does not grab focus when follow-up question presented", async () => {
|
|
|
const sleep = async (timeout: number) => {
|
|
|
@@ -1108,16 +993,7 @@ describe("ChatView - Focus Grabbing Tests", () => {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
- render(
|
|
|
- <ExtensionStateContextProvider>
|
|
|
- <ChatView
|
|
|
- isHidden={false}
|
|
|
- showAnnouncement={false}
|
|
|
- hideAnnouncement={() => {}}
|
|
|
- showHistoryView={() => {}}
|
|
|
- />
|
|
|
- </ExtensionStateContextProvider>,
|
|
|
- )
|
|
|
+ renderChatView()
|
|
|
|
|
|
// First hydrate state with initial task and streaming
|
|
|
mockPostMessage({
|