import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { Test, TestingModule } from "@nestjs/testing"; import { ExecutionContext } from "@nestjs/common"; import { WorkspaceSettingsController } from "./workspace-settings.controller"; import { WorkspaceSettingsService } from "./workspace-settings.service"; import { AuthGuard } from "../auth/guards/auth.guard"; import type { WorkspaceLlmSettings, LlmProviderInstance, Personality } from "@prisma/client"; import type { AuthenticatedRequest } from "../common/types/user.types"; describe("WorkspaceSettingsController", () => { let controller: WorkspaceSettingsController; let service: WorkspaceSettingsService; const mockWorkspaceId = "workspace-123"; const mockUserId = "user-123"; const mockSettings: WorkspaceLlmSettings = { id: "settings-123", workspaceId: mockWorkspaceId, defaultLlmProviderId: "provider-123", defaultPersonalityId: "personality-123", settings: {}, createdAt: new Date(), updatedAt: new Date(), }; const mockProvider: LlmProviderInstance = { id: "provider-123", providerType: "ollama", displayName: "Test Provider", userId: null, config: { endpoint: "http://localhost:11434" }, isDefault: true, isEnabled: true, createdAt: new Date(), updatedAt: new Date(), }; const mockPersonality: Personality = { id: "personality-123", workspaceId: mockWorkspaceId, name: "default", displayName: "Default", description: "Default personality", systemPrompt: "You are a helpful assistant", temperature: null, maxTokens: null, llmProviderInstanceId: null, isDefault: true, isEnabled: true, createdAt: new Date(), updatedAt: new Date(), }; const mockAuthGuard = { canActivate: vi.fn((context: ExecutionContext) => { const request = context.switchToHttp().getRequest(); request.user = { id: mockUserId, email: "test@example.com", name: "Test User", emailVerified: true, image: null, authProviderId: null, preferences: {}, createdAt: new Date(), updatedAt: new Date(), }; return true; }), }; const mockAuthRequest: AuthenticatedRequest = { user: { id: mockUserId, email: "test@example.com", name: "Test User", emailVerified: true, image: null, authProviderId: null, preferences: {}, createdAt: new Date(), updatedAt: new Date(), }, } as AuthenticatedRequest; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ controllers: [WorkspaceSettingsController], providers: [ { provide: WorkspaceSettingsService, useValue: { getSettings: vi.fn(), updateSettings: vi.fn(), getEffectiveLlmProvider: vi.fn(), getEffectivePersonality: vi.fn(), }, }, ], }) .overrideGuard(AuthGuard) .useValue(mockAuthGuard) .compile(); controller = module.get(WorkspaceSettingsController); service = module.get(WorkspaceSettingsService); }); afterEach(() => { vi.clearAllMocks(); }); describe("getSettings", () => { it("should return workspace settings", async () => { vi.spyOn(service, "getSettings").mockResolvedValue(mockSettings); const result = await controller.getSettings(mockWorkspaceId); expect(result).toEqual(mockSettings); expect(service.getSettings).toHaveBeenCalledWith(mockWorkspaceId); }); it("should handle service errors", async () => { vi.spyOn(service, "getSettings").mockRejectedValue(new Error("Service error")); await expect(controller.getSettings(mockWorkspaceId)).rejects.toThrow("Service error"); }); it("should work with valid workspace ID", async () => { vi.spyOn(service, "getSettings").mockResolvedValue(mockSettings); const result = await controller.getSettings(mockWorkspaceId); expect(result.workspaceId).toBe(mockWorkspaceId); }); }); describe("updateSettings", () => { it("should update workspace settings", async () => { const updateDto = { defaultLlmProviderId: "new-provider-123", defaultPersonalityId: "new-personality-123", }; const updatedSettings = { ...mockSettings, ...updateDto }; vi.spyOn(service, "updateSettings").mockResolvedValue(updatedSettings); const result = await controller.updateSettings(mockWorkspaceId, updateDto); expect(result).toEqual(updatedSettings); expect(service.updateSettings).toHaveBeenCalledWith(mockWorkspaceId, updateDto); }); it("should allow partial updates", async () => { const updateDto = { defaultLlmProviderId: "new-provider-123", }; const updatedSettings = { ...mockSettings, defaultLlmProviderId: updateDto.defaultLlmProviderId, }; vi.spyOn(service, "updateSettings").mockResolvedValue(updatedSettings); const result = await controller.updateSettings(mockWorkspaceId, updateDto); expect(result.defaultLlmProviderId).toBe(updateDto.defaultLlmProviderId); }); it("should handle null values", async () => { const updateDto = { defaultLlmProviderId: null, }; const updatedSettings = { ...mockSettings, defaultLlmProviderId: null }; vi.spyOn(service, "updateSettings").mockResolvedValue(updatedSettings); const result = await controller.updateSettings(mockWorkspaceId, updateDto); expect(result.defaultLlmProviderId).toBeNull(); }); it("should handle service errors", async () => { const updateDto = { defaultLlmProviderId: "invalid-id" }; vi.spyOn(service, "updateSettings").mockRejectedValue(new Error("Provider not found")); await expect(controller.updateSettings(mockWorkspaceId, updateDto)).rejects.toThrow( "Provider not found" ); }); }); describe("getEffectiveProvider", () => { it("should return effective provider with authenticated user", async () => { vi.spyOn(service, "getEffectiveLlmProvider").mockResolvedValue(mockProvider); const result = await controller.getEffectiveProvider(mockWorkspaceId, mockAuthRequest); expect(result).toEqual(mockProvider); expect(service.getEffectiveLlmProvider).toHaveBeenCalledWith(mockWorkspaceId, mockUserId); }); it("should return effective provider without user ID when not authenticated", async () => { const unauthRequest = { user: undefined } as AuthenticatedRequest; vi.spyOn(service, "getEffectiveLlmProvider").mockResolvedValue(mockProvider); const result = await controller.getEffectiveProvider(mockWorkspaceId, unauthRequest); expect(result).toEqual(mockProvider); expect(service.getEffectiveLlmProvider).toHaveBeenCalledWith(mockWorkspaceId, undefined); }); it("should handle no provider available error", async () => { vi.spyOn(service, "getEffectiveLlmProvider").mockRejectedValue( new Error("No LLM provider available") ); await expect( controller.getEffectiveProvider(mockWorkspaceId, mockAuthRequest) ).rejects.toThrow("No LLM provider available"); }); it("should pass user ID to service when available", async () => { vi.spyOn(service, "getEffectiveLlmProvider").mockResolvedValue(mockProvider); await controller.getEffectiveProvider(mockWorkspaceId, mockAuthRequest); expect(service.getEffectiveLlmProvider).toHaveBeenCalledWith(mockWorkspaceId, mockUserId); }); }); describe("getEffectivePersonality", () => { it("should return effective personality", async () => { vi.spyOn(service, "getEffectivePersonality").mockResolvedValue(mockPersonality); const result = await controller.getEffectivePersonality(mockWorkspaceId); expect(result).toEqual(mockPersonality); expect(service.getEffectivePersonality).toHaveBeenCalledWith(mockWorkspaceId); }); it("should handle no personality available error", async () => { vi.spyOn(service, "getEffectivePersonality").mockRejectedValue( new Error("No personality available") ); await expect(controller.getEffectivePersonality(mockWorkspaceId)).rejects.toThrow( "No personality available" ); }); it("should work with valid workspace ID", async () => { vi.spyOn(service, "getEffectivePersonality").mockResolvedValue(mockPersonality); const result = await controller.getEffectivePersonality(mockWorkspaceId); expect(result.workspaceId).toBe(mockWorkspaceId); }); }); describe("endpoint paths", () => { it("should be accessible at /workspaces/:workspaceId/settings/llm", () => { const metadata = Reflect.getMetadata("path", WorkspaceSettingsController); expect(metadata).toBe("workspaces/:workspaceId/settings/llm"); }); }); });