UNPKG

ai-switcher

Version:

A package which helps you switch between AI APIs using configurations, so that code changes are not required.

97 lines (78 loc) 3.53 kB
// src/__tests__/AIClient.test.ts import { AIClient } from '../index'; import { AnthropicClient } from '../clients/anthropic'; import { OpenAIClient } from '../clients/openai'; import { Message, AIError } from '../types'; import { mockOpenAIClient, mockAnthropicClient } from './mocks'; jest.mock('../clients/anthropic', () => ({ AnthropicClient: jest.fn().mockImplementation(() => mockAnthropicClient) })); jest.mock('../clients/openai', () => ({ OpenAIClient: jest.fn().mockImplementation(() => mockOpenAIClient) })); describe('AIClient', () => { let client: AIClient; beforeEach(() => { jest.clearAllMocks(); client = new AIClient({ anthropicApiKey: 'test-anthropic-key', openaiApiKey: 'test-openai-key', defaultProvider: 'openai' }); }); describe('initialization', () => { it('should initialize with API keys', () => { expect(client).toBeInstanceOf(AIClient); }); it('should throw error when no API keys provided', () => { expect(() => new AIClient({})).toThrow('At least one provider API key must be provided'); }); }); describe('provider selection', () => { const messages: Message[] = [{ role: 'user' as const, content: 'test' }]; it('should use default provider when none specified', async () => { mockOpenAIClient.createCompletion.mockResolvedValue('test response'); await client.createCompletion(messages); expect(mockOpenAIClient.createCompletion).toHaveBeenCalled(); expect(mockAnthropicClient.createCompletion).not.toHaveBeenCalled(); }); it('should override default provider when specified in options', async () => { mockAnthropicClient.createCompletion.mockResolvedValue('test response'); await client.createCompletion(messages, { provider: 'anthropic' }); expect(mockAnthropicClient.createCompletion).toHaveBeenCalled(); expect(mockOpenAIClient.createCompletion).not.toHaveBeenCalled(); }); }); describe('createEmbedding', () => { it('should return embedding data using openai provider', async () => { mockOpenAIClient.createEmbedding.mockResolvedValue([0.1, 0.2, 0.3]); const result = await client.createEmbedding('test', 'openai'); expect(result).toEqual([0.1, 0.2, 0.3]); }); it('should throw error for anthropic provider', async () => { mockAnthropicClient.createEmbedding.mockRejectedValue(new Error('Embeddings not supported by Anthropic')); await expect(client.createEmbedding('test', 'anthropic')).rejects.toThrow('Embeddings not supported by Anthropic'); }); }); describe('error handling', () => { const messages: Message[] = [{ role: 'user' as const, content: 'test' }]; it('should handle rate limit errors', async () => { const error = new AIError('Rate limit exceeded', 'openai', 429); mockOpenAIClient.createCompletion.mockRejectedValue(error); await expect(client.createCompletion(messages)).rejects.toMatchObject({ message: expect.stringContaining('Rate limit exceeded'), provider: 'openai', statusCode: 429 }); }); it('should handle authentication errors', async () => { const error = new AIError('Invalid API key', 'openai', 401); mockOpenAIClient.createCompletion.mockRejectedValue(error); await expect(client.createCompletion(messages)).rejects.toMatchObject({ message: expect.stringContaining('Invalid API key'), provider: 'openai', statusCode: 401 }); }); }); });