import { useBusterNewChatContextSelector } from '@/context/Chats'; import { useChatIndividualContextSelector } from '@/layouts/ChatLayout/ChatContext'; import { renderHook } from '@testing-library/react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { useChatInputFlow } from './useChatInputFlow'; // Mock the context selectors vi.mock('@/layouts/ChatLayout/ChatContext', () => ({ useChatIndividualContextSelector: vi.fn() })); vi.mock('@/context/Chats', () => ({ useBusterNewChatContextSelector: vi.fn() })); describe('useChatInputFlow', () => { const mockSetInputValue = vi.fn(); const mockTextAreaRef = { current: { focus: vi.fn(), select: vi.fn(), value: '', type: 'textarea' } as unknown as HTMLTextAreaElement }; const mockOnStartNewChat = vi.fn(); const mockOnFollowUpChat = vi.fn(); const mockOnStartChatFromFile = vi.fn(); const mockOnStopChat = vi.fn(); beforeEach(() => { vi.clearAllMocks(); (useBusterNewChatContextSelector as any).mockImplementation((selector: any) => { const state = { onStartNewChat: mockOnStartNewChat, onFollowUpChat: mockOnFollowUpChat, onStartChatFromFile: mockOnStartChatFromFile, onStopChat: mockOnStopChat }; return selector(state); }); }); const defaultProps = { disableSubmit: false, inputValue: 'test message', setInputValue: mockSetInputValue, textAreaRef: mockTextAreaRef, loading: false }; it('should handle followup-chat flow', async () => { (useChatIndividualContextSelector as any).mockImplementation((selector: any) => { const state = { hasChat: true, chatId: 'test-chat-id', currentMessageId: 'test-message-id', selectedFileType: null, selectedFileId: null }; return selector(state); }); const { result } = renderHook(() => useChatInputFlow(defaultProps)); await result.current.onSubmitPreflight(); await new Promise((resolve) => setTimeout(resolve, 50)); expect(mockOnFollowUpChat).toHaveBeenCalledWith({ prompt: 'test message', chatId: 'test-chat-id' }); expect(mockSetInputValue).toHaveBeenCalledWith(''); expect(mockTextAreaRef.current.focus).toHaveBeenCalled(); }); it('should handle followup-metric flow', async () => { (useChatIndividualContextSelector as any).mockImplementation((selector: any) => { const state = { hasChat: false, chatId: 'test-chat-id', currentMessageId: 'test-message-id', selectedFileType: 'metric', selectedFileId: 'test-metric-id' }; return selector(state); }); const { result } = renderHook(() => useChatInputFlow(defaultProps)); await result.current.onSubmitPreflight(); await new Promise((resolve) => setTimeout(resolve, 50)); expect(mockOnStartChatFromFile).toHaveBeenCalledWith({ prompt: 'test message', fileId: 'test-metric-id', fileType: 'metric' }); expect(mockSetInputValue).toHaveBeenCalledWith(''); expect(mockTextAreaRef.current.focus).toHaveBeenCalled(); }); it('should handle followup-dashboard flow', async () => { (useChatIndividualContextSelector as any).mockImplementation((selector: any) => { const state = { hasChat: false, chatId: 'test-chat-id', currentMessageId: 'test-message-id', selectedFileType: 'dashboard', selectedFileId: 'test-dashboard-id' }; return selector(state); }); const { result } = renderHook(() => useChatInputFlow(defaultProps)); await result.current.onSubmitPreflight(); await new Promise((resolve) => setTimeout(resolve, 50)); expect(mockOnStartChatFromFile).toHaveBeenCalledWith({ prompt: 'test message', fileId: 'test-dashboard-id', fileType: 'dashboard' }); expect(mockSetInputValue).toHaveBeenCalledWith(''); expect(mockTextAreaRef.current.focus).toHaveBeenCalled(); }); it('should handle new chat flow', async () => { (useChatIndividualContextSelector as any).mockImplementation((selector: any) => { const state = { hasChat: false, chatId: 'test-chat-id', currentMessageId: 'test-message-id', selectedFileType: null, selectedFileId: null }; return selector(state); }); const { result } = renderHook(() => useChatInputFlow(defaultProps)); await result.current.onSubmitPreflight(); await new Promise((resolve) => setTimeout(resolve, 50)); expect(mockOnStartNewChat).toHaveBeenCalledWith({ prompt: 'test message' }); expect(mockSetInputValue).toHaveBeenCalledWith(''); expect(mockTextAreaRef.current.focus).toHaveBeenCalled(); }); it('should handle stop chat', () => { (useChatIndividualContextSelector as any).mockImplementation((selector: any) => { const state = { hasChat: true, chatId: 'test-chat-id', currentMessageId: 'test-message-id', selectedFileType: null, selectedFileId: null }; return selector(state); }); const { result } = renderHook(() => useChatInputFlow(defaultProps)); result.current.onStopChat(); expect(mockOnStopChat).toHaveBeenCalledWith({ chatId: 'test-chat-id', messageId: 'test-message-id' }); expect(mockTextAreaRef.current.focus).toHaveBeenCalled(); expect(mockTextAreaRef.current.select).toHaveBeenCalled(); }); it('should not submit when disabled', async () => { (useChatIndividualContextSelector as any).mockImplementation((selector: any) => { const state = { hasChat: true, chatId: 'test-chat-id', currentMessageId: 'test-message-id', selectedFileType: null, selectedFileId: null }; return selector(state); }); const { result } = renderHook(() => useChatInputFlow({ ...defaultProps, disableSubmit: true })); await result.current.onSubmitPreflight(); expect(mockOnFollowUpChat).not.toHaveBeenCalled(); expect(mockSetInputValue).not.toHaveBeenCalled(); expect(mockTextAreaRef.current.focus).not.toHaveBeenCalled(); }); it('should stop chat when loading', async () => { (useChatIndividualContextSelector as any).mockImplementation((selector: any) => { const state = { hasChat: true, chatId: 'test-chat-id', currentMessageId: 'test-message-id', selectedFileType: null, selectedFileId: null }; return selector(state); }); const { result } = renderHook(() => useChatInputFlow({ ...defaultProps, loading: true })); await result.current.onSubmitPreflight(); await new Promise((resolve) => setTimeout(resolve, 50)); expect(mockOnStopChat).toHaveBeenCalled(); expect(mockOnFollowUpChat).not.toHaveBeenCalled(); expect(mockSetInputValue).not.toHaveBeenCalled(); }); });