import { describe, expect, it, vi, beforeEach } from "vitest"; import { BrainController } from "./brain.controller"; import { BrainService, BrainQueryResult, BrainContext } from "./brain.service"; import { TaskStatus, TaskPriority, ProjectStatus, EntityType } from "@prisma/client"; describe("BrainController", () => { let controller: BrainController; let mockService: { query: ReturnType; getContext: ReturnType; search: ReturnType; }; const mockWorkspaceId = "123e4567-e89b-12d3-a456-426614174000"; const mockQueryResult: BrainQueryResult = { tasks: [ { id: "task-1", title: "Test Task", description: null, status: TaskStatus.IN_PROGRESS, priority: TaskPriority.HIGH, dueDate: null, assignee: null, project: null, }, ], events: [ { id: "event-1", title: "Test Event", description: null, startTime: new Date("2025-02-01T10:00:00Z"), endTime: new Date("2025-02-01T11:00:00Z"), allDay: false, location: null, project: null, }, ], projects: [ { id: "project-1", name: "Test Project", description: null, status: ProjectStatus.ACTIVE, startDate: null, endDate: null, color: null, _count: { tasks: 5, events: 2 }, }, ], meta: { totalTasks: 1, totalEvents: 1, totalProjects: 1, filters: {}, }, }; const mockContext: BrainContext = { timestamp: new Date(), workspace: { id: mockWorkspaceId, name: "Test Workspace" }, summary: { activeTasks: 10, overdueTasks: 2, upcomingEvents: 5, activeProjects: 3, }, tasks: [ { id: "task-1", title: "Test Task", status: TaskStatus.IN_PROGRESS, priority: TaskPriority.HIGH, dueDate: null, isOverdue: false, }, ], events: [ { id: "event-1", title: "Test Event", startTime: new Date("2025-02-01T10:00:00Z"), endTime: new Date("2025-02-01T11:00:00Z"), allDay: false, location: null, }, ], projects: [ { id: "project-1", name: "Test Project", status: ProjectStatus.ACTIVE, taskCount: 5, }, ], }; beforeEach(() => { mockService = { query: vi.fn().mockResolvedValue(mockQueryResult), getContext: vi.fn().mockResolvedValue(mockContext), search: vi.fn().mockResolvedValue(mockQueryResult), }; controller = new BrainController(mockService as unknown as BrainService); }); describe("query", () => { it("should call service.query with merged workspaceId", async () => { const queryDto = { workspaceId: "different-id", query: "What tasks are due?", }; const result = await controller.query(queryDto, mockWorkspaceId); expect(mockService.query).toHaveBeenCalledWith({ ...queryDto, workspaceId: mockWorkspaceId, }); expect(result).toEqual(mockQueryResult); }); it("should handle query with filters", async () => { const queryDto = { workspaceId: mockWorkspaceId, entities: [EntityType.TASK, EntityType.EVENT], tasks: { status: TaskStatus.IN_PROGRESS }, events: { upcoming: true }, }; await controller.query(queryDto, mockWorkspaceId); expect(mockService.query).toHaveBeenCalledWith({ ...queryDto, workspaceId: mockWorkspaceId, }); }); it("should handle query with search term", async () => { const queryDto = { workspaceId: mockWorkspaceId, search: "important", limit: 10, }; await controller.query(queryDto, mockWorkspaceId); expect(mockService.query).toHaveBeenCalledWith({ ...queryDto, workspaceId: mockWorkspaceId, }); }); it("should return query result structure", async () => { const result = await controller.query( { workspaceId: mockWorkspaceId }, mockWorkspaceId ); expect(result).toHaveProperty("tasks"); expect(result).toHaveProperty("events"); expect(result).toHaveProperty("projects"); expect(result).toHaveProperty("meta"); expect(result.tasks).toHaveLength(1); expect(result.events).toHaveLength(1); expect(result.projects).toHaveLength(1); }); }); describe("getContext", () => { it("should call service.getContext with merged workspaceId", async () => { const contextDto = { workspaceId: "different-id", includeTasks: true, }; const result = await controller.getContext(contextDto, mockWorkspaceId); expect(mockService.getContext).toHaveBeenCalledWith({ ...contextDto, workspaceId: mockWorkspaceId, }); expect(result).toEqual(mockContext); }); it("should handle context with all options", async () => { const contextDto = { workspaceId: mockWorkspaceId, includeTasks: true, includeEvents: true, includeProjects: true, eventDays: 14, }; await controller.getContext(contextDto, mockWorkspaceId); expect(mockService.getContext).toHaveBeenCalledWith({ ...contextDto, workspaceId: mockWorkspaceId, }); }); it("should return context structure", async () => { const result = await controller.getContext( { workspaceId: mockWorkspaceId }, mockWorkspaceId ); expect(result).toHaveProperty("timestamp"); expect(result).toHaveProperty("workspace"); expect(result).toHaveProperty("summary"); expect(result.summary).toHaveProperty("activeTasks"); expect(result.summary).toHaveProperty("overdueTasks"); expect(result.summary).toHaveProperty("upcomingEvents"); expect(result.summary).toHaveProperty("activeProjects"); }); it("should include detailed lists when requested", async () => { const result = await controller.getContext( { workspaceId: mockWorkspaceId, includeTasks: true, includeEvents: true, includeProjects: true, }, mockWorkspaceId ); expect(result.tasks).toBeDefined(); expect(result.events).toBeDefined(); expect(result.projects).toBeDefined(); }); }); describe("search", () => { it("should call service.search with parameters", async () => { const result = await controller.search("test query", "10", mockWorkspaceId); expect(mockService.search).toHaveBeenCalledWith(mockWorkspaceId, "test query", 10); expect(result).toEqual(mockQueryResult); }); it("should use default limit when not provided", async () => { await controller.search("test", undefined as unknown as string, mockWorkspaceId); expect(mockService.search).toHaveBeenCalledWith(mockWorkspaceId, "test", 20); }); it("should cap limit at 100", async () => { await controller.search("test", "500", mockWorkspaceId); expect(mockService.search).toHaveBeenCalledWith(mockWorkspaceId, "test", 100); }); it("should handle empty search term", async () => { await controller.search(undefined as unknown as string, "10", mockWorkspaceId); expect(mockService.search).toHaveBeenCalledWith(mockWorkspaceId, "", 10); }); it("should handle invalid limit", async () => { await controller.search("test", "invalid", mockWorkspaceId); expect(mockService.search).toHaveBeenCalledWith(mockWorkspaceId, "test", 20); }); it("should return search result structure", async () => { const result = await controller.search("test", "10", mockWorkspaceId); expect(result).toHaveProperty("tasks"); expect(result).toHaveProperty("events"); expect(result).toHaveProperty("projects"); expect(result).toHaveProperty("meta"); }); }); });