Skip to content

Commit 186ebb9

Browse files
committed
test(api): cover canonical provider routing
1 parent d25f8b7 commit 186ebb9

1 file changed

Lines changed: 90 additions & 30 deletions

File tree

src/api/__tests__/index.spec.ts

Lines changed: 90 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
// npx vitest run src/api/__tests__/index.spec.ts
22

3-
import fs from "node:fs"
4-
53
// Mock vscode first to avoid import errors
64
vitest.mock("vscode", () => ({
75
workspace: {
@@ -11,40 +9,110 @@ vitest.mock("vscode", () => ({
119
},
1210
}))
1311

14-
import {
15-
providerIdentifiers,
16-
retiredProviderIdentifiers,
17-
type ProviderSettings,
18-
type ProviderNameWithRetired,
19-
} from "@roo-code/types"
12+
// Handler constructors can require credentials or initialize SDK clients. Replace them
13+
// with inert classes so these tests exercise only the factory's routing behavior.
14+
vitest.mock("../providers", async () => {
15+
const providers = await vitest.importActual<Record<string, unknown>>("../providers")
2016

21-
import { buildApiHandler } from "../index"
22-
import { AnthropicHandler } from "../providers/anthropic"
23-
import { KenariHandler } from "../providers/kenari"
24-
import { OpenRouterHandler } from "../providers/openrouter"
17+
return Object.fromEntries(Object.keys(providers).map((name) => [name, class {}]))
18+
})
2519

26-
describe("buildApiHandler", () => {
27-
it("returns a KenariHandler for the kenari provider", () => {
28-
const configuration: ProviderSettings = {
29-
apiProvider: providerIdentifiers.kenari,
30-
kenariApiKey: "test-key",
31-
kenariModelId: "glm-5-2",
32-
}
20+
vitest.mock("../providers/native-ollama", () => ({
21+
NativeOllamaHandler: class {},
22+
}))
3323

34-
const handler = buildApiHandler(configuration)
24+
import { providerIdentifiers, retiredProviderIdentifiers, type ProviderNameWithRetired } from "@roo-code/types"
3525

36-
expect(handler).toBeInstanceOf(KenariHandler)
37-
})
26+
import { buildApiHandler } from "../index"
27+
import {
28+
AnthropicHandler,
29+
AnthropicVertexHandler,
30+
AwsBedrockHandler,
31+
BasetenHandler,
32+
DeepSeekHandler,
33+
FakeAIHandler,
34+
FireworksHandler,
35+
FriendliHandler,
36+
GeminiHandler,
37+
KenariHandler,
38+
KimiCodeHandler,
39+
LiteLLMHandler,
40+
LmStudioHandler,
41+
MiniMaxHandler,
42+
MimoHandler,
43+
MistralHandler,
44+
MoonshotHandler,
45+
OpenAiCodexHandler,
46+
OpenAiHandler,
47+
OpenAiNativeHandler,
48+
OpencodeGoHandler,
49+
OpenRouterHandler,
50+
PoeHandler,
51+
QwenCodeHandler,
52+
RequestyHandler,
53+
SambaNovaHandler,
54+
UnboundHandler,
55+
VercelAiGatewayHandler,
56+
VertexHandler,
57+
VsCodeLmHandler,
58+
XAIHandler,
59+
ZAiHandler,
60+
ZooGatewayHandler,
61+
} from "../providers"
62+
import { NativeOllamaHandler } from "../providers/native-ollama"
3863

64+
describe("buildApiHandler", () => {
3965
it.each([
4066
[providerIdentifiers.anthropic, AnthropicHandler],
4167
[providerIdentifiers.openrouter, OpenRouterHandler],
68+
[providerIdentifiers.bedrock, AwsBedrockHandler],
69+
[providerIdentifiers.openai, OpenAiHandler],
70+
[providerIdentifiers.ollama, NativeOllamaHandler],
71+
[providerIdentifiers.lmstudio, LmStudioHandler],
72+
[providerIdentifiers.gemini, GeminiHandler],
73+
[providerIdentifiers.openaiCodex, OpenAiCodexHandler],
74+
[providerIdentifiers.openaiNative, OpenAiNativeHandler],
75+
[providerIdentifiers.deepseek, DeepSeekHandler],
76+
[providerIdentifiers.qwenCode, QwenCodeHandler],
77+
[providerIdentifiers.moonshot, MoonshotHandler],
78+
[providerIdentifiers.kimiCode, KimiCodeHandler],
79+
[providerIdentifiers.vscodeLm, VsCodeLmHandler],
80+
[providerIdentifiers.mistral, MistralHandler],
81+
[providerIdentifiers.requesty, RequestyHandler],
82+
[providerIdentifiers.unbound, UnboundHandler],
83+
[providerIdentifiers.fakeAi, FakeAIHandler],
84+
[providerIdentifiers.xai, XAIHandler],
85+
[providerIdentifiers.litellm, LiteLLMHandler],
86+
[providerIdentifiers.sambanova, SambaNovaHandler],
87+
[providerIdentifiers.mimo, MimoHandler],
88+
[providerIdentifiers.zai, ZAiHandler],
89+
[providerIdentifiers.fireworks, FireworksHandler],
90+
[providerIdentifiers.friendli, FriendliHandler],
91+
[providerIdentifiers.vercelAiGateway, VercelAiGatewayHandler],
92+
[providerIdentifiers.opencodeGo, OpencodeGoHandler],
93+
[providerIdentifiers.kenari, KenariHandler],
94+
[providerIdentifiers.zooGateway, ZooGatewayHandler],
95+
[providerIdentifiers.minimax, MiniMaxHandler],
96+
[providerIdentifiers.baseten, BasetenHandler],
97+
[providerIdentifiers.poe, PoeHandler],
4298
] as const)("returns the expected handler for %s", (apiProvider, Handler) => {
4399
const handler = buildApiHandler({ apiProvider })
44100

45101
expect(handler).toBeInstanceOf(Handler)
46102
})
47103

104+
it.each([
105+
["non-Claude models", "gemini-2.5-pro", VertexHandler],
106+
["Claude models", "claude-3-7-sonnet", AnthropicVertexHandler],
107+
] as const)("returns the expected Vertex handler for %s", (_description, apiModelId, Handler) => {
108+
const handler = buildApiHandler({
109+
apiProvider: providerIdentifiers.vertex,
110+
apiModelId,
111+
})
112+
113+
expect(handler).toBeInstanceOf(Handler)
114+
})
115+
48116
it("preserves the dedicated removal error for the retired Roo provider", () => {
49117
expect(() =>
50118
buildApiHandler({
@@ -68,12 +136,4 @@ describe("buildApiHandler", () => {
68136

69137
expect(handler).toBeInstanceOf(AnthropicHandler)
70138
})
71-
72-
it("uses canonical identifiers instead of provider literals in the handler factory", () => {
73-
const factorySource = fs.readFileSync(new URL("../index.ts", import.meta.url), "utf8")
74-
75-
expect(factorySource).toContain("providerIdentifiers.anthropic")
76-
expect(factorySource).toContain("retiredProviderIdentifiers.roo")
77-
expect(factorySource).not.toMatch(/case\s+["']/)
78-
})
79139
})

0 commit comments

Comments
 (0)