import { describe, it, expect, beforeEach, vi } from "vitest"; import { Test, TestingModule } from "@nestjs/testing"; import { KnowledgeGraphController } from "./graph.controller"; import { GraphService } from "./services/graph.service"; import { PrismaService } from "../prisma/prisma.service"; import { AuthGuard } from "../auth/guards/auth.guard"; import { WorkspaceGuard } from "../common/guards/workspace.guard"; import { PermissionGuard } from "../common/guards/permission.guard"; describe("KnowledgeGraphController", () => { let controller: KnowledgeGraphController; let graphService: GraphService; let prismaService: PrismaService; const mockGraphService = { getFullGraph: vi.fn(), getGraphStats: vi.fn(), getEntryGraph: vi.fn(), getEntryGraphBySlug: vi.fn(), }; const mockPrismaService = { knowledgeEntry: { findUnique: vi.fn(), }, }; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ controllers: [KnowledgeGraphController], providers: [ { provide: GraphService, useValue: mockGraphService, }, { provide: PrismaService, useValue: mockPrismaService, }, ], }) .overrideGuard(AuthGuard) .useValue({ canActivate: vi.fn(() => true) }) .overrideGuard(WorkspaceGuard) .useValue({ canActivate: vi.fn(() => true) }) .overrideGuard(PermissionGuard) .useValue({ canActivate: vi.fn(() => true) }) .compile(); controller = module.get(KnowledgeGraphController); graphService = module.get(GraphService); prismaService = module.get(PrismaService); vi.clearAllMocks(); }); it("should be defined", () => { expect(controller).toBeDefined(); }); describe("getFullGraph", () => { it("should return full graph without filters", async () => { const mockGraph = { nodes: [], edges: [], stats: { totalNodes: 0, totalEdges: 0, orphanCount: 0 }, }; mockGraphService.getFullGraph.mockResolvedValue(mockGraph); const result = await controller.getFullGraph("workspace-1", {}); expect(graphService.getFullGraph).toHaveBeenCalledWith("workspace-1", {}); expect(result).toEqual(mockGraph); }); it("should pass filters to service", async () => { const mockGraph = { nodes: [], edges: [], stats: { totalNodes: 0, totalEdges: 0, orphanCount: 0 }, }; mockGraphService.getFullGraph.mockResolvedValue(mockGraph); const filters = { tags: ["tag-1"], status: "PUBLISHED", limit: 100, }; await controller.getFullGraph("workspace-1", filters); expect(graphService.getFullGraph).toHaveBeenCalledWith("workspace-1", filters); }); }); describe("getGraphStats", () => { it("should return graph statistics", async () => { const mockStats = { totalEntries: 10, totalLinks: 15, orphanEntries: 2, averageLinks: 1.5, mostConnectedEntries: [], tagDistribution: [], }; mockGraphService.getGraphStats.mockResolvedValue(mockStats); const result = await controller.getGraphStats("workspace-1"); expect(graphService.getGraphStats).toHaveBeenCalledWith("workspace-1"); expect(result).toEqual(mockStats); }); }); describe("getEntryGraph", () => { it("should return entry-centered graph", async () => { const mockEntry = { id: "entry-1", slug: "test-entry", title: "Test Entry", }; const mockGraph = { centerNode: mockEntry, nodes: [mockEntry], edges: [], stats: { totalNodes: 1, totalEdges: 0, maxDepth: 1 }, }; mockGraphService.getEntryGraphBySlug.mockResolvedValue(mockGraph); const result = await controller.getEntryGraph("workspace-1", "test-entry", { depth: 2 }); expect(graphService.getEntryGraphBySlug).toHaveBeenCalledWith("workspace-1", "test-entry", 2); expect(result).toEqual(mockGraph); }); it("should use default depth if not provided", async () => { mockGraphService.getEntryGraphBySlug.mockResolvedValue({}); await controller.getEntryGraph("workspace-1", "test-entry", {}); expect(graphService.getEntryGraphBySlug).toHaveBeenCalledWith("workspace-1", "test-entry", 1); }); it("should throw error if entry not found", async () => { mockGraphService.getEntryGraphBySlug.mockRejectedValue(new Error("Entry not found")); await expect(controller.getEntryGraph("workspace-1", "non-existent", {})).rejects.toThrow( "Entry not found" ); }); }); });