Skip to content

Commit b13ed53

Browse files
authored
Merge branch 'main' into mode
2 parents c3d43ab + d2e5019 commit b13ed53

File tree

73 files changed

+322
-195
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+322
-195
lines changed

jest.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ module.exports = {
3636
"^default-shell$": "<rootDir>/src/__mocks__/default-shell.js",
3737
"^os-name$": "<rootDir>/src/__mocks__/os-name.js",
3838
"^strip-bom$": "<rootDir>/src/__mocks__/strip-bom.js",
39+
"^@roo/(.*)$": "<rootDir>/src/$1",
40+
"^@src/(.*)$": "<rootDir>/webview-ui/src/$1",
3941
},
4042
transformIgnorePatterns: [
4143
"node_modules/(?!(@modelcontextprotocol|delay|p-wait-for|serialize-error|strip-ansi|default-shell|os-name|strip-bom)/)",

src/shared/__tests__/support-prompts.test.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,123 @@ describe("Code Action Prompts", () => {
8686
})
8787
})
8888

89+
describe("ADD_TO_CONTEXT action", () => {
90+
it("should format ADD_TO_CONTEXT prompt correctly with all parameters", () => {
91+
const prompt = supportPrompt.create("ADD_TO_CONTEXT", {
92+
name: "Roo",
93+
place: "Workspace",
94+
filePath: testFilePath,
95+
selectedText: testCode,
96+
startLine: "1",
97+
endLine: "1",
98+
diagnostics: [],
99+
})
100+
const expected = `${testFilePath}:1-1\n\`\`\`\n${testCode}\n\`\`\``
101+
expect(prompt).toBe(expected)
102+
})
103+
104+
it("should format ADD_TO_CONTEXT prompt with diagnostics", () => {
105+
const diagnostics = [{ message: "Error 1" }, { source: "Linter", message: "Warning 2" }]
106+
const prompt = supportPrompt.create("ADD_TO_CONTEXT", {
107+
filePath: testFilePath,
108+
selectedText: testCode,
109+
startLine: "10",
110+
endLine: "20",
111+
diagnostics,
112+
})
113+
const expected = `${testFilePath}:10-20\n\`\`\`\n${testCode}\n\`\`\``
114+
expect(prompt).toBe(expected)
115+
})
116+
117+
it("should not replace placeholders within parameter values", () => {
118+
const prompt = supportPrompt.create("ADD_TO_CONTEXT", {
119+
value1: "This is ${value2}",
120+
value2: "Actual Value 2",
121+
filePath: testFilePath,
122+
selectedText: testCode,
123+
startLine: "5",
124+
endLine: "15",
125+
})
126+
const expected = `${testFilePath}:5-15\n\`\`\`\n${testCode}\n\`\`\``
127+
expect(prompt).toBe(expected)
128+
})
129+
130+
it("should replace remaining placeholders (not in params) with empty strings", () => {
131+
const prompt = supportPrompt.create("ADD_TO_CONTEXT", {
132+
name: "Roo",
133+
filePath: testFilePath,
134+
selectedText: testCode,
135+
startLine: "1",
136+
endLine: "1",
137+
}) // 'status' is missing
138+
const expected = `${testFilePath}:1-1\n\`\`\`\n${testCode}\n\`\`\``
139+
expect(prompt).toBe(expected)
140+
})
141+
142+
it("should handle placeholders in values that are not in the template", () => {
143+
const prompt = supportPrompt.create("ADD_TO_CONTEXT", {
144+
data: "Some data with ${extraInfo}",
145+
filePath: testFilePath,
146+
selectedText: testCode,
147+
startLine: "1",
148+
endLine: "1",
149+
})
150+
const expected = `${testFilePath}:1-1\n\`\`\`\n${testCode}\n\`\`\``
151+
expect(prompt).toBe(expected)
152+
})
153+
154+
it("should handle minimal params object", () => {
155+
const prompt = supportPrompt.create("ADD_TO_CONTEXT", {
156+
filePath: testFilePath,
157+
selectedText: testCode,
158+
startLine: "1",
159+
endLine: "1",
160+
})
161+
const expected = `${testFilePath}:1-1\n\`\`\`\n${testCode}\n\`\`\``
162+
expect(prompt).toBe(expected)
163+
})
164+
165+
it("should handle params with non-string values", () => {
166+
const prompt = supportPrompt.create("ADD_TO_CONTEXT", {
167+
count: "5",
168+
isActive: "true",
169+
filePath: testFilePath,
170+
selectedText: testCode,
171+
startLine: "1",
172+
endLine: "1",
173+
}) // Convert to strings
174+
const expected = `${testFilePath}:1-1\n\`\`\`\n${testCode}\n\`\`\``
175+
expect(prompt).toBe(expected)
176+
})
177+
178+
it("should handle keys with special regex characters", () => {
179+
const prompt = supportPrompt.create("ADD_TO_CONTEXT", {
180+
"key.with.dots": "Dotty",
181+
value: "Simple",
182+
filePath: testFilePath,
183+
selectedText: testCode,
184+
startLine: "1",
185+
endLine: "1",
186+
})
187+
const expected = `${testFilePath}:1-1\n\`\`\`\n${testCode}\n\`\`\``
188+
expect(prompt).toBe(expected)
189+
})
190+
191+
it("should handle bash script selection", () => {
192+
const bashText =
193+
'if [ "${#usecase_deployments[@]}" -gt 0 ] && [ ${{ parameters.single_deployment_per_environment }} = true ]; then'
194+
const prompt = supportPrompt.create("ADD_TO_CONTEXT", {
195+
selectedText: bashText,
196+
filePath: testFilePath,
197+
startLine: "1",
198+
endLine: "1",
199+
diagnostics: [],
200+
})
201+
const expected = `${testFilePath}:1-1\n\`\`\`\n${bashText}\n\`\`\``
202+
expect(prompt).toBe(expected)
203+
})
204+
})
205+
89206
describe("get template", () => {
90207
it("should return default template when no custom prompts provided", () => {
91208
const template = supportPrompt.get(undefined, "EXPLAIN")

src/shared/support-prompt.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,23 @@ const generateDiagnosticText = (diagnostics?: any[]) => {
99
}
1010

1111
export const createPrompt = (template: string, params: PromptParams): string => {
12-
let result = template
13-
for (const [key, value] of Object.entries(params)) {
14-
if (key === "diagnostics") {
15-
result = result.replaceAll("${diagnosticText}", generateDiagnosticText(value as any[]))
12+
return template.replace(/\${(.*?)}/g, (_, key) => {
13+
if (key === "diagnosticText") {
14+
return generateDiagnosticText(params["diagnostics"] as any[])
15+
} else if (params.hasOwnProperty(key)) {
16+
// Ensure the value is treated as a string for replacement
17+
const value = params[key]
18+
if (typeof value === "string") {
19+
return value
20+
} else {
21+
// Convert non-string values to string for replacement
22+
return String(value)
23+
}
1624
} else {
17-
result = result.replaceAll(`\${${key}}`, value as string)
25+
// If the placeholder key is not in params, replace with empty string
26+
return ""
1827
}
19-
}
20-
21-
// Replace any remaining placeholders with empty strings
22-
result = result.replaceAll(/\${[^}]*}/g, "")
23-
24-
return result
28+
})
2529
}
2630

2731
interface SupportPromptConfig {

webview-ui/jest.config.cjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ module.exports = {
1212
"^vscrui$": "<rootDir>/src/__mocks__/vscrui.ts",
1313
"^@vscode/webview-ui-toolkit/react$": "<rootDir>/src/__mocks__/@vscode/webview-ui-toolkit/react.ts",
1414
"^@/(.*)$": "<rootDir>/src/$1",
15+
'^@roo/(.*)$': '<rootDir>/../src/$1',
16+
'^@src/(.*)$': '<rootDir>/src/$1',
1517
"^src/i18n/setup$": "<rootDir>/src/__mocks__/i18n/setup.ts",
1618
"^\\.\\./setup$": "<rootDir>/src/__mocks__/i18n/setup.ts",
1719
"^\\./setup$": "<rootDir>/src/__mocks__/i18n/setup.ts",

webview-ui/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useCallback, useEffect, useRef, useState } from "react"
22
import { useEvent } from "react-use"
33
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
44

5-
import { ExtensionMessage } from "../../src/shared/ExtensionMessage"
5+
import { ExtensionMessage } from "@roo/shared/ExtensionMessage"
66
import TranslationProvider from "./i18n/TranslationContext"
77

88
import { vscode } from "./utils/vscode"

webview-ui/src/__tests__/App.test.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import "@testing-library/jest-dom"
66

77
import AppWithProviders from "../App"
88

9-
jest.mock("../utils/vscode", () => ({
9+
jest.mock("@src/utils/vscode", () => ({
1010
vscode: {
1111
postMessage: jest.fn(),
1212
},
1313
}))
1414

15-
jest.mock("../components/chat/ChatView", () => ({
15+
jest.mock("@src/components/chat/ChatView", () => ({
1616
__esModule: true,
1717
default: function ChatView({ isHidden }: { isHidden: boolean }) {
1818
return (
@@ -23,7 +23,7 @@ jest.mock("../components/chat/ChatView", () => ({
2323
},
2424
}))
2525

26-
jest.mock("../components/settings/SettingsView", () => ({
26+
jest.mock("@src/components/settings/SettingsView", () => ({
2727
__esModule: true,
2828
default: function SettingsView({ onDone }: { onDone: () => void }) {
2929
return (
@@ -34,7 +34,7 @@ jest.mock("../components/settings/SettingsView", () => ({
3434
},
3535
}))
3636

37-
jest.mock("../components/history/HistoryView", () => ({
37+
jest.mock("@src/components/history/HistoryView", () => ({
3838
__esModule: true,
3939
default: function HistoryView({ onDone }: { onDone: () => void }) {
4040
return (
@@ -45,7 +45,7 @@ jest.mock("../components/history/HistoryView", () => ({
4545
},
4646
}))
4747

48-
jest.mock("../components/mcp/McpView", () => ({
48+
jest.mock("@src/components/mcp/McpView", () => ({
4949
__esModule: true,
5050
default: function McpView({ onDone }: { onDone: () => void }) {
5151
return (
@@ -56,7 +56,7 @@ jest.mock("../components/mcp/McpView", () => ({
5656
},
5757
}))
5858

59-
jest.mock("../components/prompts/PromptsView", () => ({
59+
jest.mock("@src/components/prompts/PromptsView", () => ({
6060
__esModule: true,
6161
default: function PromptsView({ onDone }: { onDone: () => void }) {
6262
return (
@@ -67,7 +67,7 @@ jest.mock("../components/prompts/PromptsView", () => ({
6767
},
6868
}))
6969

70-
jest.mock("../context/ExtensionStateContext", () => ({
70+
jest.mock("@src/context/ExtensionStateContext", () => ({
7171
useExtensionState: () => ({
7272
didHydrateState: true,
7373
showWelcome: false,

webview-ui/src/__tests__/ContextWindowProgress.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { render, screen } from "@testing-library/react"
44
import "@testing-library/jest-dom"
5-
import TaskHeader from "../components/chat/TaskHeader"
5+
import TaskHeader from "@src/components/chat/TaskHeader"
66

77
// Mock formatLargeNumber function
88
jest.mock("@/utils/format", () => ({
@@ -15,7 +15,7 @@ jest.mock("@vscode/webview-ui-toolkit/react", () => ({
1515
}))
1616

1717
// Mock ExtensionStateContext since we use useExtensionState
18-
jest.mock("../context/ExtensionStateContext", () => ({
18+
jest.mock("@src/context/ExtensionStateContext", () => ({
1919
useExtensionState: jest.fn(() => ({
2020
apiConfiguration: {
2121
apiProvider: "openai",
@@ -30,8 +30,8 @@ jest.mock("../context/ExtensionStateContext", () => ({
3030
}))
3131

3232
// Mock highlighting function to avoid JSX parsing issues in tests
33-
jest.mock("../components/chat/TaskHeader", () => {
34-
const originalModule = jest.requireActual("../components/chat/TaskHeader")
33+
jest.mock("@src/components/chat/TaskHeader", () => {
34+
const originalModule = jest.requireActual("@src/components/chat/TaskHeader")
3535
return {
3636
__esModule: true,
3737
...originalModule,

webview-ui/src/__tests__/ContextWindowProgressLogic.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// This test directly tests the logic of the ContextWindowProgress component calculations
22
// without needing to render the full component
33
import { describe, test, expect } from "@jest/globals"
4-
import { calculateTokenDistribution } from "../utils/model-utils"
4+
import { calculateTokenDistribution } from "@src/utils/model-utils"
55

66
export {} // This makes the file a proper TypeScript module
77

webview-ui/src/__tests__/TelemetryClient.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Tests for TelemetryClient
33
*/
4-
import { telemetryClient } from "../utils/TelemetryClient"
4+
import { telemetryClient } from "@src/utils/TelemetryClient"
55
import posthog from "posthog-js"
66

77
describe("TelemetryClient", () => {

webview-ui/src/__tests__/components/common/CommandOutputViewer.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import React from "react"
22
import { render, screen } from "@testing-library/react"
3-
import CommandOutputViewer from "../../../components/common/CommandOutputViewer"
3+
import CommandOutputViewer from "@src/components/common/CommandOutputViewer"
44

55
// Mock the cn utility function
6-
jest.mock("../../../lib/utils", () => ({
6+
jest.mock("@src/lib/utils", () => ({
77
cn: (...inputs: any[]) => inputs.filter(Boolean).join(" "),
88
}))
99

0 commit comments

Comments
 (0)