import { convexTest } from "convex-test"; import { describe, it, expect } from "vitest"; import { api } from "./_generated/api"; import schema from "./schema"; const modules = import.meta.glob("./**/*.ts"); describe("users", () => { it("stores a new user on first login", async () => { const t = convexTest(schema, modules); const asSarah = t.withIdentity({ name: "Sarah", email: "sarah@example.com", subject: "clerk_sarah_123", }); const userId = await asSarah.mutation(api.users.store, {}); expect(userId).toBeTruthy(); const user = await asSarah.query(api.users.current, {}); expect(user).toMatchObject({ name: "Sarah", email: "sarah@example.com", role: "customer", }); }); it("returns same user ID on subsequent logins", async () => { const t = convexTest(schema, modules); const asSarah = t.withIdentity({ name: "Sarah", email: "sarah@example.com", subject: "clerk_sarah_123", }); const id1 = await asSarah.mutation(api.users.store, {}); const id2 = await asSarah.mutation(api.users.store, {}); expect(id1).toEqual(id2); }); it("updates name if it changed", async () => { const t = convexTest(schema, modules); const asSarah = t.withIdentity({ name: "Sarah", email: "sarah@example.com", subject: "clerk_sarah_123", }); await asSarah.mutation(api.users.store, {}); const asSarahRenamed = t.withIdentity({ name: "Sarah Connor", email: "sarah@example.com", subject: "clerk_sarah_123", }); await asSarahRenamed.mutation(api.users.store, {}); const user = await asSarahRenamed.query(api.users.current, {}); expect(user?.name).toBe("Sarah Connor"); }); it("returns null for unauthenticated user", async () => { const t = convexTest(schema, modules); const result = await t.query(api.users.current, {}); expect(result).toBeNull(); }); it("returns user for authenticated user", async () => { const t = convexTest(schema, modules); const asSarah = t.withIdentity({ name: "Sarah", email: "sarah@example.com", subject: "clerk_sarah_123", }); await asSarah.mutation(api.users.store, {}); const user = await asSarah.query(api.users.current, {}); expect(user).not.toBeNull(); expect(user?.email).toBe("sarah@example.com"); }); it("updateProfile updates only name, phone, avatarUrl for current user", async () => { const t = convexTest(schema, modules); const asSarah = t.withIdentity({ name: "Sarah", email: "sarah@example.com", subject: "clerk_sarah_123", }); await asSarah.mutation(api.users.store, {}); await asSarah.mutation(api.users.updateProfile, { name: "Sarah Jane", phone: "555-0000", avatarUrl: "https://example.com/avatar.png", }); const user = await asSarah.query(api.users.current, {}); expect(user?.name).toBe("Sarah Jane"); expect(user?.phone).toBe("555-0000"); expect(user?.avatarUrl).toBe("https://example.com/avatar.png"); expect(user?.email).toBe("sarah@example.com"); }); it("listCustomers returns only customers and is admin-only", async () => { const t = convexTest(schema, modules); const asCustomer = t.withIdentity({ name: "Customer", email: "customer@example.com", subject: "clerk_customer_789", }); const asAdmin = t.withIdentity({ name: "Admin", email: "admin@example.com", subject: "clerk_admin_456", }); await asCustomer.mutation(api.users.store, {}); const adminId = await asAdmin.mutation(api.users.store, {}); await t.run(async (ctx) => { await ctx.db.patch(adminId, { role: "admin" }); }); await expect( asCustomer.query(api.users.listCustomers, { paginationOpts: { numItems: 10, cursor: null }, }), ).rejects.toThrow(/Unauthorized|admin/); const result = await asAdmin.query(api.users.listCustomers, { paginationOpts: { numItems: 10, cursor: null }, }); expect(result.page.length).toBeGreaterThanOrEqual(1); expect(result.page.every((u: { role: string }) => u.role === "customer")).toBe( true, ); }); });