import { describe, it, expect, beforeEach, vi } from "vitest"; import { UnauthorizedException } from "@nestjs/common"; import { PreferencesController } from "./preferences.controller"; import { PreferencesService } from "./preferences.service"; import type { UpdatePreferencesDto, PreferencesResponseDto } from "./dto"; import type { AuthenticatedRequest } from "../common/types/user.types"; describe("PreferencesController", () => { let controller: PreferencesController; let service: PreferencesService; const mockPreferencesService = { getPreferences: vi.fn(), updatePreferences: vi.fn(), }; const mockUserId = "user-uuid-123"; const mockPreferencesResponse: PreferencesResponseDto = { id: "pref-uuid-456", userId: mockUserId, theme: "system", locale: "en", timezone: null, settings: {}, updatedAt: new Date("2026-01-01T00:00:00Z"), }; function makeRequest(userId?: string): AuthenticatedRequest { return { user: userId ? { id: userId } : undefined, } as unknown as AuthenticatedRequest; } beforeEach(() => { service = mockPreferencesService as unknown as PreferencesService; controller = new PreferencesController(service); vi.clearAllMocks(); }); describe("GET /api/users/me/preferences", () => { it("should return preferences for authenticated user", async () => { mockPreferencesService.getPreferences.mockResolvedValue(mockPreferencesResponse); const result = await controller.getPreferences(makeRequest(mockUserId)); expect(result).toEqual(mockPreferencesResponse); expect(mockPreferencesService.getPreferences).toHaveBeenCalledWith(mockUserId); }); it("should throw UnauthorizedException when user is not authenticated", async () => { await expect(controller.getPreferences(makeRequest())).rejects.toThrow(UnauthorizedException); expect(mockPreferencesService.getPreferences).not.toHaveBeenCalled(); }); }); describe("PUT /api/users/me/preferences", () => { const updateDto: UpdatePreferencesDto = { theme: "dark", locale: "fr", timezone: "Europe/Paris", }; it("should update and return preferences for authenticated user", async () => { const updatedResponse: PreferencesResponseDto = { ...mockPreferencesResponse, theme: "dark", locale: "fr", timezone: "Europe/Paris", }; mockPreferencesService.updatePreferences.mockResolvedValue(updatedResponse); const result = await controller.updatePreferences(updateDto, makeRequest(mockUserId)); expect(result).toEqual(updatedResponse); expect(mockPreferencesService.updatePreferences).toHaveBeenCalledWith(mockUserId, updateDto); }); it("should throw UnauthorizedException when user is not authenticated", async () => { await expect(controller.updatePreferences(updateDto, makeRequest())).rejects.toThrow( UnauthorizedException ); expect(mockPreferencesService.updatePreferences).not.toHaveBeenCalled(); }); }); describe("PATCH /api/users/me/preferences", () => { const patchDto: UpdatePreferencesDto = { theme: "light", }; it("should partially update and return preferences for authenticated user", async () => { const patchedResponse: PreferencesResponseDto = { ...mockPreferencesResponse, theme: "light", }; mockPreferencesService.updatePreferences.mockResolvedValue(patchedResponse); const result = await controller.patchPreferences(patchDto, makeRequest(mockUserId)); expect(result).toEqual(patchedResponse); expect(mockPreferencesService.updatePreferences).toHaveBeenCalledWith(mockUserId, patchDto); }); it("should throw UnauthorizedException when user is not authenticated", async () => { await expect(controller.patchPreferences(patchDto, makeRequest())).rejects.toThrow( UnauthorizedException ); expect(mockPreferencesService.updatePreferences).not.toHaveBeenCalled(); }); }); });