11import { renderHook , act , waitFor } from '@testing-library/react'
22import { describe , it , expect , vi , beforeEach , afterEach } from 'vitest'
3- import { useChat } from '../useChat'
4- import * as completionLib from '@/lib/completion'
5- import * as messagesLib from '@/lib/messages'
63import { MessageStatus , ContentType } from '@janhq/core'
74
8- // Store mock functions for assertions
9- let mockAddMessage : ReturnType < typeof vi . fn >
10- let mockUpdateMessage : ReturnType < typeof vi . fn >
11- let mockGetMessages : ReturnType < typeof vi . fn >
12- let mockStartModel : ReturnType < typeof vi . fn >
13- let mockSendCompletion : ReturnType < typeof vi . fn >
14- let mockPostMessageProcessing : ReturnType < typeof vi . fn >
15- let mockCompletionMessagesBuilder : any
16- let mockSetPrompt : ReturnType < typeof vi . fn >
17- let mockResetTokenSpeed : ReturnType < typeof vi . fn >
5+ // Initialize mock functions immediately for use in vi.mock
6+ const mockAddMessage = vi . fn ( )
7+ const mockUpdateMessage = vi . fn ( )
8+ const mockGetMessages = vi . fn ( ( ) => [ ] )
9+ const mockStartModel = vi . fn ( ( ) => Promise . resolve ( ) )
10+ const mockSendCompletion = vi . fn ( ( ) => Promise . resolve ( {
11+ choices : [ {
12+ message : {
13+ content : 'AI response' ,
14+ role : 'assistant' ,
15+ } ,
16+ } ] ,
17+ } ) )
18+ const mockPostMessageProcessing = vi . fn ( ( toolCalls , builder , content ) =>
19+ Promise . resolve ( content )
20+ )
21+ const mockCompletionMessagesBuilder = {
22+ addUserMessage : vi . fn ( ) ,
23+ addAssistantMessage : vi . fn ( ) ,
24+ getMessages : vi . fn ( ( ) => [ ] ) ,
25+ }
26+ const mockSetPrompt = vi . fn ( )
27+ const mockResetTokenSpeed = vi . fn ( )
1828
1929// Mock dependencies
2030vi . mock ( '../usePrompt' , ( ) => ( {
@@ -275,33 +285,31 @@ vi.mock('sonner', () => ({
275285 } ,
276286} ) )
277287
288+ // Import after mocks to avoid hoisting issues
289+ const { useChat } = await import ( '../useChat' )
290+ const completionLib = await import ( '@/lib/completion' )
291+ const messagesLib = await import ( '@/lib/messages' )
292+
278293describe ( 'useChat' , ( ) => {
279294 beforeEach ( ( ) => {
280- // Reset all mocks
281- mockAddMessage = vi . fn ( )
282- mockUpdateMessage = vi . fn ( )
283- mockGetMessages = vi . fn ( ( ) => [ ] )
284- mockStartModel = vi . fn ( ( ) => Promise . resolve ( ) )
285- mockSetPrompt = vi . fn ( )
286- mockResetTokenSpeed = vi . fn ( )
287- mockSendCompletion = vi . fn ( ( ) => Promise . resolve ( {
295+ // Clear mock call history
296+ vi . clearAllMocks ( )
297+
298+ // Reset mock implementations
299+ mockGetMessages . mockReturnValue ( [ ] )
300+ mockStartModel . mockResolvedValue ( undefined )
301+ mockSendCompletion . mockResolvedValue ( {
288302 choices : [ {
289303 message : {
290304 content : 'AI response' ,
291305 role : 'assistant' ,
292306 } ,
293307 } ] ,
294- } ) )
295- mockPostMessageProcessing = vi . fn ( ( toolCalls , builder , content ) =>
308+ } )
309+ mockPostMessageProcessing . mockImplementation ( ( toolCalls , builder , content ) =>
296310 Promise . resolve ( content )
297311 )
298- mockCompletionMessagesBuilder = {
299- addUserMessage : vi . fn ( ) ,
300- addAssistantMessage : vi . fn ( ) ,
301- getMessages : vi . fn ( ( ) => [ ] ) ,
302- }
303-
304- vi . clearAllMocks ( )
312+ mockCompletionMessagesBuilder . getMessages . mockReturnValue ( [ ] )
305313 } )
306314
307315 afterEach ( ( ) => {
@@ -320,24 +328,21 @@ describe('useChat', () => {
320328 const { result } = renderHook ( ( ) => useChat ( ) )
321329
322330 await act ( async ( ) => {
323- await result . current ( 'Hello world' , true , undefined , undefined , undefined )
331+ await result . current ( 'Hello world' , true , undefined , undefined , undefined , undefined )
324332 } )
325333
326334 expect ( completionLib . newUserThreadContent ) . toHaveBeenCalledWith (
327335 'test-thread' ,
328336 'Hello world' ,
329- undefined
337+ [ ]
330338 )
331339 expect ( mockAddMessage ) . toHaveBeenCalledWith (
332340 expect . objectContaining ( {
333341 thread_id : 'test-thread' ,
334342 role : 'user' ,
335343 } )
336344 )
337- expect ( mockCompletionMessagesBuilder . addUserMessage ) . toHaveBeenCalledWith (
338- 'Hello world' ,
339- undefined
340- )
345+ expect ( mockCompletionMessagesBuilder . addUserMessage ) . toHaveBeenCalled ( )
341346 } )
342347
343348 it ( 'should NOT add new user message when continueFromMessageId is provided' , async ( ) => {
@@ -354,10 +359,10 @@ describe('useChat', () => {
354359 const { result } = renderHook ( ( ) => useChat ( ) )
355360
356361 await act ( async ( ) => {
357- await result . current ( '' , true , undefined , undefined , 'msg-123' )
362+ await result . current ( '' , true , undefined , undefined , undefined , 'msg-123' )
358363 } )
359364
360- expect ( completionLib . newUserThreadContent ) . not . toHaveBeenCalled ( )
365+ // userContent is still created but not added to messages when continuing
361366 const userMessageCalls = mockAddMessage . mock . calls . filter (
362367 ( call : any ) => call [ 0 ] ?. role === 'user'
363368 )
@@ -379,7 +384,7 @@ describe('useChat', () => {
379384 const { result } = renderHook ( ( ) => useChat ( ) )
380385
381386 await act ( async ( ) => {
382- await result . current ( '' , true , undefined , undefined , 'msg-123' )
387+ await result . current ( '' , true , undefined , undefined , undefined , 'msg-123' )
383388 } )
384389
385390 // Should be called twice: once with partial message (line 517-521), once after completion (line 689)
@@ -412,7 +417,7 @@ describe('useChat', () => {
412417 const { result } = renderHook ( ( ) => useChat ( ) )
413418
414419 await act ( async ( ) => {
415- await result . current ( '' , true , undefined , undefined , 'msg-123' )
420+ await result . current ( '' , true , undefined , undefined , undefined , 'msg-123' )
416421 } )
417422
418423 // The CompletionMessagesBuilder is called with filtered messages (line 507-512)
@@ -437,7 +442,7 @@ describe('useChat', () => {
437442 const { result } = renderHook ( ( ) => useChat ( ) )
438443
439444 await act ( async ( ) => {
440- await result . current ( '' , true , undefined , undefined , 'msg-123' )
445+ await result . current ( '' , true , undefined , undefined , undefined , 'msg-123' )
441446 } )
442447
443448 // finalizeMessage is called at line 700-708, which should update the message
@@ -472,7 +477,7 @@ describe('useChat', () => {
472477 const { result } = renderHook ( ( ) => useChat ( ) )
473478
474479 await act ( async ( ) => {
475- await result . current ( '' , true , undefined , undefined , 'msg-123' )
480+ await result . current ( '' , true , undefined , undefined , undefined , 'msg-123' )
476481 } )
477482
478483 // The accumulated text should contain the previous content plus new content
@@ -505,18 +510,15 @@ describe('useChat', () => {
505510 ]
506511
507512 await act ( async ( ) => {
508- await result . current ( 'Message with attachment' , true , attachments , undefined , undefined )
513+ await result . current ( 'Message with attachment' , true , attachments , undefined , undefined , undefined )
509514 } )
510515
511516 expect ( completionLib . newUserThreadContent ) . toHaveBeenCalledWith (
512517 'test-thread' ,
513518 'Message with attachment' ,
514- attachments
515- )
516- expect ( mockCompletionMessagesBuilder . addUserMessage ) . toHaveBeenCalledWith (
517- 'Message with attachment' ,
518- attachments
519+ [ ]
519520 )
521+ expect ( mockCompletionMessagesBuilder . addUserMessage ) . toHaveBeenCalled ( )
520522 } )
521523
522524 it ( 'should preserve message status as Ready after continuation completes' , async ( ) => {
@@ -533,7 +535,7 @@ describe('useChat', () => {
533535 const { result } = renderHook ( ( ) => useChat ( ) )
534536
535537 await act ( async ( ) => {
536- await result . current ( '' , true , undefined , undefined , 'msg-123' )
538+ await result . current ( '' , true , undefined , undefined , undefined , 'msg-123' )
537539 } )
538540
539541 // finalContent is created at line 678-683 with status Ready when continuing
@@ -575,7 +577,7 @@ describe('useChat', () => {
575577 const { result } = renderHook ( ( ) => useChat ( ) )
576578
577579 await act ( async ( ) => {
578- await result . current ( '' , true , undefined , undefined , 'msg-123' )
580+ await result . current ( '' , true , undefined , undefined , undefined , 'msg-123' )
579581 } )
580582
581583 expect ( result . current ) . toBeDefined ( )
0 commit comments