import { beforeEach, describe, expect, it } from "bun:test"; import { eq } from "drizzle-orm"; import * as schema from "../../src/db/schema.ts"; import { getPublicProfile, getPublicSetupWithItems, updateProfile, } from "../../src/server/services/profile.service.ts"; import { createSetup, getAllSetups, getSetupWithItems, updateSetup, } from "../../src/server/services/setup.service.ts"; import { createTestDb } from "../helpers/db.ts"; type Db = Awaited>["db"]; describe("Profile Service", () => { let db: Db; let userId: number; beforeEach(async () => { const testData = await createTestDb(); db = testData.db; userId = testData.userId; }); describe("updateProfile", () => { it("updates displayName and returns updated user", async () => { const result = await updateProfile(db, userId, { displayName: "Alice", }); expect(result).not.toBeNull(); expect(result!.displayName).toBe("Alice"); }); it("updates bio only, leaves other fields untouched", async () => { await updateProfile(db, userId, { displayName: "Alice" }); const result = await updateProfile(db, userId, { bio: "Bikepacker" }); expect(result).not.toBeNull(); expect(result!.bio).toBe("Bikepacker"); expect(result!.displayName).toBe("Alice"); }); it("handles empty update without error", async () => { const result = await updateProfile(db, userId, {}); expect(result).not.toBeNull(); expect(result!.id).toBe(userId); }); it("returns null for non-existent user", async () => { const result = await updateProfile(db, 99999, { displayName: "Ghost", }); expect(result).toBeNull(); }); }); describe("getPublicProfile", () => { it("returns user profile with empty setups when none exist", async () => { await updateProfile(db, userId, { displayName: "Alice", bio: "Bikepacker", }); const profile = await getPublicProfile(db, userId); expect(profile).not.toBeNull(); expect(profile!.displayName).toBe("Alice"); expect(profile!.bio).toBe("Bikepacker"); expect(profile!.setups).toEqual([]); }); it("returns only public setups, not private ones", async () => { // Create one public and one private setup const _pub = await createSetup(db, userId, { name: "Public Setup", visibility: "public", }); const _priv = await createSetup(db, userId, { name: "Private Setup" }); const profile = await getPublicProfile(db, userId); expect(profile).not.toBeNull(); expect(profile!.setups).toHaveLength(1); expect(profile!.setups[0].name).toBe("Public Setup"); }); it("returns null for non-existent user", async () => { const profile = await getPublicProfile(db, 99999); expect(profile).toBeNull(); }); }); describe("getPublicSetupWithItems", () => { it("returns setup with items when visibility is public", async () => { const setup = await createSetup(db, userId, { name: "Public Setup", visibility: "public", }); // Create an item and add to setup const [cat] = await db .select() .from(schema.categories) .where(eq(schema.categories.userId, userId)); const [item] = await db .insert(schema.items) .values({ name: "Tent", categoryId: cat.id, userId, weightGrams: 1200, priceCents: 30000, }) .returning(); await db.insert(schema.setupItems).values({ setupId: setup.id, itemId: item.id, }); const result = await getPublicSetupWithItems(db, setup.id); expect(result).not.toBeNull(); expect(result!.name).toBe("Public Setup"); expect(result!.items).toHaveLength(1); expect(result!.items[0].name).toBe("Tent"); }); it("returns null when visibility is private", async () => { const setup = await createSetup(db, userId, { name: "Private Setup", }); const result = await getPublicSetupWithItems(db, setup.id); expect(result).toBeNull(); }); it("returns null for non-existent setup", async () => { const result = await getPublicSetupWithItems(db, 99999); expect(result).toBeNull(); }); }); }); describe("Setup Service - visibility", () => { let db: Db; let userId: number; beforeEach(async () => { const testData = await createTestDb(); db = testData.db; userId = testData.userId; }); it("createSetup persists visibility when public", async () => { const setup = await createSetup(db, userId, { name: "Public", visibility: "public", }); expect(setup.visibility).toBe("public"); }); it("createSetup defaults visibility to private", async () => { const setup = await createSetup(db, userId, { name: "Private" }); expect(setup.visibility).toBe("private"); }); it("updateSetup can change visibility", async () => { const setup = await createSetup(db, userId, { name: "Test" }); expect(setup.visibility).toBe("private"); const updated = await updateSetup(db, userId, setup.id, { name: "Test", visibility: "public", }); expect(updated).not.toBeNull(); expect(updated!.visibility).toBe("public"); }); it("getAllSetups includes visibility in response", async () => { await createSetup(db, userId, { name: "Public", visibility: "public" }); await createSetup(db, userId, { name: "Private" }); const setups = await getAllSetups(db, userId); expect(setups).toHaveLength(2); const pub = setups.find((s) => s.name === "Public"); const priv = setups.find((s) => s.name === "Private"); expect(pub!.visibility).toBe("public"); expect(priv!.visibility).toBe("private"); }); it("getSetupWithItems includes visibility", async () => { const setup = await createSetup(db, userId, { name: "Test", visibility: "public", }); const result = await getSetupWithItems(db, userId, setup.id); expect(result).not.toBeNull(); expect(result!.visibility).toBe("public"); }); });