import { describe, expect, it } from "vitest"; import type { User } from "../drizzle/schema"; import type { TrpcContext } from "./_core/context"; import { protectedProcedure, router, superAdminProcedure } from "./_core/trpc"; const testRouter = router({ read: protectedProcedure.query(() => "read-ok"), write: protectedProcedure.mutation(() => "write-ok"), manageUsers: superAdminProcedure.query(() => "users-ok"), }); function user(role: User["role"], mustChangePassword = 0): User { const now = new Date(); return { id: 1, username: `${role}-account`, passwordHash: "unused", name: role, email: null, role, isActive: 1, mustChangePassword, sessionVersion: 0, createdAt: now, updatedAt: now, lastLoginAt: null, }; } function context(currentUser: User | null): TrpcContext { return { user: currentUser, req: {} as TrpcContext["req"], res: {} as TrpcContext["res"] }; } describe("三角色权限矩阵", () => { it("未登录不能读取", async () => { await expect(testRouter.createCaller(context(null)).read()).rejects.toMatchObject({ code: "UNAUTHORIZED" }); }); it("首次改密前不能读取业务数据", async () => { await expect(testRouter.createCaller(context(user("super_admin", 1))).read()).rejects.toMatchObject({ code: "FORBIDDEN" }); }); it("普通用户可读但不可写,也不可管理用户", async () => { const caller = testRouter.createCaller(context(user("user"))); await expect(caller.read()).resolves.toBe("read-ok"); await expect(caller.write()).rejects.toMatchObject({ code: "FORBIDDEN" }); await expect(caller.manageUsers()).rejects.toMatchObject({ code: "FORBIDDEN" }); }); it("管理员可读写但不可管理用户", async () => { const caller = testRouter.createCaller(context(user("admin"))); await expect(caller.read()).resolves.toBe("read-ok"); await expect(caller.write()).resolves.toBe("write-ok"); await expect(caller.manageUsers()).rejects.toMatchObject({ code: "FORBIDDEN" }); }); it("超级管理员拥有全部权限", async () => { const caller = testRouter.createCaller(context(user("super_admin"))); await expect(caller.read()).resolves.toBe("read-ok"); await expect(caller.write()).resolves.toBe("write-ok"); await expect(caller.manageUsers()).resolves.toBe("users-ok"); }); });