/** * Tests for GET /api/profile/me/demographics * * Covers: * - returns all-null fields when Profile row has no demographics yet * - returns 401 when not authenticated * - returns saved values when row is populated * - returns withdrawnAt when data was withdrawn */ import { describe, expect, it, vi, beforeEach } from "vitest"; const mocks = vi.hoisted(() => ({ profile: { findUnique: vi.fn(), }, requireUser: vi.fn(), })); vi.mock("../../server/utils/prisma", () => ({ usePrisma: () => ({ profile: mocks.profile }), })); vi.mock("../../server/utils/auth", () => ({ requireUser: mocks.requireUser, })); import { getDemographics } from "../../server/db/profile"; beforeEach(() => { vi.clearAllMocks(); }); // ─── getDemographics DB-layer ───────────────────────────────────────────── describe("getDemographics — all-null row", () => { it("returns null for all 9 demographic fields + consent fields when not yet filled", async () => { mocks.profile.findUnique.mockResolvedValueOnce({ birthYear: null, gender: null, maritalStatus: null, employmentStatus: null, shiftWork: null, industry: null, jobTenure: null, bundesland: null, city: null, demographicsConsentAt: null, demographicsWithdrawnAt: null, }); const result = await getDemographics("user-1"); expect(result).toEqual({ birthYear: null, gender: null, maritalStatus: null, employmentStatus: null, shiftWork: null, industry: null, jobTenure: null, bundesland: null, city: null, consentAt: null, withdrawnAt: null, }); expect(mocks.profile.findUnique).toHaveBeenCalledWith({ where: { id: "user-1" }, select: expect.objectContaining({ birthYear: true, gender: true, demographicsConsentAt: true, demographicsWithdrawnAt: true, }), }); }); }); describe("getDemographics — 404 when profile missing", () => { it("throws 404 when profile row does not exist", async () => { mocks.profile.findUnique.mockResolvedValueOnce(null); await expect(getDemographics("ghost-user")).rejects.toMatchObject({ statusCode: 404, }); }); }); describe("getDemographics — populated row", () => { it("returns ISO strings for dates and correct field values", async () => { const consentDate = new Date("2026-04-01T10:00:00Z"); mocks.profile.findUnique.mockResolvedValueOnce({ birthYear: 1989, gender: "male", maritalStatus: "single", employmentStatus: "employed", shiftWork: false, industry: "IT", jobTenure: "3_5y", bundesland: "DE-BY", city: "München", demographicsConsentAt: consentDate, demographicsWithdrawnAt: null, }); const result = await getDemographics("user-2"); expect(result.birthYear).toBe(1989); expect(result.gender).toBe("male"); expect(result.consentAt).toBe("2026-04-01T10:00:00.000Z"); expect(result.withdrawnAt).toBeNull(); }); }); describe("getDemographics — withdrawn row", () => { it("returns withdrawnAt as ISO string when data was withdrawn", async () => { const consentDate = new Date("2026-03-01T00:00:00Z"); const withdrawnDate = new Date("2026-04-15T12:00:00Z"); mocks.profile.findUnique.mockResolvedValueOnce({ birthYear: null, gender: null, maritalStatus: null, employmentStatus: null, shiftWork: null, industry: null, jobTenure: null, bundesland: null, city: null, demographicsConsentAt: consentDate, demographicsWithdrawnAt: withdrawnDate, }); const result = await getDemographics("user-3"); expect(result.consentAt).toBe("2026-03-01T00:00:00.000Z"); expect(result.withdrawnAt).toBe("2026-04-15T12:00:00.000Z"); // all data fields nulled after withdrawal expect(result.birthYear).toBeNull(); expect(result.city).toBeNull(); }); }); // ─── 401 guard (endpoint-level) ─────────────────────────────────────────── // We test the auth guard by importing the handler and simulating a // requireUser rejection — no real Nitro boot needed. describe("demographics.get endpoint — 401 when not authenticated", () => { it("propagates the 401 error from requireUser", async () => { const authError = Object.assign(new Error("Unauthorized"), { statusCode: 401, }); mocks.requireUser.mockRejectedValueOnce(authError); // Import handler (defineEventHandler stub in setup.ts returns the fn as-is) const mod = await import( "../../server/api/profile/me/demographics.get" ); const handler = typeof mod.default === "function" ? mod.default : (mod.default as { handler?: unknown }).handler; await expect( (handler as (e: unknown) => Promise)({ body: null }), ).rejects.toMatchObject({ statusCode: 401 }); }); });