Skip to content

Commit ceee77b

Browse files
committed
test(dcg): cover settings installation paths
1 parent 984f7c4 commit ceee77b

2 files changed

Lines changed: 81 additions & 0 deletions

File tree

src/core/webview/__tests__/webviewMessageHandler.spec.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ vi.mock("../../../services/command/commands", () => ({
2626
getCommands: vi.fn(),
2727
}))
2828

29+
vi.mock("../../../services/destructive-command-guard", () => ({
30+
ensureDcgInstalled: vi.fn(),
31+
}))
32+
2933
vi.mock("@anthropic-ai/vertex-sdk", () => ({
3034
AnthropicVertex: vi.fn(),
3135
}))
@@ -58,6 +62,7 @@ import type { ClineProvider } from "../ClineProvider"
5862
import { flushModels, getModels } from "../../../api/providers/fetchers/modelCache"
5963
import { getLMStudioModels } from "../../../api/providers/fetchers/lmstudio"
6064
import { getCommands } from "../../../services/command/commands"
65+
import { ensureDcgInstalled } from "../../../services/destructive-command-guard"
6166
import {
6267
handleCreateRule,
6368
handleDeleteRule,
@@ -1098,6 +1103,62 @@ describe("webviewMessageHandler - mcpEnabled", () => {
10981103
})
10991104
})
11001105

1106+
describe("webviewMessageHandler - destructiveCommandGuardEnabled", () => {
1107+
beforeEach(() => {
1108+
vi.clearAllMocks()
1109+
vi.mocked(ensureDcgInstalled).mockResolvedValue("/mock/global/storage/dcg")
1110+
})
1111+
1112+
it("installs and persists destructive command guard when enabled", async () => {
1113+
await webviewMessageHandler(mockClineProvider, {
1114+
type: "updateSettings",
1115+
updatedSettings: { destructiveCommandGuardEnabled: true },
1116+
})
1117+
1118+
expect(ensureDcgInstalled).toHaveBeenCalledWith("/mock/global/storage")
1119+
expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("destructiveCommandGuardEnabled", true)
1120+
expect(vscode.window.showErrorMessage).not.toHaveBeenCalled()
1121+
})
1122+
1123+
it("disables the setting and reports an installation failure", async () => {
1124+
vi.mocked(ensureDcgInstalled).mockRejectedValue(new Error("checksum mismatch"))
1125+
1126+
await webviewMessageHandler(mockClineProvider, {
1127+
type: "updateSettings",
1128+
updatedSettings: { destructiveCommandGuardEnabled: true },
1129+
})
1130+
1131+
expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("destructiveCommandGuardEnabled", false)
1132+
expect(vscode.window.showErrorMessage).toHaveBeenCalledWith(
1133+
"common:errors.destructive_command_guard_enable_failed",
1134+
)
1135+
})
1136+
1137+
it("reports non-Error installation failures", async () => {
1138+
vi.mocked(ensureDcgInstalled).mockRejectedValue("download unavailable")
1139+
1140+
await webviewMessageHandler(mockClineProvider, {
1141+
type: "updateSettings",
1142+
updatedSettings: { destructiveCommandGuardEnabled: true },
1143+
})
1144+
1145+
expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("destructiveCommandGuardEnabled", false)
1146+
expect(t).toHaveBeenCalledWith("common:errors.destructive_command_guard_enable_failed", {
1147+
error: "download unavailable",
1148+
})
1149+
})
1150+
1151+
it("persists disabled state without trying to install", async () => {
1152+
await webviewMessageHandler(mockClineProvider, {
1153+
type: "updateSettings",
1154+
updatedSettings: { destructiveCommandGuardEnabled: false },
1155+
})
1156+
1157+
expect(ensureDcgInstalled).not.toHaveBeenCalled()
1158+
expect(mockClineProvider.contextProxy.setValue).toHaveBeenCalledWith("destructiveCommandGuardEnabled", false)
1159+
})
1160+
})
1161+
11011162
describe("webviewMessageHandler - terminalProfile", () => {
11021163
beforeEach(() => {
11031164
vi.clearAllMocks()

webview-ui/src/components/settings/__tests__/AutoApproveSettings.spec.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ describe("AutoApproveSettings - Save/Discard contract", () => {
6767
expectNoImmediateUpdateSettings()
6868
})
6969

70+
it("buffers an allowed command submitted with Enter", () => {
71+
const { setCachedStateField } = renderSettings()
72+
73+
const input = screen.getByTestId("command-input")
74+
fireEvent.change(input, { target: { value: "pnpm test" } })
75+
fireEvent.keyDown(input, { key: "Enter" })
76+
77+
expect(setCachedStateField).toHaveBeenCalledWith("allowedCommands", ["pnpm test"])
78+
})
79+
7080
// Case 2: allowedCommands remove
7181
it("buffers a removed allowed command without persisting before Save", () => {
7282
const { setCachedStateField } = renderSettings({ allowedCommands: ["npm test"] })
@@ -88,6 +98,16 @@ describe("AutoApproveSettings - Save/Discard contract", () => {
8898
expectNoImmediateUpdateSettings()
8999
})
90100

101+
it("buffers a denied command submitted with Enter", () => {
102+
const { setCachedStateField } = renderSettings()
103+
104+
const input = screen.getByTestId("denied-command-input")
105+
fireEvent.change(input, { target: { value: "sudo rm" } })
106+
fireEvent.keyDown(input, { key: "Enter" })
107+
108+
expect(setCachedStateField).toHaveBeenCalledWith("deniedCommands", ["sudo rm"])
109+
})
110+
91111
// Case 3b: deniedCommands remove
92112
it("buffers a removed denied command without persisting before Save", () => {
93113
const { setCachedStateField } = renderSettings({ deniedCommands: ["rm -rf"] })

0 commit comments

Comments
 (0)