WIP! A BB-style forum, on the ATmosphere! We're still working... we'll be back soon when we have something to show off!
node typescript hono htmx atproto
at atb-52-css-token-extraction 200 lines 5.6 kB view raw
1import { describe, it, expect, beforeEach, afterEach } from "vitest"; 2import { Indexer } from "../indexer.js"; 3import { createTestContext, type TestContext } from "./test-context.js"; 4import { roles, rolePermissions } from "@atbb/db"; 5import { eq } from "drizzle-orm"; 6import type { 7 CommitCreateEvent, 8 CommitUpdateEvent, 9 CommitDeleteEvent, 10} from "@skyware/jetstream"; 11 12describe("Indexer - Role Handlers", () => { 13 let ctx: TestContext; 14 let indexer: Indexer; 15 16 beforeEach(async () => { 17 ctx = await createTestContext(); 18 indexer = new Indexer(ctx.db, ctx.logger); 19 }); 20 21 afterEach(async () => { 22 await ctx.db.delete(roles).where(eq(roles.did, "did:plc:test-forum")); 23 await ctx.cleanup(); 24 }); 25 26 it("handleRoleCreate indexes role record with all fields", async () => { 27 const event: CommitCreateEvent<"space.atbb.forum.role"> = { 28 kind: "commit", 29 commit: { 30 rev: "abc123", 31 operation: "create", 32 collection: "space.atbb.forum.role", 33 rkey: "role1", 34 record: { 35 $type: "space.atbb.forum.role", 36 name: "Moderator", 37 description: "Can moderate posts", 38 permissions: ["space.atbb.permission.moderatePosts"], 39 priority: 10, 40 createdAt: "2026-02-15T00:00:00Z", 41 } as any, 42 cid: "bafyrole", 43 }, 44 did: "did:plc:test-forum", 45 time_us: 1000000, 46 }; 47 48 await indexer.handleRoleCreate(event); 49 50 const [role] = await ctx.db 51 .select() 52 .from(roles) 53 .where(eq(roles.rkey, "role1")) 54 .limit(1); 55 56 expect(role).toBeDefined(); 57 expect(role.name).toBe("Moderator"); 58 expect(role.description).toBe("Can moderate posts"); 59 expect(role.priority).toBe(10); 60 61 const perms = await ctx.db 62 .select({ permission: rolePermissions.permission }) 63 .from(rolePermissions) 64 .where(eq(rolePermissions.roleId, role.id)); 65 expect(perms.map((p) => p.permission)).toEqual([ 66 "space.atbb.permission.moderatePosts", 67 ]); 68 }); 69 70 it("handleRoleCreate indexes role without optional description", async () => { 71 const event: CommitCreateEvent<"space.atbb.forum.role"> = { 72 kind: "commit", 73 commit: { 74 rev: "abc123", 75 operation: "create", 76 collection: "space.atbb.forum.role", 77 rkey: "role2", 78 record: { 79 $type: "space.atbb.forum.role", 80 name: "Member", 81 permissions: ["space.atbb.permission.createPosts"], 82 priority: 50, 83 createdAt: "2026-02-15T00:00:00Z", 84 } as any, 85 cid: "bafyrole2", 86 }, 87 did: "did:plc:test-forum", 88 time_us: 1000000, 89 }; 90 91 await indexer.handleRoleCreate(event); 92 93 const [role] = await ctx.db 94 .select() 95 .from(roles) 96 .where(eq(roles.rkey, "role2")) 97 .limit(1); 98 99 expect(role).toBeDefined(); 100 expect(role.description).toBeNull(); 101 }); 102 103 it("handleRoleUpdate updates role fields", async () => { 104 // First create a role (no permissions column — permissions live in role_permissions) 105 await ctx.db.insert(roles).values({ 106 did: "did:plc:test-forum", 107 rkey: "role3", 108 cid: "bafyold", 109 name: "Old Name", 110 description: "Old description", 111 priority: 30, 112 createdAt: new Date(), 113 indexedAt: new Date(), 114 }); 115 116 const event: CommitUpdateEvent<"space.atbb.forum.role"> = { 117 kind: "commit", 118 commit: { 119 rev: "def456", 120 operation: "update", 121 collection: "space.atbb.forum.role", 122 rkey: "role3", 123 record: { 124 $type: "space.atbb.forum.role", 125 name: "Updated Name", 126 description: "Updated description", 127 permissions: [ 128 "space.atbb.permission.createPosts", 129 "space.atbb.permission.moderatePosts", 130 ], 131 priority: 20, 132 createdAt: "2026-02-15T00:00:00Z", 133 } as any, 134 cid: "bafynew", 135 }, 136 did: "did:plc:test-forum", 137 time_us: 2000000, 138 }; 139 140 await indexer.handleRoleUpdate(event); 141 142 const [role] = await ctx.db 143 .select() 144 .from(roles) 145 .where(eq(roles.rkey, "role3")) 146 .limit(1); 147 148 expect(role.name).toBe("Updated Name"); 149 expect(role.description).toBe("Updated description"); 150 expect(role.priority).toBe(20); 151 expect(role.cid).toBe("bafynew"); 152 153 const perms = await ctx.db 154 .select({ permission: rolePermissions.permission }) 155 .from(rolePermissions) 156 .where(eq(rolePermissions.roleId, role.id)); 157 expect(perms).toHaveLength(2); 158 expect(perms.map((p) => p.permission)).toEqual( 159 expect.arrayContaining([ 160 "space.atbb.permission.createPosts", 161 "space.atbb.permission.moderatePosts", 162 ]) 163 ); 164 }); 165 166 it("handleRoleDelete removes role record", async () => { 167 // First create a role (no permissions column — permissions live in role_permissions) 168 await ctx.db.insert(roles).values({ 169 did: "did:plc:test-forum", 170 rkey: "role4", 171 cid: "bafyrole4", 172 name: "To Delete", 173 priority: 99, 174 createdAt: new Date(), 175 indexedAt: new Date(), 176 }); 177 178 const event: CommitDeleteEvent<"space.atbb.forum.role"> = { 179 kind: "commit", 180 commit: { 181 rev: "ghi789", 182 operation: "delete", 183 collection: "space.atbb.forum.role", 184 rkey: "role4", 185 }, 186 did: "did:plc:test-forum", 187 time_us: 3000000, 188 }; 189 190 await indexer.handleRoleDelete(event); 191 192 const result = await ctx.db 193 .select() 194 .from(roles) 195 .where(eq(roles.rkey, "role4")) 196 .limit(1); 197 198 expect(result).toHaveLength(0); 199 }); 200});