diff --git a/__tests__/AIClasses/BaseAIClass.test.ts b/__tests__/AIClasses/BaseAIClass.test.ts index 563b499..d6b9f80 100644 --- a/__tests__/AIClasses/BaseAIClass.test.ts +++ b/__tests__/AIClasses/BaseAIClass.test.ts @@ -48,7 +48,8 @@ describe('BaseAIClass Shared Methods', () => { if (provider === AIProvider.Gemini) return 'test-gemini-key'; return ''; }), - getApiKeyForCurrentModel: vi.fn(() => 'test-claude-key') + getApiKeyForCurrentModel: vi.fn(() => 'test-claude-key'), + subscribeToSettingsChanged: vi.fn() }; RegisterSingleton(Services.SettingsService, mockSettingsService); diff --git a/__tests__/AIClasses/Claude.test.ts b/__tests__/AIClasses/Claude.test.ts index c3edd1d..98b3e3a 100644 --- a/__tests__/AIClasses/Claude.test.ts +++ b/__tests__/AIClasses/Claude.test.ts @@ -52,7 +52,8 @@ describe('Claude', () => { if (provider === AIProvider.Gemini) return 'test-gemini-key'; return ''; }), - getApiKeyForCurrentModel: vi.fn(() => 'test-claude-key') + getApiKeyForCurrentModel: vi.fn(() => 'test-claude-key'), + subscribeToSettingsChanged: vi.fn() }; RegisterSingleton(Services.SettingsService, mockSettingsService); diff --git a/__tests__/AIClasses/CrossProviderIntegration.test.ts b/__tests__/AIClasses/CrossProviderIntegration.test.ts index 6924b7c..e8beee5 100644 --- a/__tests__/AIClasses/CrossProviderIntegration.test.ts +++ b/__tests__/AIClasses/CrossProviderIntegration.test.ts @@ -61,7 +61,8 @@ describe('Cross-Provider Integration - Thought Signature Support', () => { if (provider === AIProvider.Gemini) return 'test-gemini-key'; return ''; }), - getApiKeyForCurrentModel: vi.fn(() => 'test-gemini-key') + getApiKeyForCurrentModel: vi.fn(() => 'test-gemini-key'), + subscribeToSettingsChanged: vi.fn() }; RegisterSingleton(Services.SettingsService, mockSettingsService); diff --git a/__tests__/AIClasses/Gemini.test.ts b/__tests__/AIClasses/Gemini.test.ts index e82cca1..bec825b 100644 --- a/__tests__/AIClasses/Gemini.test.ts +++ b/__tests__/AIClasses/Gemini.test.ts @@ -50,7 +50,8 @@ describe('Gemini', () => { if (provider === AIProvider.Gemini) return 'test-gemini-key'; return ''; }), - getApiKeyForCurrentModel: vi.fn(() => 'test-gemini-key') + getApiKeyForCurrentModel: vi.fn(() => 'test-gemini-key'), + subscribeToSettingsChanged: vi.fn() }; RegisterSingleton(Services.SettingsService, mockSettingsService); diff --git a/__tests__/AIClasses/Mistral.test.ts b/__tests__/AIClasses/Mistral.test.ts index 8874441..3c9bdcf 100644 --- a/__tests__/AIClasses/Mistral.test.ts +++ b/__tests__/AIClasses/Mistral.test.ts @@ -53,7 +53,8 @@ describe('Mistral', () => { if (provider === AIProvider.Mistral) return 'test-mistral-key'; return ''; }), - getApiKeyForCurrentModel: vi.fn(() => 'test-mistral-key') + getApiKeyForCurrentModel: vi.fn(() => 'test-mistral-key'), + subscribeToSettingsChanged: vi.fn() }; RegisterSingleton(Services.SettingsService, mockSettingsService); diff --git a/__tests__/AIClasses/OpenAI.test.ts b/__tests__/AIClasses/OpenAI.test.ts index c7ec113..18033e0 100644 --- a/__tests__/AIClasses/OpenAI.test.ts +++ b/__tests__/AIClasses/OpenAI.test.ts @@ -53,7 +53,8 @@ describe('OpenAI', () => { if (provider === AIProvider.Gemini) return 'test-gemini-key'; return ''; }), - getApiKeyForCurrentModel: vi.fn(() => 'test-openai-key') + getApiKeyForCurrentModel: vi.fn(() => 'test-openai-key'), + subscribeToSettingsChanged: vi.fn() }; RegisterSingleton(Services.SettingsService, mockSettingsService); diff --git a/__tests__/Services/SettingsService.test.ts b/__tests__/Services/SettingsService.test.ts index 57d1f1c..127196c 100644 --- a/__tests__/Services/SettingsService.test.ts +++ b/__tests__/Services/SettingsService.test.ts @@ -3,6 +3,7 @@ import { SettingsService, type IVaultkeeperAISettings } from '../../Services/Set import { RegisterSingleton, DeregisterAllServices } from '../../Services/DependencyService'; import { Services } from '../../Services/Services'; import { AIProvider, AIProviderModel, fromModel } from '../../Enums/ApiProvider'; +import { ChatMode } from 'Enums/ChatMode'; describe('SettingsService', () => { let settingsService: SettingsService; @@ -110,7 +111,8 @@ describe('SettingsService', () => { quickActionModel: AIProviderModel.ClaudeSonnet_4_6, enableContextMenuActions: false, enableToolbarActions: false, - hideDrawerElements: false + hideDrawerElements: false, + chatMode: ChatMode.ReadOnly }; settingsService = new SettingsService(loadedSettings); }); @@ -160,7 +162,8 @@ describe('SettingsService', () => { quickActionModel: AIProviderModel.ClaudeSonnet_4_6, enableContextMenuActions: false, enableToolbarActions: false, - hideDrawerElements: false + hideDrawerElements: false, + chatMode: ChatMode.ReadOnly }; settingsService = new SettingsService(loadedSettings); @@ -190,7 +193,8 @@ describe('SettingsService', () => { quickActionModel: AIProviderModel.GPT_5_4_Mini, enableContextMenuActions: false, enableToolbarActions: false, - hideDrawerElements: false + hideDrawerElements: false, + chatMode: ChatMode.ReadOnly }; settingsService = new SettingsService(loadedSettings); @@ -220,7 +224,8 @@ describe('SettingsService', () => { quickActionModel: AIProviderModel.GeminiFlash_2_5, enableContextMenuActions: false, enableToolbarActions: false, - hideDrawerElements: false + hideDrawerElements: false, + chatMode: ChatMode.ReadOnly }; settingsService = new SettingsService(loadedSettings); @@ -278,7 +283,8 @@ describe('SettingsService', () => { quickActionModel: AIProviderModel.ClaudeSonnet_4_6, enableContextMenuActions: false, enableToolbarActions: false, - hideDrawerElements: false + hideDrawerElements: false, + chatMode: ChatMode.ReadOnly }; settingsService = new SettingsService(loadedSettings); }); @@ -342,23 +348,24 @@ describe('SettingsService', () => { quickActionModel: AIProviderModel.ClaudeSonnet_4_6, enableContextMenuActions: false, enableToolbarActions: false, - hideDrawerElements: false + hideDrawerElements: false, + chatMode: ChatMode.ReadOnly }; settingsService = new SettingsService(loadedSettings); + mockPlugin.saveData.mockClear(); }); it('should call plugin.saveData with current settings', async () => { - await settingsService.saveSettings(); + await settingsService.updateSettings(() => {}); expect(mockPlugin.saveData).toHaveBeenCalledWith(settingsService.settings); - expect(mockPlugin.saveData).toHaveBeenCalledTimes(1); }); it('should call plugin.saveData with updated settings after modification', async () => { - settingsService.setApiKeyForProvider(AIProvider.Claude, 'updated-key'); - settingsService.settings.userInstruction = 'Updated instruction'; - - await settingsService.saveSettings(); + await settingsService.updateSettings(settings => { + settings.apiKeys.claude = 'updated-key'; + settings.userInstruction = 'Updated instruction'; + }); expect(mockPlugin.saveData).toHaveBeenCalledWith( expect.objectContaining({ @@ -373,7 +380,7 @@ describe('SettingsService', () => { it('should handle saveData errors gracefully', async () => { mockPlugin.saveData.mockRejectedValue(new Error('Save failed')); - await expect(settingsService.saveSettings()).rejects.toThrow('Save failed'); + await expect(settingsService.updateSettings(() => {})).rejects.toThrow('Save failed'); }); }); @@ -520,7 +527,7 @@ describe('SettingsService', () => { snippetSizeLimit: 250 }); - await settingsService.saveSettings(); + await settingsService.updateSettings(() => {}); expect(mockPlugin.saveData).toHaveBeenCalledWith( expect.objectContaining({ @@ -533,10 +540,10 @@ describe('SettingsService', () => { it('should handle modified limits in saveSettings', async () => { settingsService = new SettingsService({}); - settingsService.settings.searchResultsLimit = 100; - settingsService.settings.snippetSizeLimit = 600; - - await settingsService.saveSettings(); + await settingsService.updateSettings(settings => { + settings.searchResultsLimit = 100; + settings.snippetSizeLimit = 600; + }); expect(mockPlugin.saveData).toHaveBeenCalledWith( expect.objectContaining({