import { describe, test, expect, beforeAll, afterAll } from 'vitest'; import { neo4jService } from '../database/Neo4jService'; import { graphMemoryService } from '../memory/GraphMemoryService'; const shouldRunNeo4jTests = process.env.RUN_NEO4J_TESTS === 'true'; const describeGraphRag = shouldRunNeo4jTests ? describe : describe.skip; let neo4jAvailable = false; describeGraphRag('GraphRAG Integration Tests', () => { beforeAll(async () => { if (!shouldRunNeo4jTests) { neo4jAvailable = false; return; } try { await neo4jService.connect(); neo4jAvailable = await neo4jService.healthCheck(); } catch { neo4jAvailable = false; console.log('⚠️ Neo4j not available - GraphRAG tests will be skipped'); } }); afterAll(async () => { if (neo4jAvailable) { try { await neo4jService.runQuery('MATCH (n:TestEntity) DETACH DELETE n'); } catch { /* ignore cleanup errors */ } await neo4jService.disconnect(); } }); test('should create entity and retrieve it', async () => { const entity = await graphMemoryService.createEntity( 'TestEntity', 'Test Person', { role: 'developer', team: 'backend' } ); expect(entity.id).toBeDefined(); expect(entity.name).toBe('Test Person'); expect(entity.type).toBe('TestEntity'); const retrieved = await neo4jService.getNodeById(entity.id); expect(retrieved).toBeDefined(); expect(retrieved?.properties.role).toBe('developer'); }); test('should create relation between entities', async () => { const person = await graphMemoryService.createEntity('TestEntity', 'Alice', {}); const project = await graphMemoryService.createEntity('TestEntity', 'Project X', {}); const relation = await graphMemoryService.createRelation( person.id, project.id, 'WORKS_ON', { since: '2025-01-01' } ); expect(relation.id).toBeDefined(); expect(relation.type).toBe('WORKS_ON'); expect(relation.sourceId).toBe(person.id); expect(relation.targetId).toBe(project.id); }); test('should search entities by name', async () => { await graphMemoryService.createEntity('TestEntity', 'Bob Smith', { role: 'designer' }); await graphMemoryService.createEntity('TestEntity', 'Bob Jones', { role: 'developer' }); const results = await graphMemoryService.searchEntities('Bob'); expect(results.length).toBeGreaterThanOrEqual(2); expect(results.some(e => e.name.includes('Bob'))).toBe(true); }); test('should get related entities', async () => { const alice = await graphMemoryService.createEntity('TestEntity', 'Alice', {}); const bob = await graphMemoryService.createEntity('TestEntity', 'Bob', {}); const charlie = await graphMemoryService.createEntity('TestEntity', 'Charlie', {}); await graphMemoryService.createRelation(alice.id, bob.id, 'KNOWS'); await graphMemoryService.createRelation(alice.id, charlie.id, 'KNOWS'); const related = await graphMemoryService.getRelatedEntities(alice.id); expect(related.length).toBe(2); expect(related.some(e => e.name === 'Bob')).toBe(true); expect(related.some(e => e.name === 'Charlie')).toBe(true); }); test('should find path between entities', async () => { const a = await graphMemoryService.createEntity('TestEntity', 'A', {}); const b = await graphMemoryService.createEntity('TestEntity', 'B', {}); const c = await graphMemoryService.createEntity('TestEntity', 'C', {}); await graphMemoryService.createRelation(a.id, b.id, 'CONNECTS'); await graphMemoryService.createRelation(b.id, c.id, 'CONNECTS'); const path = await graphMemoryService.findPath(a.id, c.id); expect(path).toBeDefined(); expect(path?.path.length).toBe(3); // A -> B -> C expect(path?.relations.length).toBe(2); }); test('should get graph statistics', async () => { const stats = await graphMemoryService.getStatistics(); expect(stats.totalEntities).toBeGreaterThan(0); expect(stats.entityTypes).toBeDefined(); expect(stats.relationTypes).toBeDefined(); }); test('should update entity properties', async () => { const entity = await graphMemoryService.createEntity('TestEntity', 'Test', { version: 1 }); const updated = await graphMemoryService.updateEntity(entity.id, { version: 2, status: 'active' }); expect(updated).toBeDefined(); expect(updated?.properties.version).toBe(2); expect(updated?.properties.status).toBe('active'); }); test('should delete entity and its relations', async () => { const entity = await graphMemoryService.createEntity('TestEntity', 'ToDelete', {}); const other = await graphMemoryService.createEntity('TestEntity', 'Other', {}); await graphMemoryService.createRelation(entity.id, other.id, 'TEMP'); await graphMemoryService.deleteEntity(entity.id); const retrieved = await neo4jService.getNodeById(entity.id); expect(retrieved).toBeNull(); }); }); export { };