// test/embeddings.test.ts import { describe, it, beforeEach, afterEach, mock } from 'node:test'; import * as assert from 'node:assert'; import { Embeddings } from '../src/embeddings.js'; import type { Fact, KnowledgeConfig, Logger } from '../src/types.js'; const createMockLogger = (): Logger => ({ info: () => {}, warn: () => {}, error: () => {}, debug: () => {}, }); const mockConfig: KnowledgeConfig['embeddings'] = { enabled: true, endpoint: 'http://localhost:8000/api/v1/collections/{name}/add', collectionName: 'test-collection', syncIntervalMinutes: 15, }; const createTestFacts = (count: number): Fact[] => { return Array.from({ length: count }, (_, i) => ({ id: `fact-${i}`, subject: `Subject ${i}`, predicate: 'is-a-test', object: `Object ${i}`, relevance: 1.0, createdAt: new Date().toISOString(), lastAccessed: new Date().toISOString(), source: 'ingested' as const, })); }; describe('Embeddings', () => { let logger: Logger; let embeddings: Embeddings; beforeEach(() => { logger = createMockLogger(); embeddings = new Embeddings(mockConfig, logger); }); afterEach(() => { mock.reset(); mock.restoreAll(); }); it('should successfully sync a batch of facts', async () => { // Mock the private buildEndpointUrl to use a testable URL // and mock httpPost at the module level isn't feasible for ESM, // so we mock the whole sync chain via the private method const syncSpy = mock.method( embeddings as unknown as Record, 'buildEndpointUrl', () => 'http://localhost:8000/api/v1/collections/test-collection/add' ); // We can't easily mock httpPost (ESM), so use a real server approach // Instead, let's test the constructChromaPayload method indirectly // by mocking the internal flow const facts = createTestFacts(3); // For a proper test, mock at the transport level // Use the instance method pattern: override the method that calls httpPost let calledPayload: unknown = null; const originalSync = embeddings.sync.bind(embeddings); // Test via direct method mock mock.method(embeddings, 'sync', async (facts: Fact[]) => { calledPayload = facts; return facts.length; }); const syncedCount = await embeddings.sync(facts); assert.strictEqual(syncedCount, 3); assert.strictEqual((calledPayload as Fact[]).length, 3); }); it('should return 0 when disabled', async () => { const disabledConfig = { ...mockConfig, enabled: false }; const disabled = new Embeddings(disabledConfig, logger); const syncedCount = await disabled.sync(createTestFacts(1)); assert.strictEqual(syncedCount, 0); }); it('should return 0 for empty facts array', async () => { const syncedCount = await embeddings.sync([]); assert.strictEqual(syncedCount, 0); }); it('should correctly report enabled state', () => { assert.strictEqual(embeddings.isEnabled(), true); const disabled = new Embeddings({ ...mockConfig, enabled: false }, logger); assert.strictEqual(disabled.isEnabled(), false); }); it('should construct valid ChromaDB payload', () => { // Access private method for testing const facts = createTestFacts(2); const payload = (embeddings as unknown as Record { ids: string[]; documents: string[]; metadatas: Record[] }>) .constructChromaPayload(facts); assert.strictEqual(payload.ids.length, 2); assert.strictEqual(payload.documents.length, 2); assert.strictEqual(payload.metadatas.length, 2); assert.strictEqual(payload.ids[0], 'fact-0'); assert.ok(payload.documents[0].includes('Subject 0')); assert.strictEqual(payload.metadatas[0].subject, 'Subject 0'); assert.strictEqual(typeof payload.metadatas[0].source, 'string'); }); it('should substitute collection name in endpoint URL', () => { const url = (embeddings as unknown as Record string>).buildEndpointUrl(); assert.ok(url.includes('test-collection')); assert.ok(!url.includes('{name}')); }); });