Skip to content

Commit 0e23a5a

Browse files
committed
test(core): avoid mutating provider identifiers
1 parent 53a2fdd commit 0e23a5a

3 files changed

Lines changed: 90 additions & 114 deletions

File tree

src/core/task/__tests__/Task.spec.ts

Lines changed: 42 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as path from "path"
66
import * as vscode from "vscode"
77
import { Anthropic } from "@anthropic-ai/sdk"
88

9-
import { providerIdentifiers, type GlobalState, type ProviderSettings, type ModelInfo } from "@roo-code/types"
9+
import type { GlobalState, ProviderSettings, ModelInfo } from "@roo-code/types"
1010
import { TelemetryService } from "@roo-code/telemetry"
1111

1212
import { Task } from "../Task"
@@ -1902,55 +1902,47 @@ describe("Cline", () => {
19021902
expect(metadata!.abortSignal).toBe(task.currentRequestAbortController!.signal)
19031903
})
19041904

1905-
it("uses the canonical Gemini identifier when configuring tool restrictions", async () => {
1906-
const identifiers = providerIdentifiers as Record<string, string>
1907-
const originalIdentifier = identifiers.gemini
1908-
1909-
try {
1910-
identifiers.gemini = "canonical-gemini"
1911-
const apiConfiguration = {
1912-
...mockApiConfig,
1913-
apiProvider: identifiers.gemini,
1914-
} as ProviderSettings
1915-
const task = new Task({
1916-
provider: mockProvider,
1917-
apiConfiguration,
1918-
task: "test task",
1919-
startTask: false,
1920-
})
1921-
1922-
vi.spyOn(task as any, "getSystemPrompt").mockResolvedValue("mock system prompt")
1923-
vi.spyOn(task.api, "getModel").mockReturnValue({
1924-
id: mockApiConfig.apiModelId!,
1925-
info: { contextWindow: 200000, maxTokens: 4096 } as ModelInfo,
1926-
})
1927-
const providerState = await mockProvider.getState()
1928-
vi.spyOn(mockProvider, "getState").mockResolvedValue({
1929-
...providerState,
1930-
apiConfiguration,
1931-
autoApprovalEnabled: true,
1932-
requestDelaySeconds: 0,
1933-
})
1934-
const mockStream = (async function* () {
1935-
yield { type: "text", text: "response" } as ApiStreamChunk
1936-
})()
1937-
const createMessageSpy = vi.spyOn(task.api, "createMessage").mockReturnValue(mockStream)
1938-
task.apiConversationHistory = [
1939-
{ role: "user", content: [{ type: "text", text: "test message" }], ts: Date.now() },
1940-
] as any
1941-
1942-
await task.attemptApiRequest(0).next()
1943-
1944-
const [, , metadata] = createMessageSpy.mock.calls[0]!
1945-
expect(metadata).toEqual(
1946-
expect.objectContaining({
1947-
tools: expect.any(Array),
1948-
allowedFunctionNames: expect.any(Array),
1949-
}),
1950-
)
1951-
} finally {
1952-
identifiers.gemini = originalIdentifier
1953-
}
1905+
it("configures tool restrictions for Gemini requests", async () => {
1906+
const apiConfiguration = {
1907+
...mockApiConfig,
1908+
apiProvider: "gemini",
1909+
} as ProviderSettings
1910+
const task = new Task({
1911+
provider: mockProvider,
1912+
apiConfiguration,
1913+
task: "test task",
1914+
startTask: false,
1915+
})
1916+
1917+
vi.spyOn(task as any, "getSystemPrompt").mockResolvedValue("mock system prompt")
1918+
vi.spyOn(task.api, "getModel").mockReturnValue({
1919+
id: mockApiConfig.apiModelId!,
1920+
info: { contextWindow: 200000, maxTokens: 4096 } as ModelInfo,
1921+
})
1922+
const providerState = await mockProvider.getState()
1923+
vi.spyOn(mockProvider, "getState").mockResolvedValue({
1924+
...providerState,
1925+
apiConfiguration,
1926+
autoApprovalEnabled: true,
1927+
requestDelaySeconds: 0,
1928+
})
1929+
const mockStream = (async function* () {
1930+
yield { type: "text", text: "response" } as ApiStreamChunk
1931+
})()
1932+
const createMessageSpy = vi.spyOn(task.api, "createMessage").mockReturnValue(mockStream)
1933+
task.apiConversationHistory = [
1934+
{ role: "user", content: [{ type: "text", text: "test message" }], ts: Date.now() },
1935+
] as any
1936+
1937+
await task.attemptApiRequest(0).next()
1938+
1939+
const [, , metadata] = createMessageSpy.mock.calls[0]!
1940+
expect(metadata).toEqual(
1941+
expect.objectContaining({
1942+
tools: expect.any(Array),
1943+
allowedFunctionNames: expect.any(Array),
1944+
}),
1945+
)
19541946
})
19551947

19561948
it("should invoke abort on currentRequestAbortController during first-chunk wait", async () => {

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

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -528,25 +528,16 @@ describe("ClineProvider", () => {
528528
expect(ClineProvider.getVisibleInstance()).toBe(provider)
529529
})
530530

531-
test("prepares LM Studio tasks through the canonical provider identifier", async () => {
532-
const identifiers = providerIdentifiers as Record<string, string>
533-
const originalIdentifier = identifiers.lmstudio
534-
535-
try {
536-
identifiers.lmstudio = "canonical-lmstudio"
537-
538-
await provider.performPreparationTasks({
539-
apiConfiguration: {
540-
apiProvider: identifiers.lmstudio,
541-
lmStudioBaseUrl: "http://localhost:1234",
542-
lmStudioModelId: "test-model",
543-
},
544-
} as Task)
531+
test("loads full model details when preparing an LM Studio task", async () => {
532+
await provider.performPreparationTasks({
533+
apiConfiguration: {
534+
apiProvider: "lmstudio",
535+
lmStudioBaseUrl: "http://localhost:1234",
536+
lmStudioModelId: "test-model",
537+
},
538+
} as Task)
545539

546-
expect(forceFullModelDetailsLoad).toHaveBeenCalledWith("http://localhost:1234", "test-model")
547-
} finally {
548-
identifiers.lmstudio = originalIdentifier
549-
}
540+
expect(forceFullModelDetailsLoad).toHaveBeenCalledWith("http://localhost:1234", "test-model")
550541
})
551542

552543
test("resolveWebviewView hydrates the saved terminalProfile into the process-wide Terminal state", async () => {

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

Lines changed: 39 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ vi.mock("../rulesMessageHandler", () => ({
5151
handleOpenRulesDirectory: vi.fn(),
5252
}))
5353

54-
import { providerIdentifiers, type ModelRecord } from "@roo-code/types"
54+
import type { ModelRecord } from "@roo-code/types"
5555

5656
import { webviewMessageHandler } from "../webviewMessageHandler"
5757
import type { ClineProvider } from "../ClineProvider"
@@ -1495,56 +1495,49 @@ describe("zooCodeSignOut", () => {
14951495
vi.clearAllMocks()
14961496
})
14971497

1498-
it("disconnects Zoo Code and clears tokens from all profiles using the canonical Zoo Gateway identifier", async () => {
1498+
it("disconnects Zoo Code and clears tokens from all Zoo Gateway profiles", async () => {
14991499
const { disconnectZooCode } = await import("../../../services/zoo-code-auth")
1500-
const identifiers = providerIdentifiers as Record<string, string>
1501-
const originalIdentifier = identifiers.zooGateway
15021500
const upsertProviderProfile = vi.fn().mockResolvedValue(undefined)
15031501
const saveConfig = vi.fn().mockResolvedValue(undefined)
15041502

1505-
try {
1506-
identifiers.zooGateway = "canonical-zoo-gateway"
1507-
;(mockClineProvider as any).contextProxy = {
1508-
...mockClineProvider.contextProxy,
1509-
getProviderSettings: vi.fn().mockReturnValue({ apiProvider: identifiers.zooGateway }),
1510-
getValues: vi.fn().mockReturnValue({ currentApiConfigName: "Zoo Gateway" }),
1511-
}
1512-
;(mockClineProvider as any).providerSettingsManager = {
1513-
listConfig: vi.fn().mockResolvedValue([
1514-
{ name: "Zoo Gateway", apiProvider: identifiers.zooGateway },
1515-
{ name: "Backup Zoo", apiProvider: identifiers.zooGateway },
1516-
]),
1517-
getProfile: vi
1518-
.fn()
1519-
.mockResolvedValueOnce({
1520-
apiProvider: identifiers.zooGateway,
1521-
zooSessionToken: "token-active",
1522-
zooGatewayModelId: "anthropic/claude-sonnet-4",
1523-
})
1524-
.mockResolvedValueOnce({
1525-
apiProvider: identifiers.zooGateway,
1526-
zooSessionToken: "token-backup",
1527-
}),
1528-
saveConfig,
1529-
}
1530-
;(mockClineProvider as any).upsertProviderProfile = upsertProviderProfile
1531-
1532-
await webviewMessageHandler(mockClineProvider, { type: "zooCodeSignOut" })
1533-
1534-
expect(disconnectZooCode).toHaveBeenCalled()
1535-
expect(upsertProviderProfile).toHaveBeenCalledWith(
1536-
"Zoo Gateway",
1537-
expect.not.objectContaining({ zooSessionToken: expect.anything() }),
1538-
true,
1539-
)
1540-
expect(saveConfig).toHaveBeenCalledWith(
1541-
"Backup Zoo",
1542-
expect.not.objectContaining({ zooSessionToken: expect.anything() }),
1543-
)
1544-
expect(mockClineProvider.postStateToWebview).toHaveBeenCalled()
1545-
} finally {
1546-
identifiers.zooGateway = originalIdentifier
1503+
;(mockClineProvider as any).contextProxy = {
1504+
...mockClineProvider.contextProxy,
1505+
getProviderSettings: vi.fn().mockReturnValue({ apiProvider: "zoo-gateway" }),
1506+
getValues: vi.fn().mockReturnValue({ currentApiConfigName: "Zoo Gateway" }),
1507+
}
1508+
;(mockClineProvider as any).providerSettingsManager = {
1509+
listConfig: vi.fn().mockResolvedValue([
1510+
{ name: "Zoo Gateway", apiProvider: "zoo-gateway" },
1511+
{ name: "Backup Zoo", apiProvider: "zoo-gateway" },
1512+
]),
1513+
getProfile: vi
1514+
.fn()
1515+
.mockResolvedValueOnce({
1516+
apiProvider: "zoo-gateway",
1517+
zooSessionToken: "token-active",
1518+
zooGatewayModelId: "anthropic/claude-sonnet-4",
1519+
})
1520+
.mockResolvedValueOnce({
1521+
apiProvider: "zoo-gateway",
1522+
zooSessionToken: "token-backup",
1523+
}),
1524+
saveConfig,
15471525
}
1526+
;(mockClineProvider as any).upsertProviderProfile = upsertProviderProfile
1527+
1528+
await webviewMessageHandler(mockClineProvider, { type: "zooCodeSignOut" })
1529+
1530+
expect(disconnectZooCode).toHaveBeenCalled()
1531+
expect(upsertProviderProfile).toHaveBeenCalledWith(
1532+
"Zoo Gateway",
1533+
expect.not.objectContaining({ zooSessionToken: expect.anything() }),
1534+
true,
1535+
)
1536+
expect(saveConfig).toHaveBeenCalledWith(
1537+
"Backup Zoo",
1538+
expect.not.objectContaining({ zooSessionToken: expect.anything() }),
1539+
)
1540+
expect(mockClineProvider.postStateToWebview).toHaveBeenCalled()
15481541
})
15491542

15501543
it("still clears the in-memory handler when the active profile token is already empty on disk", async () => {

0 commit comments

Comments
 (0)