Files
ruvnet__ruflo/v3/@claude-flow/cli/__tests__/graph-backend.test.ts
Reuven 7eb505d22f feat: native ruvllm + graph-node intelligence backends (ADR-086, ADR-087)
Wire @ruvector/ruvllm as intelligence coordinator (SonaCoordinator,
ContrastiveTrainer, TrainingPipeline) and @ruvector/graph-node as
native graph database for agent relationships and causal edges.

- Fix ESM/CJS import: use createRequire pattern for CJS packages
- Eager loading of all backends during initialization
- Wire into neural status, hooks_intelligence, ruvllm_status CLI/MCP
- Auto-trigger background learning on trajectory-end
- Auto-save LoRA checkpoints after neural train
- Graph-node records agents on spawn, causal edges, swarm teams
- Fix community issues #1511, #1509, #1507, #1506, #1505
- Real Product Quantization with k-means trained codebooks
- SONA native routing with 5-tier fallback
- Embedding fallback transparency warnings
- Plugin peer dep fixes (semver ranges, removed phantom deps)

32 test files, 1762 tests passing, 0 regressions.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-04-08 09:06:13 -04:00

93 lines
4.1 KiB
TypeScript

/**
* ADR-087: @ruvector/graph-node native graph database backend tests
*
* Tests the wrapper module's exports and CJS import pattern.
* The actual graph-node integration is verified by the e2e node script.
*/
import { describe, it, expect } from 'vitest';
describe('ADR-087: graph-node backend', () => {
describe('module exports', () => {
it('exports all expected functions', async () => {
const mod = await import('../src/ruvector/graph-backend.js');
expect(typeof mod.isGraphBackendAvailable).toBe('function');
expect(typeof mod.addNode).toBe('function');
expect(typeof mod.addEdge).toBe('function');
expect(typeof mod.addHyperedge).toBe('function');
expect(typeof mod.getNeighbors).toBe('function');
expect(typeof mod.getGraphStats).toBe('function');
expect(typeof mod.recordCausalEdge).toBe('function');
expect(typeof mod.recordCollaboration).toBe('function');
expect(typeof mod.recordSwarmTeam).toBe('function');
});
});
describe('graceful degradation', () => {
it('getGraphStats returns unavailable when graph-node not loaded', async () => {
// In test environment, graph-node may or may not be available
const { getGraphStats } = await import('../src/ruvector/graph-backend.js');
const stats = await getGraphStats();
expect(stats).toHaveProperty('totalNodes');
expect(stats).toHaveProperty('totalEdges');
expect(stats).toHaveProperty('avgDegree');
expect(stats).toHaveProperty('backend');
expect(['graph-node', 'unavailable']).toContain(stats.backend);
});
it('addNode returns string or null', async () => {
const { addNode } = await import('../src/ruvector/graph-backend.js');
const result = await addNode({ id: 'test-1', type: 'test' });
// Either a node ID string or null if backend unavailable
expect(result === null || typeof result === 'string').toBe(true);
});
it('getNeighbors returns array', async () => {
const { getNeighbors } = await import('../src/ruvector/graph-backend.js');
const result = await getNeighbors('nonexistent', 2);
expect(Array.isArray(result)).toBe(true);
});
it('recordCausalEdge returns result with backend', async () => {
const { recordCausalEdge } = await import('../src/ruvector/graph-backend.js');
const result = await recordCausalEdge('a', 'b', 'caused');
expect(result).toHaveProperty('success');
expect(result).toHaveProperty('backend');
});
it('recordSwarmTeam returns result', async () => {
const { recordSwarmTeam } = await import('../src/ruvector/graph-backend.js');
const result = await recordSwarmTeam(['a', 'b'], 'mesh');
expect(result).toHaveProperty('success');
});
});
describe('CJS import pattern', () => {
it('source uses createRequire for @ruvector/graph-node', async () => {
const { readFileSync } = await import('fs');
const { join } = await import('path');
const content = readFileSync(join(import.meta.dirname, '..', 'src', 'ruvector', 'graph-backend.ts'), 'utf8');
expect(content).toContain('createRequire');
expect(content).toContain("'@ruvector/graph-node'");
// Should NOT use ESM dynamic import for graph-node
expect(content).not.toMatch(/await import\(['"]@ruvector\/graph-node['"]\)/);
});
});
describe('type exports', () => {
it('exports GraphNodeData interface shape', async () => {
const { addNode } = await import('../src/ruvector/graph-backend.js');
// TypeScript ensures this matches GraphNodeData
const data = { id: 'x', type: 'agent', name: 'test', properties: { foo: 'bar' } };
const result = await addNode(data);
expect(result === null || typeof result === 'string').toBe(true);
});
it('exports GraphEdgeData interface shape', async () => {
const { addEdge } = await import('../src/ruvector/graph-backend.js');
const data = { from: 'a', to: 'b', label: 'test', description: 'desc', weight: 0.5, properties: {} };
const result = await addEdge(data);
expect(result === null || typeof result === 'string').toBe(true);
});
});
});