Skip to main content
Glama
D3GraphRenderer.test.ts6.94 kB
/** * Tests for D3GraphRenderer * * Verifies force-directed graph generation with D3.js features. */ import { describe, it, expect, beforeEach } from '@jest/globals'; import { D3GraphRenderer, type GraphNode, type GraphEdge } from '../../artifacts/visualizations/D3GraphRenderer.js'; describe('D3GraphRenderer', () => { let renderer: D3GraphRenderer; beforeEach(() => { renderer = new D3GraphRenderer(1200, 800); }); describe('Constructor', () => { it('should initialize with default dimensions', () => { const defaultRenderer = new D3GraphRenderer(); expect(defaultRenderer).toBeDefined(); }); it('should initialize with custom dimensions', () => { const customRenderer = new D3GraphRenderer(800, 600); expect(customRenderer).toBeDefined(); }); }); describe('generateForceDirectedGraph', () => { it('should generate valid HTML with SVG', () => { const nodes: GraphNode[] = [ { id: 'node1', label: 'Signal A', type: 'EventBus' }, { id: 'node2', label: 'Signal B', type: 'SignalBus' } ]; const edges: GraphEdge[] = [ { source: 'node1', target: 'node2' } ]; const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('<!DOCTYPE html>'); expect(html).toContain('<svg id="graph"'); expect(html).toContain('</svg>'); expect(html).toContain('</html>'); }); it('should embed node data in HTML', () => { const nodes: GraphNode[] = [ { id: 'test_signal', label: 'Test Signal', type: 'EventBus', filePath: 'test.gd', line: 42 } ]; const edges: GraphEdge[] = []; const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('test_signal'); expect(html).toContain('Test Signal'); expect(html).toContain('EventBus'); }); it('should embed edge data in HTML', () => { const nodes: GraphNode[] = [ { id: 'node1', label: 'A', type: 'EventBus' }, { id: 'node2', label: 'B', type: 'EventBus' } ]; const edges: GraphEdge[] = [ { source: 'node1', target: 'node2', type: 'emit' } ]; const html = renderer.generateForceDirectedGraph(nodes, edges); const nodesJson = JSON.stringify(nodes); const edgesJson = JSON.stringify(edges); expect(html).toContain(nodesJson); expect(html).toContain(edgesJson); }); it('should include D3 force simulation setup', () => { const nodes: GraphNode[] = [ { id: 'node1', label: 'A', type: 'EventBus' } ]; const edges: GraphEdge[] = []; const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('d3.forceSimulation'); expect(html).toContain('forceLink'); expect(html).toContain('forceManyBody'); expect(html).toContain('forceCenter'); }); it('should include zoom controls', () => { const nodes: GraphNode[] = [{ id: 'node1', label: 'A', type: 'EventBus' }]; const edges: GraphEdge[] = []; const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('d3.zoom'); expect(html).toContain('scaleExtent'); expect(html).toContain('resetZoom'); }); it('should include drag controls', () => { const nodes: GraphNode[] = [{ id: 'node1', label: 'A', type: 'EventBus' }]; const edges: GraphEdge[] = []; const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('d3.drag'); expect(html).toContain('dragStarted'); expect(html).toContain('dragged'); expect(html).toContain('dragEnded'); }); it('should limit simulation to max ticks (performance)', () => { const nodes: GraphNode[] = [{ id: 'node1', label: 'A', type: 'EventBus' }]; const edges: GraphEdge[] = []; const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('maxTicks'); expect(html).toContain('300'); // Performance limit }); it('should include control buttons', () => { const nodes: GraphNode[] = [{ id: 'node1', label: 'A', type: 'EventBus' }]; const edges: GraphEdge[] = []; const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('Reset Zoom'); expect(html).toContain('Toggle Labels'); expect(html).toContain('Restart Sim'); }); it('should include legend for node types', () => { const nodes: GraphNode[] = [{ id: 'node1', label: 'A', type: 'EventBus' }]; const edges: GraphEdge[] = []; const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('legend'); expect(html).toContain('EventBus'); expect(html).toContain('SignalBus'); expect(html).toContain('Custom'); }); it('should include stats display', () => { const nodes: GraphNode[] = [ { id: 'node1', label: 'A', type: 'EventBus' }, { id: 'node2', label: 'B', type: 'SignalBus' } ]; const edges: GraphEdge[] = [{ source: 'node1', target: 'node2' }]; const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('node-count'); expect(html).toContain('edge-count'); expect(html).toContain('zoom-level'); }); it('should handle empty graph', () => { const nodes: GraphNode[] = []; const edges: GraphEdge[] = []; const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('<!DOCTYPE html>'); expect(html).toContain('<svg id="graph"'); }); it('should handle graph with many nodes (stress test)', () => { const nodes: GraphNode[] = Array.from({ length: 100 }, (_, i) => ({ id: `node${i}`, label: `Signal ${i}`, type: i % 2 === 0 ? 'EventBus' : 'SignalBus' })); const edges: GraphEdge[] = Array.from({ length: 50 }, (_, i) => ({ source: `node${i}`, target: `node${i + 1}` })); const html = renderer.generateForceDirectedGraph(nodes, edges); expect(html).toContain('node99'); // Last node expect(html.length).toBeGreaterThan(1000); // Substantial HTML }); }); describe('getNodeColor', () => { it('should return color for EventBus type', () => { const color = renderer.getNodeColor('EventBus'); expect(color).toBe('#1f77b4'); }); it('should return color for SignalBus type', () => { const color = renderer.getNodeColor('SignalBus'); expect(color).toBe('#ff7f0e'); }); it('should return color for Custom type', () => { const color = renderer.getNodeColor('Custom'); expect(color).toBe('#2ca02c'); }); it('should return default color for unknown type', () => { const color = renderer.getNodeColor('UnknownType'); expect(color).toBe('#999'); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/EricA1019/CTS_MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server