Skip to content

Commit 5e8d804

Browse files
committed
Add test
1 parent 2cdfff0 commit 5e8d804

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
import { OpenAiHandler } from '../openai'
2+
import { ApiHandlerOptions, openAiModelInfoSaneDefaults } from '../../../shared/api'
3+
import OpenAI, { AzureOpenAI } from 'openai'
4+
import { Anthropic } from '@anthropic-ai/sdk'
5+
6+
// Mock dependencies
7+
jest.mock('openai')
8+
9+
describe('OpenAiHandler', () => {
10+
const mockOptions: ApiHandlerOptions = {
11+
openAiApiKey: 'test-key',
12+
openAiModelId: 'gpt-4',
13+
openAiStreamingEnabled: true,
14+
openAiBaseUrl: 'https://api.openai.com/v1'
15+
}
16+
17+
beforeEach(() => {
18+
jest.clearAllMocks()
19+
})
20+
21+
test('constructor initializes with correct options', () => {
22+
const handler = new OpenAiHandler(mockOptions)
23+
expect(handler).toBeInstanceOf(OpenAiHandler)
24+
expect(OpenAI).toHaveBeenCalledWith({
25+
apiKey: mockOptions.openAiApiKey,
26+
baseURL: mockOptions.openAiBaseUrl
27+
})
28+
})
29+
30+
test('constructor initializes Azure client when Azure URL is provided', () => {
31+
const azureOptions: ApiHandlerOptions = {
32+
...mockOptions,
33+
openAiBaseUrl: 'https://example.azure.com',
34+
azureApiVersion: '2023-05-15'
35+
}
36+
const handler = new OpenAiHandler(azureOptions)
37+
expect(handler).toBeInstanceOf(OpenAiHandler)
38+
expect(AzureOpenAI).toHaveBeenCalledWith({
39+
baseURL: azureOptions.openAiBaseUrl,
40+
apiKey: azureOptions.openAiApiKey,
41+
apiVersion: azureOptions.azureApiVersion
42+
})
43+
})
44+
45+
test('getModel returns correct model info', () => {
46+
const handler = new OpenAiHandler(mockOptions)
47+
const result = handler.getModel()
48+
49+
expect(result).toEqual({
50+
id: mockOptions.openAiModelId,
51+
info: openAiModelInfoSaneDefaults
52+
})
53+
})
54+
55+
test('createMessage handles streaming correctly when enabled', async () => {
56+
const handler = new OpenAiHandler({
57+
...mockOptions,
58+
openAiStreamingEnabled: true,
59+
includeMaxTokens: true
60+
})
61+
62+
const mockStream = {
63+
async *[Symbol.asyncIterator]() {
64+
yield {
65+
choices: [{
66+
delta: {
67+
content: 'test response'
68+
}
69+
}],
70+
usage: {
71+
prompt_tokens: 10,
72+
completion_tokens: 5
73+
}
74+
}
75+
}
76+
}
77+
78+
const mockCreate = jest.fn().mockResolvedValue(mockStream)
79+
;(OpenAI as jest.MockedClass<typeof OpenAI>).prototype.chat = {
80+
completions: { create: mockCreate }
81+
} as any
82+
83+
const systemPrompt = 'test system prompt'
84+
const messages: Anthropic.Messages.MessageParam[] = [
85+
{ role: 'user', content: 'test message' }
86+
]
87+
88+
const generator = handler.createMessage(systemPrompt, messages)
89+
const chunks = []
90+
91+
for await (const chunk of generator) {
92+
chunks.push(chunk)
93+
}
94+
95+
expect(chunks).toEqual([
96+
{
97+
type: 'text',
98+
text: 'test response'
99+
},
100+
{
101+
type: 'usage',
102+
inputTokens: 10,
103+
outputTokens: 5
104+
}
105+
])
106+
107+
expect(mockCreate).toHaveBeenCalledWith({
108+
model: mockOptions.openAiModelId,
109+
messages: [
110+
{ role: 'system', content: systemPrompt },
111+
{ role: 'user', content: 'test message' }
112+
],
113+
temperature: 0,
114+
stream: true,
115+
stream_options: { include_usage: true },
116+
max_tokens: openAiModelInfoSaneDefaults.maxTokens
117+
})
118+
})
119+
120+
test('createMessage handles non-streaming correctly when disabled', async () => {
121+
const handler = new OpenAiHandler({
122+
...mockOptions,
123+
openAiStreamingEnabled: false
124+
})
125+
126+
const mockResponse = {
127+
choices: [{
128+
message: {
129+
content: 'test response'
130+
}
131+
}],
132+
usage: {
133+
prompt_tokens: 10,
134+
completion_tokens: 5
135+
}
136+
}
137+
138+
const mockCreate = jest.fn().mockResolvedValue(mockResponse)
139+
;(OpenAI as jest.MockedClass<typeof OpenAI>).prototype.chat = {
140+
completions: { create: mockCreate }
141+
} as any
142+
143+
const systemPrompt = 'test system prompt'
144+
const messages: Anthropic.Messages.MessageParam[] = [
145+
{ role: 'user', content: 'test message' }
146+
]
147+
148+
const generator = handler.createMessage(systemPrompt, messages)
149+
const chunks = []
150+
151+
for await (const chunk of generator) {
152+
chunks.push(chunk)
153+
}
154+
155+
expect(chunks).toEqual([
156+
{
157+
type: 'text',
158+
text: 'test response'
159+
},
160+
{
161+
type: 'usage',
162+
inputTokens: 10,
163+
outputTokens: 5
164+
}
165+
])
166+
167+
expect(mockCreate).toHaveBeenCalledWith({
168+
model: mockOptions.openAiModelId,
169+
messages: [
170+
{ role: 'user', content: systemPrompt },
171+
{ role: 'user', content: 'test message' }
172+
]
173+
})
174+
})
175+
176+
test('createMessage handles API errors', async () => {
177+
const handler = new OpenAiHandler(mockOptions)
178+
const mockStream = {
179+
async *[Symbol.asyncIterator]() {
180+
throw new Error('API Error')
181+
}
182+
}
183+
184+
const mockCreate = jest.fn().mockResolvedValue(mockStream)
185+
;(OpenAI as jest.MockedClass<typeof OpenAI>).prototype.chat = {
186+
completions: { create: mockCreate }
187+
} as any
188+
189+
const generator = handler.createMessage('test', [])
190+
await expect(generator.next()).rejects.toThrow('API Error')
191+
})
192+
})

0 commit comments

Comments
 (0)