mirror of https://github.com/buster-so/buster.git
220 lines
6.8 KiB
TypeScript
220 lines
6.8 KiB
TypeScript
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();
|
|
});
|
|
});
|