* chore: managing and maintaining models and threads in the cache * test: add tests for hooks
193 lines
5.2 KiB
TypeScript
193 lines
5.2 KiB
TypeScript
// useThreads.test.ts
|
|
|
|
import { renderHook, act } from '@testing-library/react'
|
|
import { useSetAtom } from 'jotai'
|
|
import { ExtensionTypeEnum } from '@janhq/core'
|
|
import { extensionManager } from '@/extension/ExtensionManager'
|
|
import useThreads from './useThreads'
|
|
import {
|
|
threadDataReadyAtom,
|
|
threadModelParamsAtom,
|
|
threadsAtom,
|
|
threadStatesAtom,
|
|
} from '@/helpers/atoms/Thread.atom'
|
|
|
|
// Mock the necessary dependencies
|
|
jest.mock('jotai', () => ({
|
|
useAtomValue: jest.fn(),
|
|
useSetAtom: jest.fn(),
|
|
useAtom: jest.fn(),
|
|
atom: jest.fn(),
|
|
}))
|
|
jest.mock('@/extension/ExtensionManager')
|
|
|
|
describe('useThreads', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
})
|
|
|
|
const mockThreads = [
|
|
{
|
|
id: 'thread1',
|
|
metadata: { lastMessage: 'Hello' },
|
|
assistants: [
|
|
{
|
|
model: {
|
|
parameters: { param1: 'value1' },
|
|
settings: { setting1: 'value1' },
|
|
},
|
|
},
|
|
],
|
|
},
|
|
{
|
|
id: 'thread2',
|
|
metadata: { lastMessage: 'Hi there' },
|
|
assistants: [
|
|
{
|
|
model: {
|
|
parameters: { param2: 'value2' },
|
|
settings: { setting2: 'value2' },
|
|
},
|
|
},
|
|
],
|
|
},
|
|
]
|
|
|
|
it('should fetch and set threads data', async () => {
|
|
// Mock Jotai hooks
|
|
const mockSetThreadStates = jest.fn()
|
|
const mockSetThreads = jest.fn()
|
|
const mockSetThreadModelRuntimeParams = jest.fn()
|
|
const mockSetThreadDataReady = jest.fn()
|
|
|
|
;(useSetAtom as jest.Mock).mockImplementation((atom) => {
|
|
switch (atom) {
|
|
case threadStatesAtom:
|
|
return mockSetThreadStates
|
|
case threadsAtom:
|
|
return mockSetThreads
|
|
case threadModelParamsAtom:
|
|
return mockSetThreadModelRuntimeParams
|
|
case threadDataReadyAtom:
|
|
return mockSetThreadDataReady
|
|
default:
|
|
return jest.fn()
|
|
}
|
|
})
|
|
|
|
// Mock extensionManager
|
|
const mockGetThreads = jest.fn().mockResolvedValue(mockThreads)
|
|
;(extensionManager.get as jest.Mock).mockReturnValue({
|
|
getThreads: mockGetThreads,
|
|
})
|
|
|
|
const { result } = renderHook(() => useThreads())
|
|
|
|
await act(async () => {
|
|
// Wait for useEffect to complete
|
|
})
|
|
|
|
// Assertions
|
|
expect(extensionManager.get).toHaveBeenCalledWith(
|
|
ExtensionTypeEnum.Conversational
|
|
)
|
|
expect(mockGetThreads).toHaveBeenCalled()
|
|
|
|
expect(mockSetThreadStates).toHaveBeenCalledWith({
|
|
thread1: {
|
|
hasMore: false,
|
|
waitingForResponse: false,
|
|
lastMessage: 'Hello',
|
|
},
|
|
thread2: {
|
|
hasMore: false,
|
|
waitingForResponse: false,
|
|
lastMessage: 'Hi there',
|
|
},
|
|
})
|
|
|
|
expect(mockSetThreads).toHaveBeenCalledWith(mockThreads)
|
|
|
|
expect(mockSetThreadModelRuntimeParams).toHaveBeenCalledWith({
|
|
thread1: { param1: 'value1', setting1: 'value1' },
|
|
thread2: { param2: 'value2', setting2: 'value2' },
|
|
})
|
|
|
|
expect(mockSetThreadDataReady).toHaveBeenCalledWith(true)
|
|
})
|
|
|
|
it('should handle empty threads', async () => {
|
|
// Mock empty threads
|
|
;(extensionManager.get as jest.Mock).mockReturnValue({
|
|
getThreads: jest.fn().mockResolvedValue([]),
|
|
})
|
|
|
|
const mockSetThreadStates = jest.fn()
|
|
const mockSetThreads = jest.fn()
|
|
const mockSetThreadModelRuntimeParams = jest.fn()
|
|
const mockSetThreadDataReady = jest.fn()
|
|
|
|
;(useSetAtom as jest.Mock).mockImplementation((atom) => {
|
|
switch (atom) {
|
|
case threadStatesAtom:
|
|
return mockSetThreadStates
|
|
case threadsAtom:
|
|
return mockSetThreads
|
|
case threadModelParamsAtom:
|
|
return mockSetThreadModelRuntimeParams
|
|
case threadDataReadyAtom:
|
|
return mockSetThreadDataReady
|
|
default:
|
|
return jest.fn()
|
|
}
|
|
})
|
|
|
|
const { result } = renderHook(() => useThreads())
|
|
|
|
await act(async () => {
|
|
// Wait for useEffect to complete
|
|
})
|
|
|
|
expect(mockSetThreadStates).toHaveBeenCalledWith({})
|
|
expect(mockSetThreads).toHaveBeenCalledWith([])
|
|
expect(mockSetThreadModelRuntimeParams).toHaveBeenCalledWith({})
|
|
expect(mockSetThreadDataReady).toHaveBeenCalledWith(true)
|
|
})
|
|
|
|
it('should handle missing ConversationalExtension', async () => {
|
|
// Mock missing ConversationalExtension
|
|
;(extensionManager.get as jest.Mock).mockReturnValue(null)
|
|
|
|
const mockSetThreadStates = jest.fn()
|
|
const mockSetThreads = jest.fn()
|
|
const mockSetThreadModelRuntimeParams = jest.fn()
|
|
const mockSetThreadDataReady = jest.fn()
|
|
|
|
;(useSetAtom as jest.Mock).mockImplementation((atom) => {
|
|
switch (atom) {
|
|
case threadStatesAtom:
|
|
return mockSetThreadStates
|
|
case threadsAtom:
|
|
return mockSetThreads
|
|
case threadModelParamsAtom:
|
|
return mockSetThreadModelRuntimeParams
|
|
case threadDataReadyAtom:
|
|
return mockSetThreadDataReady
|
|
default:
|
|
return jest.fn()
|
|
}
|
|
})
|
|
|
|
const { result } = renderHook(() => useThreads())
|
|
|
|
await act(async () => {
|
|
// Wait for useEffect to complete
|
|
})
|
|
|
|
expect(mockSetThreadStates).toHaveBeenCalledWith({})
|
|
expect(mockSetThreads).toHaveBeenCalledWith([])
|
|
expect(mockSetThreadModelRuntimeParams).toHaveBeenCalledWith({})
|
|
expect(mockSetThreadDataReady).toHaveBeenCalledWith(true)
|
|
})
|
|
})
|