import { describe, it, expect, beforeEach, vi } from "vitest"; import { Test, TestingModule } from "@nestjs/testing"; import { CredentialsController } from "./credentials.controller"; import { CredentialsService } from "./credentials.service"; import { CredentialType, CredentialScope } from "@prisma/client"; import { AuthGuard } from "../auth/guards/auth.guard"; import { WorkspaceGuard } from "../common/guards/workspace.guard"; import { PermissionGuard } from "../common/guards/permission.guard"; import { ExecutionContext } from "@nestjs/common"; describe("CredentialsController", () => { let controller: CredentialsController; let service: CredentialsService; const mockCredentialsService = { create: vi.fn(), findAll: vi.fn(), findOne: vi.fn(), getValue: vi.fn(), update: vi.fn(), rotate: vi.fn(), remove: vi.fn(), }; const mockAuthGuard = { canActivate: vi.fn((context: ExecutionContext) => { const request = context.switchToHttp().getRequest(); request.user = { id: "550e8400-e29b-41d4-a716-446655440002", workspaceId: "550e8400-e29b-41d4-a716-446655440001", }; return true; }), }; const mockWorkspaceGuard = { canActivate: vi.fn(() => true), }; const mockPermissionGuard = { canActivate: vi.fn(() => true), }; const mockWorkspaceId = "550e8400-e29b-41d4-a716-446655440001"; const mockUserId = "550e8400-e29b-41d4-a716-446655440002"; const mockCredentialId = "550e8400-e29b-41d4-a716-446655440003"; const mockUser = { id: mockUserId, email: "test@example.com", name: "Test User", }; const mockCredential = { id: mockCredentialId, userId: mockUserId, workspaceId: mockWorkspaceId, name: "GitHub Token", provider: "github", type: CredentialType.API_KEY, scope: CredentialScope.USER, maskedValue: "****3456", description: "My GitHub API key", expiresAt: null, lastUsedAt: null, metadata: {}, isActive: true, rotatedAt: null, createdAt: new Date(), updatedAt: new Date(), }; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ controllers: [CredentialsController], providers: [ { provide: CredentialsService, useValue: mockCredentialsService, }, ], }) .overrideGuard(AuthGuard) .useValue(mockAuthGuard) .overrideGuard(WorkspaceGuard) .useValue(mockWorkspaceGuard) .overrideGuard(PermissionGuard) .useValue(mockPermissionGuard) .compile(); controller = module.get(CredentialsController); service = module.get(CredentialsService); // Clear all mocks before each test vi.clearAllMocks(); }); it("should be defined", () => { expect(controller).toBeDefined(); }); describe("create", () => { it("should create a credential", async () => { const createDto = { name: "GitHub Token", provider: "github", type: CredentialType.API_KEY, value: "ghp_1234567890abcdef", description: "My GitHub API key", }; mockCredentialsService.create.mockResolvedValue(mockCredential); const result = await controller.create(createDto, mockWorkspaceId, mockUser); expect(result).toEqual(mockCredential); expect(service.create).toHaveBeenCalledWith(mockWorkspaceId, mockUserId, createDto); }); }); describe("findAll", () => { it("should return paginated credentials", async () => { const query = { page: 1, limit: 10 }; const paginatedResult = { data: [mockCredential], meta: { total: 1, page: 1, limit: 10, totalPages: 1, }, }; mockCredentialsService.findAll.mockResolvedValue(paginatedResult); const result = await controller.findAll(query, mockWorkspaceId, mockUser); expect(result).toEqual(paginatedResult); expect(service.findAll).toHaveBeenCalledWith(mockWorkspaceId, mockUserId, query); }); }); describe("findOne", () => { it("should return a single credential", async () => { mockCredentialsService.findOne.mockResolvedValue(mockCredential); const result = await controller.findOne(mockCredentialId, mockWorkspaceId, mockUser); expect(result).toEqual(mockCredential); expect(service.findOne).toHaveBeenCalledWith(mockCredentialId, mockWorkspaceId, mockUserId); }); }); describe("getValue", () => { it("should return decrypted credential value", async () => { const valueResponse = { value: "ghp_1234567890abcdef" }; mockCredentialsService.getValue.mockResolvedValue(valueResponse); const result = await controller.getValue(mockCredentialId, mockWorkspaceId, mockUser); expect(result).toEqual(valueResponse); expect(service.getValue).toHaveBeenCalledWith(mockCredentialId, mockWorkspaceId, mockUserId); }); }); describe("update", () => { it("should update credential metadata", async () => { const updateDto = { description: "Updated description" }; const updatedCredential = { ...mockCredential, ...updateDto }; mockCredentialsService.update.mockResolvedValue(updatedCredential); const result = await controller.update( mockCredentialId, updateDto, mockWorkspaceId, mockUser ); expect(result).toEqual(updatedCredential); expect(service.update).toHaveBeenCalledWith( mockCredentialId, mockWorkspaceId, mockUserId, updateDto ); }); }); describe("rotate", () => { it("should rotate credential value", async () => { const rotateDto = { newValue: "ghp_new_token_12345" }; const rotatedCredential = { ...mockCredential, rotatedAt: new Date() }; mockCredentialsService.rotate.mockResolvedValue(rotatedCredential); const result = await controller.rotate( mockCredentialId, rotateDto, mockWorkspaceId, mockUser ); expect(result).toEqual(rotatedCredential); expect(service.rotate).toHaveBeenCalledWith( mockCredentialId, mockWorkspaceId, mockUserId, rotateDto.newValue ); }); }); describe("remove", () => { it("should soft-delete a credential", async () => { mockCredentialsService.remove.mockResolvedValue(undefined); await controller.remove(mockCredentialId, mockWorkspaceId, mockUser); expect(service.remove).toHaveBeenCalledWith(mockCredentialId, mockWorkspaceId, mockUserId); }); }); });