Skip to content

Commit 97b6792

Browse files
committed
Add tests
1 parent df46f60 commit 97b6792

File tree

3 files changed

+181
-6
lines changed

3 files changed

+181
-6
lines changed

src/core/webview/__tests__/ClineProvider.test.ts

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,41 @@ import { setSoundEnabled } from "../../../utils/sound"
99
import { defaultModeSlug } from "../../../shared/modes"
1010
import { experimentDefault } from "../../../shared/experiments"
1111

12-
// Mock custom-instructions module
13-
const mockAddCustomInstructions = jest.fn()
12+
// Mock setup must come before imports
13+
jest.mock("../../prompts/sections/custom-instructions")
1414

15-
jest.mock("../../prompts/sections/custom-instructions", () => ({
16-
addCustomInstructions: mockAddCustomInstructions,
17-
}))
15+
// Mock dependencies
16+
jest.mock("vscode")
17+
jest.mock("delay")
18+
jest.mock(
19+
"@modelcontextprotocol/sdk/types.js",
20+
() => ({
21+
CallToolResultSchema: {},
22+
ListResourcesResultSchema: {},
23+
ListResourceTemplatesResultSchema: {},
24+
ListToolsResultSchema: {},
25+
ReadResourceResultSchema: {},
26+
ErrorCode: {
27+
InvalidRequest: "InvalidRequest",
28+
MethodNotFound: "MethodNotFound",
29+
InternalError: "InternalError",
30+
},
31+
McpError: class McpError extends Error {
32+
code: string
33+
constructor(code: string, message: string) {
34+
super(message)
35+
this.code = code
36+
this.name = "McpError"
37+
}
38+
},
39+
}),
40+
{ virtual: true },
41+
)
42+
43+
// Initialize mocks
44+
const mockAddCustomInstructions = jest.fn().mockResolvedValue("Combined instructions")
45+
;(jest.requireMock("../../prompts/sections/custom-instructions") as any).addCustomInstructions =
46+
mockAddCustomInstructions
1847

1948
// Mock delay module
2049
jest.mock("delay", () => {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { EXPERIMENT_IDS, experimentConfigsMap, experiments as Experiments, ExperimentId } from "../experiments"
2+
3+
describe("experiments", () => {
4+
describe("POWER_STEERING", () => {
5+
it("is configured correctly", () => {
6+
expect(EXPERIMENT_IDS.POWER_STEERING).toBe("powerSteering")
7+
expect(experimentConfigsMap.POWER_STEERING).toMatchObject({
8+
name: 'Use experimental "power steering" mode',
9+
description:
10+
"When enabled, Roo will remind the model about the details of its current mode definition more frequently. This will lead to stronger adherence to role definitions and custom instructions, but will use additional tokens.",
11+
enabled: false,
12+
})
13+
})
14+
})
15+
16+
describe("isEnabled", () => {
17+
it("returns false when experiment is not enabled", () => {
18+
const experiments: Record<ExperimentId, boolean> = {
19+
powerSteering: false,
20+
experimentalDiffStrategy: false,
21+
search_and_replace: false,
22+
insert_content: false,
23+
}
24+
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false)
25+
})
26+
27+
it("returns true when experiment is enabled", () => {
28+
const experiments: Record<ExperimentId, boolean> = {
29+
powerSteering: true,
30+
experimentalDiffStrategy: false,
31+
search_and_replace: false,
32+
insert_content: false,
33+
}
34+
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(true)
35+
})
36+
37+
it("returns false when experiment is not present", () => {
38+
const experiments: Record<ExperimentId, boolean> = {
39+
experimentalDiffStrategy: false,
40+
search_and_replace: false,
41+
insert_content: false,
42+
powerSteering: false,
43+
}
44+
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false)
45+
})
46+
})
47+
})

src/shared/__tests__/modes.test.ts

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
import { isToolAllowedForMode, FileRestrictionError, ModeConfig } from "../modes"
1+
// Mock setup must come before imports
2+
jest.mock("vscode")
3+
const mockAddCustomInstructions = jest.fn().mockResolvedValue("Combined instructions")
4+
jest.mock("../../core/prompts/sections/custom-instructions", () => ({
5+
addCustomInstructions: mockAddCustomInstructions,
6+
}))
7+
8+
import { isToolAllowedForMode, FileRestrictionError, ModeConfig, getFullModeDetails, modes } from "../modes"
9+
import * as vscode from "vscode"
10+
import { addCustomInstructions } from "../../core/prompts/sections/custom-instructions"
211

312
describe("isToolAllowedForMode", () => {
413
const customModes: ModeConfig[] = [
@@ -324,6 +333,96 @@ describe("FileRestrictionError", () => {
324333
expect(error.name).toBe("FileRestrictionError")
325334
})
326335

336+
describe("debug mode", () => {
337+
it("is configured correctly", () => {
338+
const debugMode = modes.find((mode) => mode.slug === "debug")
339+
expect(debugMode).toBeDefined()
340+
expect(debugMode).toMatchObject({
341+
slug: "debug",
342+
name: "Debug",
343+
roleDefinition:
344+
"You are Roo, an expert software debugger specializing in systematic problem diagnosis and resolution.",
345+
groups: ["read", "edit", "browser", "command", "mcp"],
346+
})
347+
expect(debugMode?.customInstructions).toContain("Reflect on 5-7 different possible sources of the problem")
348+
})
349+
})
350+
351+
describe("getFullModeDetails", () => {
352+
beforeEach(() => {
353+
jest.clearAllMocks()
354+
;(addCustomInstructions as jest.Mock).mockResolvedValue("Combined instructions")
355+
})
356+
357+
it("returns base mode when no overrides exist", async () => {
358+
const result = await getFullModeDetails("debug")
359+
expect(result).toMatchObject({
360+
slug: "debug",
361+
name: "Debug",
362+
roleDefinition:
363+
"You are Roo, an expert software debugger specializing in systematic problem diagnosis and resolution.",
364+
})
365+
})
366+
367+
it("applies custom mode overrides", async () => {
368+
const customModes = [
369+
{
370+
slug: "debug",
371+
name: "Custom Debug",
372+
roleDefinition: "Custom debug role",
373+
groups: ["read"],
374+
},
375+
]
376+
377+
const result = await getFullModeDetails("debug", customModes)
378+
expect(result).toMatchObject({
379+
slug: "debug",
380+
name: "Custom Debug",
381+
roleDefinition: "Custom debug role",
382+
groups: ["read"],
383+
})
384+
})
385+
386+
it("applies prompt component overrides", async () => {
387+
const customModePrompts = {
388+
debug: {
389+
roleDefinition: "Overridden role",
390+
customInstructions: "Overridden instructions",
391+
},
392+
}
393+
394+
const result = await getFullModeDetails("debug", undefined, customModePrompts)
395+
expect(result.roleDefinition).toBe("Overridden role")
396+
expect(result.customInstructions).toBe("Overridden instructions")
397+
})
398+
399+
it("combines custom instructions when cwd provided", async () => {
400+
const options = {
401+
cwd: "/test/path",
402+
globalCustomInstructions: "Global instructions",
403+
preferredLanguage: "en",
404+
}
405+
406+
await getFullModeDetails("debug", undefined, undefined, options)
407+
408+
expect(addCustomInstructions).toHaveBeenCalledWith(
409+
expect.any(String),
410+
"Global instructions",
411+
"/test/path",
412+
"debug",
413+
{ preferredLanguage: "en" },
414+
)
415+
})
416+
417+
it("falls back to first mode for non-existent mode", async () => {
418+
const result = await getFullModeDetails("non-existent")
419+
expect(result).toMatchObject({
420+
...modes[0],
421+
customInstructions: "",
422+
})
423+
})
424+
})
425+
327426
it("formats error message with description when provided", () => {
328427
const error = new FileRestrictionError("Markdown Editor", "\\.md$", "Markdown files only", "test.js")
329428
expect(error.message).toBe(

0 commit comments

Comments
 (0)