diff --git a/client/src/components/settings/EmbeddingsTab.jsx b/client/src/components/settings/EmbeddingsTab.jsx index 9cb37d5b78..f03d5d9bcd 100644 --- a/client/src/components/settings/EmbeddingsTab.jsx +++ b/client/src/components/settings/EmbeddingsTab.jsx @@ -39,8 +39,8 @@ export default function EmbeddingsTab() { setModelsLoading(true); const status = await getLocalLlmStatus({ silent: true }).catch(() => null); setModels({ - ollama: (status?.ollama?.installedModels || []).map((m) => m.id || m.name), - lmstudio: (status?.lmstudio?.installedModels || []).map((m) => m.id || m.name), + ollama: (status?.ollama?.models || []).map((m) => m.id || m.name), + lmstudio: (status?.lmstudio?.models || []).map((m) => m.id || m.name), }); setModelsLoading(false); }; diff --git a/client/src/components/settings/EmbeddingsTab.test.jsx b/client/src/components/settings/EmbeddingsTab.test.jsx new file mode 100644 index 0000000000..8a47b442ee --- /dev/null +++ b/client/src/components/settings/EmbeddingsTab.test.jsx @@ -0,0 +1,38 @@ +import { describe, expect, it, vi } from 'vitest'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import { MemoryRouter } from 'react-router'; + +vi.mock('../../services/apiSystem', () => ({ + getSettings: vi.fn().mockResolvedValue({ embeddings: { provider: 'ollama', model: '' } }), + updateSettings: vi.fn(), +})); +vi.mock('../../services/apiLocalLlm', () => ({ + getLocalLlmStatus: vi.fn() + .mockResolvedValueOnce({ ollama: { models: [{ id: 'custom-embed:latest' }] }, lmstudio: { models: [] } }) + .mockResolvedValueOnce({ ollama: { models: [] }, lmstudio: { models: [] } }) + .mockResolvedValueOnce({ ollama: { models: [] }, lmstudio: { models: [{ id: 'example/custom-embedding' }] } }), +})); +vi.mock('../ui/Toast', () => ({ + default: Object.assign(vi.fn(), { success: vi.fn(), error: vi.fn() }), +})); + +import EmbeddingsTab from './EmbeddingsTab.jsx'; + +describe('EmbeddingsTab', () => { + it('reads installed embedding choices from the public models field for both backends', async () => { + render(); + + const datalist = () => document.getElementById('embeddings-model-options'); + await waitFor(() => expect(datalist().querySelector('option[value="custom-embed:latest"]')).toBeTruthy()); + + fireEvent.click(screen.getByRole('button', { name: 'Refresh' })); + await waitFor(() => expect(datalist().querySelector('option[value="custom-embed:latest"]')).toBeFalsy()); + expect(datalist().querySelector('option[value="nomic-embed-text"]')).toBeTruthy(); + fireEvent.change(screen.getByLabelText('Model'), { target: { value: 'manual-embedding-model' } }); + expect(screen.getByLabelText('Model')).toHaveValue('manual-embedding-model'); + + fireEvent.change(screen.getByLabelText('Provider'), { target: { value: 'lmstudio' } }); + fireEvent.click(screen.getByRole('button', { name: 'Refresh' })); + await waitFor(() => expect(datalist().querySelector('option[value="example/custom-embedding"]')).toBeTruthy()); + }); +});