1- import { GeminiHandler } from "../gemini"
1+ // npx jest src/api/providers/__tests__/gemini.test.ts
2+
23import { Anthropic } from "@anthropic-ai/sdk"
3- import { GoogleGenerativeAI } from "@google/generative-ai"
4-
5- // Mock the Google Generative AI SDK
6- jest . mock ( "@google/generative-ai" , ( ) => ( {
7- GoogleGenerativeAI : jest . fn ( ) . mockImplementation ( ( ) => ( {
8- getGenerativeModel : jest . fn ( ) . mockReturnValue ( {
9- generateContentStream : jest . fn ( ) ,
10- generateContent : jest . fn ( ) . mockResolvedValue ( {
11- response : {
12- text : ( ) => "Test response" ,
13- } ,
14- } ) ,
15- } ) ,
16- } ) ) ,
17- } ) )
4+
5+ import { GeminiHandler } from "../gemini"
6+ import { geminiDefaultModelId } from "../../../shared/api"
7+
8+ const GEMINI_20_FLASH_THINKING_NAME = "gemini-2.0-flash-thinking-exp-1219"
189
1910describe ( "GeminiHandler" , ( ) => {
2011 let handler : GeminiHandler
2112
2213 beforeEach ( ( ) => {
14+ // Create mock functions
15+ const mockGenerateContentStream = jest . fn ( )
16+ const mockGenerateContent = jest . fn ( )
17+ const mockGetGenerativeModel = jest . fn ( )
18+
2319 handler = new GeminiHandler ( {
2420 apiKey : "test-key" ,
25- apiModelId : "gemini-2.0-flash-thinking-exp-1219" ,
21+ apiModelId : GEMINI_20_FLASH_THINKING_NAME ,
2622 geminiApiKey : "test-key" ,
2723 } )
24+
25+ // Replace the client with our mock
26+ handler [ "client" ] = {
27+ models : {
28+ generateContentStream : mockGenerateContentStream ,
29+ generateContent : mockGenerateContent ,
30+ getGenerativeModel : mockGetGenerativeModel ,
31+ } ,
32+ } as any
2833 } )
2934
3035 describe ( "constructor" , ( ) => {
3136 it ( "should initialize with provided config" , ( ) => {
3237 expect ( handler [ "options" ] . geminiApiKey ) . toBe ( "test-key" )
33- expect ( handler [ "options" ] . apiModelId ) . toBe ( "gemini-2.0-flash-thinking-exp-1219" )
34- } )
35-
36- it . skip ( "should throw if API key is missing" , ( ) => {
37- expect ( ( ) => {
38- new GeminiHandler ( {
39- apiModelId : "gemini-2.0-flash-thinking-exp-1219" ,
40- geminiApiKey : "" ,
41- } )
42- } ) . toThrow ( "API key is required for Google Gemini" )
38+ expect ( handler [ "options" ] . apiModelId ) . toBe ( GEMINI_20_FLASH_THINKING_NAME )
4339 } )
4440 } )
4541
@@ -58,25 +54,15 @@ describe("GeminiHandler", () => {
5854 const systemPrompt = "You are a helpful assistant"
5955
6056 it ( "should handle text messages correctly" , async ( ) => {
61- // Mock the stream response
62- const mockStream = {
63- stream : [ { text : ( ) => "Hello" } , { text : ( ) => " world!" } ] ,
64- response : {
65- usageMetadata : {
66- promptTokenCount : 10 ,
67- candidatesTokenCount : 5 ,
68- } ,
57+ // Setup the mock implementation to return an async generator
58+ ; ( handler [ "client" ] . models . generateContentStream as jest . Mock ) . mockResolvedValue ( {
59+ [ Symbol . asyncIterator ] : async function * ( ) {
60+ yield { text : "Hello" }
61+ yield { text : " world!" }
62+ yield { usageMetadata : { promptTokenCount : 10 , candidatesTokenCount : 5 } }
6963 } ,
70- }
71-
72- // Setup the mock implementation
73- const mockGenerateContentStream = jest . fn ( ) . mockResolvedValue ( mockStream )
74- const mockGetGenerativeModel = jest . fn ( ) . mockReturnValue ( {
75- generateContentStream : mockGenerateContentStream ,
7664 } )
7765
78- ; ( handler [ "client" ] as any ) . getGenerativeModel = mockGetGenerativeModel
79-
8066 const stream = handler . createMessage ( systemPrompt , mockMessages )
8167 const chunks = [ ]
8268
@@ -100,99 +86,67 @@ describe("GeminiHandler", () => {
10086 outputTokens : 5 ,
10187 } )
10288
103- // Verify the model configuration
104- expect ( mockGetGenerativeModel ) . toHaveBeenCalledWith (
105- {
106- model : "gemini-2.0-flash-thinking-exp-1219" ,
107- systemInstruction : systemPrompt ,
108- } ,
109- {
110- baseUrl : undefined ,
111- } ,
112- )
113-
114- // Verify generation config
115- expect ( mockGenerateContentStream ) . toHaveBeenCalledWith (
89+ // Verify the call to generateContentStream
90+ expect ( handler [ "client" ] . models . generateContentStream ) . toHaveBeenCalledWith (
11691 expect . objectContaining ( {
117- generationConfig : {
92+ model : GEMINI_20_FLASH_THINKING_NAME ,
93+ config : expect . objectContaining ( {
11894 temperature : 0 ,
119- } ,
95+ systemInstruction : systemPrompt ,
96+ } ) ,
12097 } ) ,
12198 )
12299 } )
123100
124101 it ( "should handle API errors" , async ( ) => {
125102 const mockError = new Error ( "Gemini API error" )
126- const mockGenerateContentStream = jest . fn ( ) . mockRejectedValue ( mockError )
127- const mockGetGenerativeModel = jest . fn ( ) . mockReturnValue ( {
128- generateContentStream : mockGenerateContentStream ,
129- } )
130-
131- ; ( handler [ "client" ] as any ) . getGenerativeModel = mockGetGenerativeModel
103+ ; ( handler [ "client" ] . models . generateContentStream as jest . Mock ) . mockRejectedValue ( mockError )
132104
133105 const stream = handler . createMessage ( systemPrompt , mockMessages )
134106
135107 await expect ( async ( ) => {
136108 for await ( const chunk of stream ) {
137109 // Should throw before yielding any chunks
138110 }
139- } ) . rejects . toThrow ( "Gemini API error" )
111+ } ) . rejects . toThrow ( )
140112 } )
141113 } )
142114
143115 describe ( "completePrompt" , ( ) => {
144116 it ( "should complete prompt successfully" , async ( ) => {
145- const mockGenerateContent = jest . fn ( ) . mockResolvedValue ( {
146- response : {
147- text : ( ) => "Test response" ,
148- } ,
149- } )
150- const mockGetGenerativeModel = jest . fn ( ) . mockReturnValue ( {
151- generateContent : mockGenerateContent ,
117+ // Mock the response with text property
118+ ; ( handler [ "client" ] . models . generateContent as jest . Mock ) . mockResolvedValue ( {
119+ text : "Test response" ,
152120 } )
153- ; ( handler [ "client" ] as any ) . getGenerativeModel = mockGetGenerativeModel
154121
155122 const result = await handler . completePrompt ( "Test prompt" )
156123 expect ( result ) . toBe ( "Test response" )
157- expect ( mockGetGenerativeModel ) . toHaveBeenCalledWith (
158- {
159- model : "gemini-2.0-flash-thinking-exp-1219" ,
160- } ,
161- {
162- baseUrl : undefined ,
163- } ,
164- )
165- expect ( mockGenerateContent ) . toHaveBeenCalledWith ( {
124+
125+ // Verify the call to generateContent
126+ expect ( handler [ "client" ] . models . generateContent ) . toHaveBeenCalledWith ( {
127+ model : GEMINI_20_FLASH_THINKING_NAME ,
166128 contents : [ { role : "user" , parts : [ { text : "Test prompt" } ] } ] ,
167- generationConfig : {
129+ config : {
130+ httpOptions : undefined ,
168131 temperature : 0 ,
169132 } ,
170133 } )
171134 } )
172135
173136 it ( "should handle API errors" , async ( ) => {
174137 const mockError = new Error ( "Gemini API error" )
175- const mockGenerateContent = jest . fn ( ) . mockRejectedValue ( mockError )
176- const mockGetGenerativeModel = jest . fn ( ) . mockReturnValue ( {
177- generateContent : mockGenerateContent ,
178- } )
179- ; ( handler [ "client" ] as any ) . getGenerativeModel = mockGetGenerativeModel
138+ ; ( handler [ "client" ] . models . generateContent as jest . Mock ) . mockRejectedValue ( mockError )
180139
181140 await expect ( handler . completePrompt ( "Test prompt" ) ) . rejects . toThrow (
182141 "Gemini completion error: Gemini API error" ,
183142 )
184143 } )
185144
186145 it ( "should handle empty response" , async ( ) => {
187- const mockGenerateContent = jest . fn ( ) . mockResolvedValue ( {
188- response : {
189- text : ( ) => "" ,
190- } ,
191- } )
192- const mockGetGenerativeModel = jest . fn ( ) . mockReturnValue ( {
193- generateContent : mockGenerateContent ,
146+ // Mock the response with empty text
147+ ; ( handler [ "client" ] . models . generateContent as jest . Mock ) . mockResolvedValue ( {
148+ text : "" ,
194149 } )
195- ; ( handler [ "client" ] as any ) . getGenerativeModel = mockGetGenerativeModel
196150
197151 const result = await handler . completePrompt ( "Test prompt" )
198152 expect ( result ) . toBe ( "" )
@@ -202,7 +156,7 @@ describe("GeminiHandler", () => {
202156 describe ( "getModel" , ( ) => {
203157 it ( "should return correct model info" , ( ) => {
204158 const modelInfo = handler . getModel ( )
205- expect ( modelInfo . id ) . toBe ( "gemini-2.0-flash-thinking-exp-1219" )
159+ expect ( modelInfo . id ) . toBe ( GEMINI_20_FLASH_THINKING_NAME )
206160 expect ( modelInfo . info ) . toBeDefined ( )
207161 expect ( modelInfo . info . maxTokens ) . toBe ( 8192 )
208162 expect ( modelInfo . info . contextWindow ) . toBe ( 32_767 )
@@ -214,7 +168,7 @@ describe("GeminiHandler", () => {
214168 geminiApiKey : "test-key" ,
215169 } )
216170 const modelInfo = invalidHandler . getModel ( )
217- expect ( modelInfo . id ) . toBe ( "gemini-2.0-flash-001" ) // Default model
171+ expect ( modelInfo . id ) . toBe ( geminiDefaultModelId ) // Default model
218172 } )
219173 } )
220174} )
0 commit comments