Spaces:
Paused
Paused
| import { jest, expect, describe, beforeEach, it } from '@jest/globals' | |
| import { Bot } from '../bot' | |
| import { Options, AIOptions } from '../options' | |
| // Mock chatgpt module | |
| jest.mock('chatgpt', () => ({ | |
| ChatGPTAPI: jest.fn().mockImplementation(() => ({ | |
| sendMessage: jest.fn(), | |
| })), | |
| ChatGPTError: class ChatGPTError extends Error { | |
| status?: number | |
| constructor(message: string, status?: number) { | |
| super(message) | |
| this.status = status | |
| } | |
| }, | |
| })) | |
| describe('Bot', () => { | |
| let options: Options | |
| let aiOptions: AIOptions | |
| beforeEach(() => { | |
| jest.clearAllMocks() | |
| options = new Options( | |
| false, false, false, '0', false, false, null, '', | |
| 'meta-llama/llama-4-scout-17b-16e-instruct', | |
| 'llama-3.3-70b-versatile', | |
| '0.0', '3', '120000', '1', '1', | |
| 'https://api.groq.com/openai/v1', 'en-US', false, 'minor', '0', 'false', 'true' | |
| ) | |
| aiOptions = new AIOptions('meta-llama/llama-4-scout-17b-16e-instruct') | |
| }) | |
| describe('constructor', () => { | |
| it('should throw error if API key is missing', () => { | |
| const originalKey = process.env.GROQ_API_KEY | |
| delete process.env.GROQ_API_KEY | |
| delete process.env.AI_API_KEY | |
| expect(() => new Bot(options, aiOptions)).toThrow("Missing 'GROQ_API_KEY' or 'AI_API_KEY'") | |
| process.env.GROQ_API_KEY = originalKey | |
| }) | |
| it('should initialize with valid API key', () => { | |
| const bot = new Bot(options, aiOptions) | |
| expect(bot).toBeInstanceOf(Bot) | |
| }) | |
| it('should set up fallback models for heavy models', () => { | |
| const heavyOptions = new AIOptions('llama-3.3-70b-versatile') | |
| const bot = new Bot(options, heavyOptions) | |
| expect(bot).toBeInstanceOf(Bot) | |
| }) | |
| }) | |
| describe('chat', () => { | |
| it('should return empty response for empty message', async () => { | |
| const bot = new Bot(options, aiOptions) | |
| const result = await bot.chat('', {}) | |
| expect(result).toEqual(['', {}]) | |
| }) | |
| it('should handle AI errors gracefully', async () => { | |
| const { ChatGPTAPI } = await import('chatgpt') | |
| const mockSendMessage = jest.fn().mockRejectedValue(new Error('API Error')) | |
| ;(ChatGPTAPI as jest.Mock).mockImplementation(() => ({ | |
| sendMessage: mockSendMessage, | |
| })) | |
| const bot = new Bot(options, aiOptions) | |
| const result = await bot.chat('test message', {}) | |
| expect(result[0]).toBe('') // Should return empty on error | |
| }) | |
| it('should implement retry logic on rate limit', async () => { | |
| const { ChatGPTAPI } = await import('chatgpt') | |
| const mockSendMessage = jest.fn() | |
| .mockRejectedValueOnce({ status: 429, message: 'Rate limited' }) | |
| .mockResolvedValueOnce({ text: 'Success', id: 'msg-1' }) | |
| ;(ChatGPTAPI as jest.Mock).mockImplementation(() => ({ | |
| sendMessage: mockSendMessage, | |
| })) | |
| const bot = new Bot(options, aiOptions) | |
| // Should switch to fallback model on 429 | |
| await bot.chat('test', {}) | |
| expect(mockSendMessage).toHaveBeenCalled() | |
| }) | |
| }) | |
| describe('fallback chain', () => { | |
| it('should cycle through fallback models on errors', () => { | |
| const heavyOptions = new AIOptions('llama-3.3-70b-versatile') | |
| const bot = new Bot(options, heavyOptions) | |
| // Fallback chain should be initialized | |
| expect(bot).toBeInstanceOf(Bot) | |
| }) | |
| }) | |
| }) | |