import { describe, it, expect, beforeEach, vi } from "vitest"; import { ActivityController } from "./activity.controller"; import { ActivityService } from "./activity.service"; import { ActivityAction, EntityType } from "@prisma/client"; import type { QueryActivityLogDto } from "./dto"; describe("ActivityController", () => { let controller: ActivityController; let service: ActivityService; const mockActivityService = { findAll: vi.fn(), findOne: vi.fn(), getAuditTrail: vi.fn(), }; const mockWorkspaceId = "workspace-123"; beforeEach(() => { service = mockActivityService as any; controller = new ActivityController(service); vi.clearAllMocks(); }); describe("findAll", () => { const mockPaginatedResult = { data: [ { id: "activity-1", workspaceId: "workspace-123", userId: "user-123", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "task-123", details: {}, createdAt: new Date("2024-01-01"), user: { id: "user-123", name: "Test User", email: "test@example.com", }, }, ], meta: { total: 1, page: 1, limit: 50, totalPages: 1, }, }; it("should return paginated activity logs using authenticated user's workspaceId", async () => { const query: QueryActivityLogDto = { workspaceId: "workspace-123", page: 1, limit: 50, }; mockActivityService.findAll.mockResolvedValue(mockPaginatedResult); const result = await controller.findAll(query, mockWorkspaceId); expect(result).toEqual(mockPaginatedResult); expect(mockActivityService.findAll).toHaveBeenCalledWith({ ...query, workspaceId: "workspace-123", }); }); it("should handle query with filters", async () => { const query: QueryActivityLogDto = { workspaceId: "workspace-123", userId: "user-123", action: ActivityAction.CREATED, entityType: EntityType.TASK, page: 1, limit: 10, }; mockActivityService.findAll.mockResolvedValue(mockPaginatedResult); await controller.findAll(query, mockWorkspaceId); expect(mockActivityService.findAll).toHaveBeenCalledWith({ ...query, workspaceId: "workspace-123", }); }); it("should handle query with date range", async () => { const startDate = new Date("2024-01-01"); const endDate = new Date("2024-01-31"); const query: QueryActivityLogDto = { workspaceId: "workspace-123", startDate, endDate, page: 1, limit: 50, }; mockActivityService.findAll.mockResolvedValue(mockPaginatedResult); await controller.findAll(query, mockWorkspaceId); expect(mockActivityService.findAll).toHaveBeenCalledWith({ ...query, workspaceId: "workspace-123", }); }); it("should use user's workspaceId even if query provides different one", async () => { const query: QueryActivityLogDto = { workspaceId: "different-workspace", page: 1, limit: 50, }; mockActivityService.findAll.mockResolvedValue(mockPaginatedResult); await controller.findAll(query, mockWorkspaceId); // Should use authenticated user's workspaceId, not query's expect(mockActivityService.findAll).toHaveBeenCalledWith({ ...query, workspaceId: "workspace-123", }); }); }); describe("findOne", () => { const mockActivity = { id: "activity-123", workspaceId: "workspace-123", userId: "user-123", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "task-123", details: {}, createdAt: new Date(), user: { id: "user-123", name: "Test User", email: "test@example.com", }, }; it("should return a single activity log using authenticated user's workspaceId", async () => { mockActivityService.findOne.mockResolvedValue(mockActivity); const result = await controller.findOne("activity-123", mockWorkspaceId); expect(result).toEqual(mockActivity); expect(mockActivityService.findOne).toHaveBeenCalledWith("activity-123", "workspace-123"); }); it("should return null if activity not found", async () => { mockActivityService.findOne.mockResolvedValue(null); const result = await controller.findOne("nonexistent", mockWorkspaceId); expect(result).toBeNull(); }); it("should return null if workspaceId is missing (service handles gracefully)", async () => { mockActivityService.findOne.mockResolvedValue(null); const result = await controller.findOne("activity-123", undefined as any); expect(result).toBeNull(); expect(mockActivityService.findOne).toHaveBeenCalledWith("activity-123", undefined); }); }); describe("getAuditTrail", () => { const mockAuditTrail = [ { id: "activity-1", workspaceId: "workspace-123", userId: "user-123", action: ActivityAction.CREATED, entityType: EntityType.TASK, entityId: "task-123", details: { title: "New Task" }, createdAt: new Date("2024-01-01"), user: { id: "user-123", name: "Test User", email: "test@example.com", }, }, { id: "activity-2", workspaceId: "workspace-123", userId: "user-456", action: ActivityAction.UPDATED, entityType: EntityType.TASK, entityId: "task-123", details: { title: "Updated Task" }, createdAt: new Date("2024-01-02"), user: { id: "user-456", name: "Another User", email: "another@example.com", }, }, ]; it("should return audit trail for a task using authenticated user's workspaceId", async () => { mockActivityService.getAuditTrail.mockResolvedValue(mockAuditTrail); const result = await controller.getAuditTrail(EntityType.TASK, "task-123", mockWorkspaceId); expect(result).toEqual(mockAuditTrail); expect(mockActivityService.getAuditTrail).toHaveBeenCalledWith( "workspace-123", EntityType.TASK, "task-123" ); }); it("should return audit trail for an event", async () => { const eventAuditTrail = [ { id: "activity-3", workspaceId: "workspace-123", userId: "user-123", action: ActivityAction.CREATED, entityType: EntityType.EVENT, entityId: "event-123", details: {}, createdAt: new Date(), user: { id: "user-123", name: "Test User", email: "test@example.com", }, }, ]; mockActivityService.getAuditTrail.mockResolvedValue(eventAuditTrail); const result = await controller.getAuditTrail(EntityType.EVENT, "event-123", mockWorkspaceId); expect(result).toEqual(eventAuditTrail); expect(mockActivityService.getAuditTrail).toHaveBeenCalledWith( "workspace-123", EntityType.EVENT, "event-123" ); }); it("should return audit trail for a project", async () => { const projectAuditTrail = [ { id: "activity-4", workspaceId: "workspace-123", userId: "user-123", action: ActivityAction.CREATED, entityType: EntityType.PROJECT, entityId: "project-123", details: {}, createdAt: new Date(), user: { id: "user-123", name: "Test User", email: "test@example.com", }, }, ]; mockActivityService.getAuditTrail.mockResolvedValue(projectAuditTrail); const result = await controller.getAuditTrail( EntityType.PROJECT, "project-123", mockWorkspaceId ); expect(result).toEqual(projectAuditTrail); expect(mockActivityService.getAuditTrail).toHaveBeenCalledWith( "workspace-123", EntityType.PROJECT, "project-123" ); }); it("should return empty array if no audit trail found", async () => { mockActivityService.getAuditTrail.mockResolvedValue([]); const result = await controller.getAuditTrail( EntityType.WORKSPACE, "workspace-999", mockWorkspaceId ); expect(result).toEqual([]); }); it("should return empty array if workspaceId is missing (service handles gracefully)", async () => { mockActivityService.getAuditTrail.mockResolvedValue([]); const result = await controller.getAuditTrail(EntityType.TASK, "task-123", undefined as any); expect(result).toEqual([]); expect(mockActivityService.getAuditTrail).toHaveBeenCalledWith( undefined, EntityType.TASK, "task-123" ); }); }); });