/** * Tests for useGraphData Hook */ import { describe, it, expect } from 'vitest'; import { renderHook, act } from '@testing-library/react'; import { useGraphData } from '@/hooks/useGraphData'; import type { GraphData } from '@/types/rdf'; describe('useGraphData', () => { const sampleGraphData: GraphData = { nodes: [ { id: 'node1', type: 'uri', label: 'Node 1' }, { id: 'node2', type: 'literal', label: 'Node 2' }, { id: 'node3', type: 'Agent', label: 'Node 3' }, ], links: [ { source: 'node1', target: 'node2', predicate: 'http://example.org/pred1', label: 'predicate 1' }, { source: 'node2', target: 'node3', predicate: 'http://example.org/pred2', label: 'predicate 2' }, ], }; it('should initialize with empty state', () => { const { result } = renderHook(() => useGraphData()); expect(result.current.nodes).toEqual([]); expect(result.current.links).toEqual([]); expect(result.current.filteredNodes).toEqual([]); expect(result.current.filteredLinks).toEqual([]); expect(result.current.nodeTypes).toEqual([]); expect(result.current.predicates).toEqual([]); expect(result.current.selectedNode).toBe(null); expect(result.current.stats.totalNodes).toBe(0); expect(result.current.stats.totalLinks).toBe(0); }); it('should load graph data', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); expect(result.current.nodes).toEqual(sampleGraphData.nodes); expect(result.current.links).toEqual(sampleGraphData.links); expect(result.current.stats.totalNodes).toBe(3); expect(result.current.stats.totalLinks).toBe(2); }); it('should extract node types', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); expect(result.current.nodeTypes).toContain('uri'); expect(result.current.nodeTypes).toContain('literal'); expect(result.current.nodeTypes).toContain('Agent'); expect(result.current.nodeTypes.length).toBe(3); }); it('should extract predicates', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); expect(result.current.predicates).toContain('http://example.org/pred1'); expect(result.current.predicates).toContain('http://example.org/pred2'); expect(result.current.predicates.length).toBe(2); }); it('should filter nodes by type', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); act(() => { result.current.setFilters({ nodeTypes: new Set(['uri']) }); }); expect(result.current.filteredNodes.length).toBe(1); expect(result.current.filteredNodes[0].type).toBe('uri'); }); it('should filter nodes by search term', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); act(() => { result.current.setFilters({ searchTerm: 'Node 1' }); }); expect(result.current.filteredNodes.length).toBe(1); expect(result.current.filteredNodes[0].label).toBe('Node 1'); }); it('should filter links based on filtered nodes', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); // Filter to only node1 act(() => { result.current.setFilters({ nodeTypes: new Set(['uri']) }); }); // Links should be empty because both endpoints aren't in filtered nodes expect(result.current.filteredLinks.length).toBe(0); }); it('should filter links by predicate', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); act(() => { result.current.setFilters({ predicates: new Set(['http://example.org/pred1']) }); }); expect(result.current.filteredLinks.length).toBe(1); expect(result.current.filteredLinks[0].predicate).toBe('http://example.org/pred1'); }); it('should handle node selection', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); act(() => { result.current.setSelectedNode(sampleGraphData.nodes[0]); }); expect(result.current.selectedNode).toEqual(sampleGraphData.nodes[0]); }); it('should clear node selection', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); result.current.setSelectedNode(sampleGraphData.nodes[0]); }); expect(result.current.selectedNode).not.toBe(null); act(() => { result.current.setSelectedNode(null); }); expect(result.current.selectedNode).toBe(null); }); it('should reset filters', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); result.current.setFilters({ nodeTypes: new Set(['uri']), searchTerm: 'test', }); }); expect(result.current.filters.nodeTypes.size).toBe(1); expect(result.current.filters.searchTerm).toBe('test'); act(() => { result.current.resetFilters(); }); expect(result.current.filters.nodeTypes.size).toBe(0); expect(result.current.filters.searchTerm).toBe(''); }); it('should clear graph data', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); expect(result.current.nodes.length).toBe(3); act(() => { result.current.clearGraphData(); }); expect(result.current.nodes.length).toBe(0); expect(result.current.links.length).toBe(0); expect(result.current.selectedNode).toBe(null); }); it('should calculate stats correctly', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); expect(result.current.stats.totalNodes).toBe(3); expect(result.current.stats.totalLinks).toBe(2); expect(result.current.stats.filteredNodeCount).toBe(3); expect(result.current.stats.filteredLinkCount).toBe(2); // Apply filter act(() => { result.current.setFilters({ nodeTypes: new Set(['uri']) }); }); expect(result.current.stats.totalNodes).toBe(3); // Total unchanged expect(result.current.stats.filteredNodeCount).toBe(1); // Filtered count changed }); it('should handle link counts', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); expect(result.current.linkCounts).toHaveProperty('http://example.org/pred1'); expect(result.current.linkCounts['http://example.org/pred1']).toBe(1); expect(result.current.linkCounts['http://example.org/pred2']).toBe(1); }); it('should handle node counts', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); expect(result.current.nodeCounts).toHaveProperty('uri'); expect(result.current.nodeCounts['uri']).toBe(1); expect(result.current.nodeCounts['literal']).toBe(1); expect(result.current.nodeCounts['Agent']).toBe(1); }); it('should combine multiple filters', () => { const { result } = renderHook(() => useGraphData()); act(() => { result.current.loadGraphData(sampleGraphData); }); act(() => { result.current.setFilters({ nodeTypes: new Set(['uri', 'literal']), searchTerm: 'Node 1', }); }); // Only Node 1 should match (uri type AND "Node 1" in label) expect(result.current.filteredNodes.length).toBe(1); expect(result.current.filteredNodes[0].id).toBe('node1'); }); });