import { describe, it, expect, vi } from "vitest"; import { seedDefaultRoles, DEFAULT_ROLES } from "../lib/steps/seed-roles.js"; describe("seedDefaultRoles", () => { const forumDid = "did:plc:testforum"; function mockDb(existingRoleNames: string[] = []) { const existingQueue = [...existingRoleNames]; let roleIdCounter = 1n; return { select: vi.fn().mockReturnValue({ from: vi.fn().mockReturnValue({ where: vi.fn().mockReturnValue({ limit: vi.fn().mockImplementation(() => { const roleName = existingQueue.shift(); if (roleName) { return [{ name: roleName, did: forumDid, rkey: roleName.toLowerCase(), cid: `bafyexisting-${roleName.toLowerCase()}`, }]; } return []; }), }), }), }), insert: vi.fn().mockImplementation(() => { const id = roleIdCounter++; // values() returns a Promise (for rolePermissions inserts that are awaited directly) // but also has a .returning() method (for role inserts) const resolvedPromise = Promise.resolve(undefined); const valuesResult = Object.assign(resolvedPromise, { returning: vi.fn().mockResolvedValue([{ id }]), }); return { values: vi.fn().mockReturnValue(valuesResult), }; }), } as any; } function mockAgent() { let callCount = 0; return { com: { atproto: { repo: { createRecord: vi.fn().mockImplementation(() => { callCount++; return Promise.resolve({ data: { uri: `at://${forumDid}/space.atbb.forum.role/tid${callCount}`, cid: `bafynew${callCount}`, }, }); }), }, }, }, } as any; } it("exports DEFAULT_ROLES with correct structure", () => { expect(DEFAULT_ROLES).toHaveLength(4); expect(DEFAULT_ROLES[0].name).toBe("Owner"); expect(DEFAULT_ROLES[0].priority).toBe(0); expect(DEFAULT_ROLES[3].name).toBe("Member"); expect(DEFAULT_ROLES[3].priority).toBe(30); }); it("creates all roles on PDS and DB when none exist", async () => { const db = mockDb(); const agent = mockAgent(); const result = await seedDefaultRoles(db, agent, forumDid); expect(result.created).toBe(4); expect(result.skipped).toBe(0); expect(agent.com.atproto.repo.createRecord).toHaveBeenCalledTimes(4); // Verify DB insertions: 4 role inserts + 4 rolePermissions inserts (one per role) expect(db.insert).toHaveBeenCalledTimes(8); // Verify returned role data expect(result.roles).toHaveLength(4); expect(result.roles[0].name).toBe("Owner"); expect(result.roles[0].uri).toContain("space.atbb.forum.role/"); expect(result.roles[0].cid).toBeTruthy(); }); it("skips existing roles and returns their data", async () => { // Simulate Owner and Admin already existing const db = mockDb(["Owner", "Admin"]); const agent = mockAgent(); const result = await seedDefaultRoles(db, agent, forumDid); expect(result.skipped).toBe(2); expect(result.created).toBe(2); // All 4 roles should be in the return value expect(result.roles).toHaveLength(4); // Existing roles use data from DB expect(result.roles[0].name).toBe("Owner"); expect(result.roles[0].cid).toBe("bafyexisting-owner"); // New roles use data from PDS response expect(result.roles[2].name).toBe("Moderator"); expect(result.roles[2].cid).toMatch(/^bafynew/); }); });