import { beforeEach, describe, expect, it, vi } from 'vitest'; const mocks = vi.hoisted(() => ({ listKnowledgeDocs: vi.fn(), uploadKnowledgeDoc: vi.fn(), deleteKnowledgeDoc: vi.fn(), isSafeKnowledgeDocName: vi.fn(), })); vi.mock('../electron/utils/knowledge-docs', () => ({ listKnowledgeDocs: mocks.listKnowledgeDocs, uploadKnowledgeDoc: mocks.uploadKnowledgeDoc, deleteKnowledgeDoc: mocks.deleteKnowledgeDoc, isSafeKnowledgeDocName: mocks.isSafeKnowledgeDocName, })); import { normalizeRequest } from '../electron/api/route-utils'; import { handleKnowledgeRoutes } from '../electron/api/routes/knowledge'; const ctx = { gatewayManager: null, providerApiService: null, mainWindow: null, } as any; describe('knowledge docs routes', () => { beforeEach(() => { mocks.listKnowledgeDocs.mockReset(); mocks.uploadKnowledgeDoc.mockReset(); mocks.deleteKnowledgeDoc.mockReset(); mocks.isSafeKnowledgeDocName.mockReset(); mocks.isSafeKnowledgeDocName.mockReturnValue(true); }); it('returns listed knowledge docs from the local route', async () => { mocks.listKnowledgeDocs.mockResolvedValue([ { name: 'guide.md', size: 128, modifiedAt: '2026-04-18T10:00:00.000Z', type: 'md', }, ]); const response = await handleKnowledgeRoutes(normalizeRequest({ path: '/api/knowledge/docs', method: 'GET', }), ctx); expect(response?.ok).toBe(true); expect(response?.json).toMatchObject({ success: true, files: [ expect.objectContaining({ name: 'guide.md', type: 'md', }), ], }); }); it('uploads and deletes docs through the route contract', async () => { mocks.uploadKnowledgeDoc.mockResolvedValue({ name: 'guide.md', size: 128, modifiedAt: '2026-04-18T10:00:00.000Z', type: 'md', }); const upload = await handleKnowledgeRoutes(normalizeRequest({ path: '/api/knowledge/docs', method: 'POST', body: JSON.stringify({ fileName: 'guide.md', base64: Buffer.from('hello').toString('base64'), }), }), ctx); expect(upload?.ok).toBe(true); expect(upload?.json).toMatchObject({ success: true, file: expect.objectContaining({ name: 'guide.md', }), }); const remove = await handleKnowledgeRoutes(normalizeRequest({ path: '/api/knowledge/docs/guide.md', method: 'DELETE', }), ctx); expect(remove?.ok).toBe(true); expect(remove?.json).toMatchObject({ success: true }); expect(mocks.deleteKnowledgeDoc).toHaveBeenCalledWith('guide.md'); }); it('rejects unsafe file names', async () => { mocks.isSafeKnowledgeDocName.mockReturnValue(false); const response = await handleKnowledgeRoutes(normalizeRequest({ path: '/api/knowledge/docs', method: 'POST', body: JSON.stringify({ fileName: '../escape.md', base64: Buffer.from('bad').toString('base64'), }), }), ctx); expect(response?.ok).toBe(false); expect(response?.status).toBe(400); }); });