Skip to content

Commit 0a2276f

Browse files
committed
test(providers): cover Poe canonical identifiers
1 parent efcfa3b commit 0a2276f

1 file changed

Lines changed: 124 additions & 37 deletions

File tree

src/api/providers/__tests__/poe.spec.ts

Lines changed: 124 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,55 @@
1-
const mockStreamText = vitest.fn()
2-
const mockGenerateText = vitest.fn()
3-
const mockCreatePoe = vitest.fn()
1+
import { poeDefaultModelId, providerIdentifiers } from "@roo-code/types"
2+
3+
import { PoeHandler } from "../poe"
4+
import { getModelsFromCache } from "../fetchers/modelCache"
5+
6+
import { clearAllMocks } from "../../../test-utils/reset"
7+
8+
const { mockStreamText, mockGenerateText, mockCreatePoe, mockGetModelsFromCache, mockCaptureException } =
9+
vitest.hoisted(() => ({
10+
mockStreamText: vitest.fn(),
11+
mockGenerateText: vitest.fn(),
12+
mockCreatePoe: vitest.fn(),
13+
mockCaptureException: vitest.fn(),
14+
mockGetModelsFromCache: vitest.fn(),
15+
}))
16+
17+
const cachedModels = {
18+
"anthropic/claude-sonnet-4": {
19+
maxTokens: 10_000,
20+
contextWindow: 200_000,
21+
supportsImages: true,
22+
supportsPromptCache: true,
23+
supportsReasoningBudget: true,
24+
inputPrice: 3,
25+
outputPrice: 15,
26+
},
27+
"openai/gpt-4o": {
28+
maxTokens: 16_384,
29+
contextWindow: 128_000,
30+
supportsImages: true,
31+
supportsPromptCache: false,
32+
inputPrice: 2.5,
33+
outputPrice: 10,
34+
},
35+
"openai/o3": {
36+
maxTokens: 100_000,
37+
contextWindow: 200_000,
38+
supportsImages: true,
39+
supportsPromptCache: false,
40+
supportsReasoningEffort: ["low", "medium", "high"],
41+
inputPrice: 10,
42+
outputPrice: 40,
43+
},
44+
}
45+
46+
vitest.mock("@roo-code/telemetry", () => ({
47+
TelemetryService: {
48+
instance: {
49+
captureException: (...args: unknown[]) => mockCaptureException(...args),
50+
},
51+
},
52+
}))
453

554
vitest.mock("ai-sdk-provider-poe", () => ({
655
createPoe: (...args: unknown[]) => mockCreatePoe(...args),
@@ -41,48 +90,17 @@ vitest.mock("ai", async (importOriginal) => {
4190
})
4291

4392
vitest.mock("../fetchers/modelCache", () => ({
44-
getModelsFromCache: vitest.fn().mockReturnValue({
45-
"anthropic/claude-sonnet-4": {
46-
maxTokens: 10_000,
47-
contextWindow: 200_000,
48-
supportsImages: true,
49-
supportsPromptCache: true,
50-
supportsReasoningBudget: true,
51-
inputPrice: 3,
52-
outputPrice: 15,
53-
},
54-
"openai/gpt-4o": {
55-
maxTokens: 16_384,
56-
contextWindow: 128_000,
57-
supportsImages: true,
58-
supportsPromptCache: false,
59-
inputPrice: 2.5,
60-
outputPrice: 10,
61-
},
62-
"openai/o3": {
63-
maxTokens: 100_000,
64-
contextWindow: 200_000,
65-
supportsImages: true,
66-
supportsPromptCache: false,
67-
supportsReasoningEffort: ["low", "medium", "high"],
68-
inputPrice: 10,
69-
outputPrice: 40,
70-
},
71-
}),
93+
getModelsFromCache: mockGetModelsFromCache,
7294
}))
7395

74-
import { poeDefaultModelId } from "@roo-code/types"
75-
import { PoeHandler } from "../poe"
76-
77-
import { clearAllMocks } from "../../../test-utils/reset"
78-
7996
describe("PoeHandler", () => {
8097
const mockLanguageModel = { modelId: "test-model" }
8198
const mockPoeProvider = vitest.fn().mockReturnValue(mockLanguageModel)
8299

83100
beforeEach(() => {
84101
clearAllMocks()
85102
mockCreatePoe.mockReturnValue(mockPoeProvider)
103+
mockGetModelsFromCache.mockReturnValue(cachedModels)
86104
})
87105

88106
describe("constructor", () => {
@@ -116,9 +134,19 @@ describe("PoeHandler", () => {
116134

117135
describe("getModel", () => {
118136
it("returns model info from cache", () => {
119-
const handler = new PoeHandler({ poeApiKey: "key", apiModelId: "anthropic/claude-sonnet-4" })
137+
const options = {
138+
poeApiKey: "key",
139+
poeBaseUrl: "https://custom.poe.com/v1",
140+
apiModelId: "anthropic/claude-sonnet-4",
141+
}
142+
const handler = new PoeHandler(options)
120143
const result = handler.getModel()
121144

145+
expect(getModelsFromCache).toHaveBeenCalledWith({
146+
provider: providerIdentifiers.poe,
147+
apiKey: options.poeApiKey,
148+
baseUrl: options.poeBaseUrl,
149+
})
122150
expect(result.id).toBe("anthropic/claude-sonnet-4")
123151
expect(result.info.contextWindow).toBe(200_000)
124152
expect(result.info.maxTokens).toBe(10_000)
@@ -166,6 +194,49 @@ describe("PoeHandler", () => {
166194
expect(chunks).toContainEqual({ type: "text", text: "world!" })
167195
expect(chunks).toContainEqual(expect.objectContaining({ type: "usage", inputTokens: 10, outputTokens: 5 }))
168196
})
197+
198+
it("reports synchronous completion failures with the canonical provider identifier", async () => {
199+
const handler = new PoeHandler({ poeApiKey: "key", apiModelId: "openai/gpt-4o" })
200+
mockStreamText.mockImplementationOnce(() => {
201+
throw new Error("request failed")
202+
})
203+
204+
await expect(
205+
handler.createMessage("system", [{ role: "user" as const, content: "hello" }]).next(),
206+
).rejects.toThrow("Poe completion error: request failed")
207+
expect(mockCaptureException).toHaveBeenCalledWith(
208+
expect.objectContaining({
209+
provider: providerIdentifiers.poe,
210+
modelId: "openai/gpt-4o",
211+
operation: "createMessage",
212+
}),
213+
)
214+
})
215+
216+
it("reports asynchronous stream failures with the canonical provider identifier", async () => {
217+
const handler = new PoeHandler({ poeApiKey: "key", apiModelId: "openai/gpt-4o" })
218+
const failedStream = {
219+
[Symbol.asyncIterator]() {
220+
return this
221+
},
222+
next: vitest.fn().mockRejectedValueOnce(new Error("stream failed")),
223+
}
224+
mockStreamText.mockReturnValueOnce({
225+
fullStream: failedStream,
226+
usage: Promise.resolve(undefined),
227+
})
228+
229+
await expect(
230+
handler.createMessage("system", [{ role: "user" as const, content: "hello" }]).next(),
231+
).rejects.toThrow("Poe streaming error: stream failed")
232+
expect(mockCaptureException).toHaveBeenCalledWith(
233+
expect.objectContaining({
234+
provider: providerIdentifiers.poe,
235+
modelId: "openai/gpt-4o",
236+
operation: "createMessage",
237+
}),
238+
)
239+
})
169240
})
170241

171242
describe("reasoning", () => {
@@ -311,5 +382,21 @@ describe("PoeHandler", () => {
311382
}),
312383
)
313384
})
385+
386+
it("reports failures with the canonical provider identifier", async () => {
387+
const handler = new PoeHandler({ poeApiKey: "key", apiModelId: "openai/gpt-4o" })
388+
mockGenerateText.mockRejectedValueOnce(new Error("generation failed"))
389+
390+
await expect(handler.completePrompt("complete this")).rejects.toThrow(
391+
"Poe completion error: generation failed",
392+
)
393+
expect(mockCaptureException).toHaveBeenCalledWith(
394+
expect.objectContaining({
395+
provider: providerIdentifiers.poe,
396+
modelId: "openai/gpt-4o",
397+
operation: "completePrompt",
398+
}),
399+
)
400+
})
314401
})
315402
})

0 commit comments

Comments
 (0)