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 root/atb-56-theme-caching-layer 252 lines 7.3 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 { boards, categories, forums } from "@atbb/db"; 5import { eq } from "drizzle-orm"; 6import type { 7 CommitCreateEvent, 8 CommitUpdateEvent, 9 CommitDeleteEvent, 10} from "@skyware/jetstream"; 11 12describe("Indexer - Board Handlers", () => { 13 let ctx: TestContext; 14 let indexer: Indexer; 15 16 let testCategoryId: bigint; 17 18 beforeEach(async () => { 19 ctx = await createTestContext(); 20 indexer = new Indexer(ctx.db, ctx.logger); 21 22 // Get the forum ID created by createTestContext 23 const [forum] = await ctx.db 24 .select({ id: forums.id }) 25 .from(forums) 26 .where(eq(forums.did, "did:plc:test-forum")) 27 .limit(1); 28 29 // Insert test category and save the ID 30 const [category] = await ctx.db.insert(categories).values({ 31 did: "did:plc:test-forum", 32 rkey: "cat1", 33 cid: "bafycat", 34 name: "Test Category", 35 forumId: forum.id, 36 createdAt: new Date(), 37 indexedAt: new Date(), 38 }).returning(); 39 40 testCategoryId = category.id; 41 }); 42 43 afterEach(async () => { 44 // Clean up in correct FK order: boards -> categories -> forums 45 await ctx.db.delete(boards).where(eq(boards.did, "did:plc:test-forum")); 46 await ctx.cleanup(); 47 }); 48 49 it("handleBoardCreate indexes board record", async () => { 50 const event: CommitCreateEvent<"space.atbb.forum.board"> = { 51 kind: "commit", 52 commit: { 53 rev: "abc123", 54 operation: "create", 55 collection: "space.atbb.forum.board", 56 rkey: "board1", 57 record: { 58 $type: "space.atbb.forum.board", 59 name: "General Discussion", 60 description: "Talk about anything", 61 slug: "general", 62 sortOrder: 1, 63 category: { 64 category: { 65 uri: "at://did:plc:test-forum/space.atbb.forum.category/cat1", 66 cid: "bafycat", 67 }, 68 }, 69 createdAt: "2026-02-13T00:00:00Z", 70 } as any, 71 cid: "bafyboard", 72 }, 73 did: "did:plc:test-forum", 74 time_us: 1000000, 75 }; 76 77 await indexer.handleBoardCreate(event); 78 79 const [board] = await ctx.db 80 .select() 81 .from(boards) 82 .where(eq(boards.rkey, "board1")); 83 84 expect(board).toBeDefined(); 85 expect(board.name).toBe("General Discussion"); 86 expect(board.slug).toBe("general"); 87 expect(board.sortOrder).toBe(1); 88 expect(board.categoryId).toBe(testCategoryId); 89 expect(board.categoryUri).toBe( 90 "at://did:plc:test-forum/space.atbb.forum.category/cat1" 91 ); 92 }); 93 94 it("handleBoardCreate throws when category not found", async () => { 95 const event: CommitCreateEvent<"space.atbb.forum.board"> = { 96 kind: "commit", 97 commit: { 98 rev: "abc123", 99 operation: "create", 100 collection: "space.atbb.forum.board", 101 rkey: "board2", 102 record: { 103 $type: "space.atbb.forum.board", 104 name: "Orphan Board", 105 category: { 106 category: { 107 uri: "at://did:plc:test-forum/space.atbb.forum.category/nonexistent", 108 cid: "bafynonexistent", 109 }, 110 }, 111 createdAt: "2026-02-13T00:00:00Z", 112 } as any, 113 cid: "bafyboard2", 114 }, 115 did: "did:plc:test-forum", 116 time_us: 1000000, 117 }; 118 119 await expect(indexer.handleBoardCreate(event)).rejects.toThrow( 120 "Category not found: at://did:plc:test-forum/space.atbb.forum.category/nonexistent" 121 ); 122 123 const results = await ctx.db.select().from(boards); 124 expect(results).toHaveLength(0); 125 }); 126 127 it("handleBoardUpdate updates existing board", async () => { 128 // First create a board 129 const createEvent: CommitCreateEvent<"space.atbb.forum.board"> = { 130 kind: "commit", 131 commit: { 132 rev: "abc123", 133 operation: "create", 134 collection: "space.atbb.forum.board", 135 rkey: "board1", 136 record: { 137 $type: "space.atbb.forum.board", 138 name: "General Discussion", 139 description: "Talk about anything", 140 slug: "general", 141 sortOrder: 1, 142 category: { 143 category: { 144 uri: "at://did:plc:test-forum/space.atbb.forum.category/cat1", 145 cid: "bafycat", 146 }, 147 }, 148 createdAt: "2026-02-13T00:00:00Z", 149 } as any, 150 cid: "bafyboard", 151 }, 152 did: "did:plc:test-forum", 153 time_us: 1000000, 154 }; 155 156 await indexer.handleBoardCreate(createEvent); 157 158 // Now update it 159 const updateEvent: CommitUpdateEvent<"space.atbb.forum.board"> = { 160 kind: "commit", 161 commit: { 162 rev: "def456", 163 operation: "update", 164 collection: "space.atbb.forum.board", 165 rkey: "board1", 166 record: { 167 $type: "space.atbb.forum.board", 168 name: "Updated Board Name", 169 description: "Updated description", 170 slug: "updated-general", 171 sortOrder: 2, 172 category: { 173 category: { 174 uri: "at://did:plc:test-forum/space.atbb.forum.category/cat1", 175 cid: "bafycat", 176 }, 177 }, 178 createdAt: "2026-02-13T00:00:00Z", 179 } as any, 180 cid: "bafyboard-updated", 181 }, 182 did: "did:plc:test-forum", 183 time_us: 2000000, 184 }; 185 186 await indexer.handleBoardUpdate(updateEvent); 187 188 const [board] = await ctx.db 189 .select() 190 .from(boards) 191 .where(eq(boards.rkey, "board1")); 192 193 expect(board).toBeDefined(); 194 expect(board.name).toBe("Updated Board Name"); 195 expect(board.description).toBe("Updated description"); 196 expect(board.slug).toBe("updated-general"); 197 expect(board.sortOrder).toBe(2); 198 expect(board.cid).toBe("bafyboard-updated"); 199 }); 200 201 it("handleBoardDelete removes board", async () => { 202 // First create a board 203 const createEvent: CommitCreateEvent<"space.atbb.forum.board"> = { 204 kind: "commit", 205 commit: { 206 rev: "abc123", 207 operation: "create", 208 collection: "space.atbb.forum.board", 209 rkey: "board1", 210 record: { 211 $type: "space.atbb.forum.board", 212 name: "General Discussion", 213 category: { 214 category: { 215 uri: "at://did:plc:test-forum/space.atbb.forum.category/cat1", 216 cid: "bafycat", 217 }, 218 }, 219 createdAt: "2026-02-13T00:00:00Z", 220 } as any, 221 cid: "bafyboard", 222 }, 223 did: "did:plc:test-forum", 224 time_us: 1000000, 225 }; 226 227 await indexer.handleBoardCreate(createEvent); 228 229 // Verify it exists 230 let results = await ctx.db.select().from(boards); 231 expect(results).toHaveLength(1); 232 233 // Now delete it 234 const deleteEvent: CommitDeleteEvent<"space.atbb.forum.board"> = { 235 kind: "commit", 236 commit: { 237 rev: "ghi789", 238 operation: "delete", 239 collection: "space.atbb.forum.board", 240 rkey: "board1", 241 }, 242 did: "did:plc:test-forum", 243 time_us: 3000000, 244 }; 245 246 await indexer.handleBoardDelete(deleteEvent); 247 248 // Verify it's gone 249 results = await ctx.db.select().from(boards); 250 expect(results).toHaveLength(0); 251 }); 252});