UNPKG

@rolme/ytscript

Version:

A CLI tool to download YouTube transcripts and generate summaries

106 lines (105 loc) 4.66 kB
import { describe, it, expect, vi, beforeEach } from 'vitest'; import { ClaudeProvider } from '../../../../services/providers/claude.js'; import { AIError } from '../../../../types/ai.js'; describe('ClaudeProvider', () => { let provider; beforeEach(() => { provider = new ClaudeProvider('test-anthropic-key'); vi.clearAllMocks(); global.fetch = vi.fn(); }); describe('initialization', () => { it('should create instance with API key', () => { expect(provider).toBeInstanceOf(ClaudeProvider); expect(provider.name).toBe('claude'); }); it('should throw error if API key is missing', () => { expect(() => new ClaudeProvider('')).toThrow('Anthropic API key is required'); }); }); describe('summarize', () => { const mockTranscript = 'Sample transcript for summarization'; const mockResponse = { content: [ { text: 'Generated summary of the video' } ] }; it('should generate summary successfully with default options', async () => { global.fetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(mockResponse) }); const result = await provider.summarize(mockTranscript); expect(result).toBe(mockResponse.content[0].text); expect(global.fetch).toHaveBeenCalledWith('https://api.anthropic.com/v1/messages', expect.objectContaining({ method: 'POST', headers: { 'x-api-key': 'test-anthropic-key', 'anthropic-version': '2023-06-01', 'Content-Type': 'application/json', 'anthropic-client': 'ytscript/2.0.2' }, body: expect.stringContaining('concise') })); }); it('should use provided style and length options', async () => { global.fetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(mockResponse) }); await provider.summarize(mockTranscript, { style: 'detailed', maxLength: 1000 }); const requestBody = JSON.parse(global.fetch.mock.calls[0][1].body); expect(requestBody.messages[0].content).toContain('detailed'); expect(requestBody.messages[0].content).toContain('1000'); }); it('should handle API errors gracefully', async () => { global.fetch = vi.fn().mockResolvedValue({ ok: false, statusText: 'Rate limit exceeded' }); await expect(provider.summarize(mockTranscript)).rejects.toThrow(AIError); }); it('should handle network errors', async () => { global.fetch = vi.fn().mockRejectedValue(new Error('Network Error')); await expect(provider.summarize(mockTranscript)).rejects.toThrow(AIError); }); it('should handle invalid API response', async () => { global.fetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ content: [] }) }); await expect(provider.summarize(mockTranscript)).rejects.toThrow('Invalid response from Claude API'); }); it('should use correct model and parameters', async () => { global.fetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(mockResponse) }); await provider.summarize(mockTranscript); const requestBody = JSON.parse(global.fetch.mock.calls[0][1].body); expect(requestBody).toEqual(expect.objectContaining({ model: 'claude-3-opus-20240229', max_tokens: 1000, messages: expect.arrayContaining([ expect.objectContaining({ role: 'user' }) ]) })); }); it('should include key points instruction in prompt', async () => { global.fetch = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve(mockResponse) }); await provider.summarize(mockTranscript); const requestBody = JSON.parse(global.fetch.mock.calls[0][1].body); expect(requestBody.messages[0].content).toContain('Focus on extracting the key points and main ideas'); }); }); });