* add delete all threads * add testcase * add testcase * fix lint * fix linter * fix linter * change position Delete All Threads
165 lines
5.3 KiB
TypeScript
165 lines
5.3 KiB
TypeScript
/**
|
|
* @jest-environment jsdom
|
|
*/
|
|
|
|
import { renderHook, act } from '@testing-library/react'
|
|
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
|
|
import useDeleteThread from './useDeleteThread'
|
|
import { extensionManager } from '@/extension/ExtensionManager'
|
|
import { useCreateNewThread } from './useCreateNewThread'
|
|
import { Thread } from '@janhq/core/dist/types/types'
|
|
import { currentPromptAtom } from '@/containers/Providers/Jotai'
|
|
import { setActiveThreadIdAtom, deleteThreadStateAtom } from '@/helpers/atoms/Thread.atom'
|
|
import { deleteChatMessageAtom as deleteChatMessagesAtom } from '@/helpers/atoms/ChatMessage.atom'
|
|
// Mock the necessary dependencies
|
|
// Mock dependencies
|
|
jest.mock('jotai', () => ({
|
|
useAtomValue: jest.fn(),
|
|
useSetAtom: jest.fn(),
|
|
useAtom: jest.fn(),
|
|
atom: jest.fn(),
|
|
}))
|
|
jest.mock('./useCreateNewThread')
|
|
jest.mock('@/extension/ExtensionManager')
|
|
jest.mock('@/containers/Toast')
|
|
|
|
describe('useDeleteThread', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
})
|
|
|
|
it('should delete a thread successfully', async () => {
|
|
const mockThreads = [
|
|
{ id: 'thread1', title: 'Thread 1' },
|
|
{ id: 'thread2', title: 'Thread 2' },
|
|
]
|
|
const mockSetThreads = jest.fn()
|
|
;(useAtom as jest.Mock).mockReturnValue([mockThreads, mockSetThreads])
|
|
;(useSetAtom as jest.Mock).mockReturnValue(() => {})
|
|
;(useCreateNewThread as jest.Mock).mockReturnValue({})
|
|
|
|
const mockDeleteThread = jest.fn().mockImplementation(() => ({
|
|
catch: () => jest.fn,
|
|
}))
|
|
|
|
extensionManager.get = jest.fn().mockReturnValue({
|
|
deleteThread: mockDeleteThread,
|
|
})
|
|
|
|
const { result } = renderHook(() => useDeleteThread())
|
|
|
|
await act(async () => {
|
|
await result.current.deleteThread('thread1')
|
|
})
|
|
|
|
expect(mockDeleteThread).toHaveBeenCalledWith('thread1')
|
|
expect(mockSetThreads).toHaveBeenCalledWith([mockThreads[1]])
|
|
})
|
|
|
|
it('should clean a thread successfully', async () => {
|
|
const mockThreads = [{ id: 'thread1', title: 'Thread 1', metadata: {} }]
|
|
const mockSetThreads = jest.fn()
|
|
;(useAtom as jest.Mock).mockReturnValue([mockThreads, mockSetThreads])
|
|
const mockCleanMessages = jest.fn()
|
|
;(useSetAtom as jest.Mock).mockReturnValue(() => mockCleanMessages)
|
|
;(useAtomValue as jest.Mock).mockReturnValue(['thread 1'])
|
|
|
|
const mockSaveThread = jest.fn()
|
|
const mockDeleteMessage = jest.fn().mockResolvedValue({})
|
|
const mockModifyThread = jest.fn().mockResolvedValue({})
|
|
extensionManager.get = jest.fn().mockReturnValue({
|
|
saveThread: mockSaveThread,
|
|
getThreadAssistant: jest.fn().mockResolvedValue({}),
|
|
listMessages: jest.fn().mockResolvedValue([
|
|
{
|
|
id: 'message1',
|
|
text: 'Message 1',
|
|
},
|
|
]),
|
|
deleteMessage: mockDeleteMessage,
|
|
modifyThread: mockModifyThread,
|
|
})
|
|
|
|
const { result } = renderHook(() => useDeleteThread())
|
|
|
|
await act(async () => {
|
|
await result.current.cleanThread('thread1')
|
|
})
|
|
|
|
expect(mockDeleteMessage).toHaveBeenCalled()
|
|
expect(mockModifyThread).toHaveBeenCalled()
|
|
})
|
|
|
|
it('should handle errors when deleting a thread', async () => {
|
|
const mockThreads = [{ id: 'thread1', title: 'Thread 1' }]
|
|
const mockSetThreads = jest.fn()
|
|
;(useAtom as jest.Mock).mockReturnValue([mockThreads, mockSetThreads])
|
|
const mockCreateNewThread = jest.fn()
|
|
;(useCreateNewThread as jest.Mock).mockReturnValue({
|
|
requestCreateNewThread: mockCreateNewThread,
|
|
})
|
|
|
|
const mockDeleteThread = jest
|
|
.fn()
|
|
.mockRejectedValue(new Error('Delete error'))
|
|
extensionManager.get = jest.fn().mockReturnValue({
|
|
deleteThread: mockDeleteThread,
|
|
})
|
|
|
|
const consoleErrorSpy = jest
|
|
.spyOn(console, 'error')
|
|
.mockImplementation(() => {})
|
|
|
|
const { result } = renderHook(() => useDeleteThread())
|
|
|
|
await act(async () => {
|
|
await result.current.deleteThread('thread1')
|
|
})
|
|
|
|
expect(mockDeleteThread).toHaveBeenCalledWith('thread1')
|
|
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.any(Error))
|
|
|
|
consoleErrorSpy.mockRestore()
|
|
})
|
|
|
|
it('should delete all threads successfully', async () => {
|
|
const mockThreads = [
|
|
{ id: 'thread1', title: 'Thread 1' },
|
|
{ id: 'thread2', title: 'Thread 2' },
|
|
]
|
|
const mockSetThreads = jest.fn()
|
|
;(useAtom as jest.Mock).mockReturnValue([mockThreads, mockSetThreads])
|
|
|
|
// create mock functions
|
|
const mockSetCurrentPrompt = jest.fn()
|
|
|
|
// mock useSetAtom for each atom
|
|
let currentAtom: any
|
|
;(useSetAtom as jest.Mock).mockImplementation((atom) => {
|
|
currentAtom = atom
|
|
if (currentAtom === currentPromptAtom) return mockSetCurrentPrompt
|
|
return jest.fn()
|
|
})
|
|
|
|
const mockDeleteThread = jest.fn().mockImplementation(() => ({
|
|
catch: () => jest.fn,
|
|
}))
|
|
|
|
extensionManager.get = jest.fn().mockReturnValue({
|
|
deleteThread: mockDeleteThread,
|
|
})
|
|
|
|
const { result } = renderHook(() => useDeleteThread())
|
|
|
|
await act(async () => {
|
|
await result.current.deleteAllThreads(mockThreads as Thread[])
|
|
})
|
|
|
|
expect(mockDeleteThread).toHaveBeenCalledTimes(2)
|
|
expect(mockDeleteThread).toHaveBeenCalledWith('thread1')
|
|
expect(mockDeleteThread).toHaveBeenCalledWith('thread2')
|
|
expect(mockSetThreads).toHaveBeenCalledWith([])
|
|
expect(mockSetCurrentPrompt).toHaveBeenCalledWith('')
|
|
})
|
|
})
|