import { beforeEach, describe, expect, test, vi } from 'vitest'; import { useAIStore } from './aiStore'; function mockElectronAPI() { (window as any).electronAPI = { encryptString: vi.fn().mockResolvedValue('encrypted-value'), decryptString: vi.fn().mockResolvedValue('decrypted-key'), }; } describe('aiStore', () => { beforeEach(() => { mockElectronAPI(); useAIStore.setState({ providers: { ollama: { provider: 'ollama', baseUrl: 'http://localhost:11434', model: 'llama3' }, openai: { provider: 'openai', apiKey: '', model: 'gpt-4o' }, claude: { provider: 'claude', apiKey: '', model: 'claude-sonnet-4-20250514' }, }, defaultProvider: 'ollama', customFillerWords: '', fillerResult: null, clipSuggestions: [], isProcessing: false, processingMessage: '', _keysHydrated: false, }); }); describe('setProviderConfig', () => { test('updates Ollama base URL', () => { useAIStore.getState().setProviderConfig('ollama', { baseUrl: 'http://custom:11434' }); expect(useAIStore.getState().providers.ollama.baseUrl).toBe('http://custom:11434'); }); test('updates Ollama model', () => { useAIStore.getState().setProviderConfig('ollama', { model: 'llama3.2' }); expect(useAIStore.getState().providers.ollama.model).toBe('llama3.2'); }); test('updates OpenAI apiKey and encrypts', async () => { useAIStore.getState().setProviderConfig('openai', { apiKey: 'sk-test123' }); expect(useAIStore.getState().providers.openai.apiKey).toBe('sk-test123'); expect((window as any).electronAPI.encryptString).toHaveBeenCalledWith('sk-test123'); }); test('updates Claude model', () => { useAIStore.getState().setProviderConfig('claude', { model: 'claude-opus-4-20250514' }); expect(useAIStore.getState().providers.claude.model).toBe('claude-opus-4-20250514'); }); test('preserves existing config when updating partial fields', () => { useAIStore.getState().setProviderConfig('openai', { apiKey: 'sk-new', model: 'gpt-4o-mini' }); expect(useAIStore.getState().providers.openai.apiKey).toBe('sk-new'); expect(useAIStore.getState().providers.openai.model).toBe('gpt-4o-mini'); }); }); describe('setDefaultProvider', () => { test('changes default provider', () => { useAIStore.getState().setDefaultProvider('openai'); expect(useAIStore.getState().defaultProvider).toBe('openai'); }); test('can switch to claude', () => { useAIStore.getState().setDefaultProvider('claude'); expect(useAIStore.getState().defaultProvider).toBe('claude'); }); }); describe('setCustomFillerWords', () => { test('sets custom filler words', () => { useAIStore.getState().setCustomFillerWords('okay, alright, anyway'); expect(useAIStore.getState().customFillerWords).toBe('okay, alright, anyway'); }); test('clears custom filler words', () => { useAIStore.getState().setCustomFillerWords('test'); useAIStore.getState().setCustomFillerWords(''); expect(useAIStore.getState().customFillerWords).toBe(''); }); }); describe('setFillerResult', () => { test('sets filler result', () => { const result = { fillers: [{ word: 'um', start: 1.0, end: 1.3 }], totalCount: 1 }; useAIStore.getState().setFillerResult(result as any); expect(useAIStore.getState().fillerResult).toEqual(result); }); test('clears filler result', () => { useAIStore.getState().setFillerResult({ fillers: [], totalCount: 0 } as any); useAIStore.getState().setFillerResult(null); expect(useAIStore.getState().fillerResult).toBeNull(); }); }); describe('setProcessing', () => { test('sets processing true with message', () => { useAIStore.getState().setProcessing(true, 'Analyzing transcript...'); expect(useAIStore.getState().isProcessing).toBe(true); expect(useAIStore.getState().processingMessage).toBe('Analyzing transcript...'); }); test('sets processing false', () => { useAIStore.getState().setProcessing(true, 'Working...'); useAIStore.getState().setProcessing(false); expect(useAIStore.getState().isProcessing).toBe(false); }); }); describe('setClipSuggestions', () => { test('sets clip suggestions', () => { const clips = [{ title: 'Best moment', start: 10, end: 40, reason: 'Engaging' }]; useAIStore.getState().setClipSuggestions(clips as any); expect(useAIStore.getState().clipSuggestions).toEqual(clips); }); test('clears clip suggestions', () => { useAIStore.getState().setClipSuggestions([{ title: 'x', start: 0, end: 10, reason: 'y' }] as any); useAIStore.getState().setClipSuggestions([]); expect(useAIStore.getState().clipSuggestions).toEqual([]); }); }); });