Implements GET/PATCH/PUT /users/me/preferences. Fixes profile page 'Preferences unavailable' error by correcting the /api prefix in frontend calls and adding PATCH handler to controller. Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
113 lines
4.0 KiB
TypeScript
113 lines
4.0 KiB
TypeScript
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();
|
|
});
|
|
});
|
|
});
|