import { describe, it, expect, beforeEach, afterEach } from "vitest"; import { Indexer } from "../indexer.js"; import { createTestContext, type TestContext } from "./test-context.js"; import { boards, categories, forums } from "@atbb/db"; import { eq } from "drizzle-orm"; import type { CommitCreateEvent, CommitUpdateEvent, CommitDeleteEvent, } from "@skyware/jetstream"; describe("Indexer - Board Handlers", () => { let ctx: TestContext; let indexer: Indexer; let testCategoryId: bigint; beforeEach(async () => { ctx = await createTestContext(); indexer = new Indexer(ctx.db, ctx.logger); // Get the forum ID created by createTestContext const [forum] = await ctx.db .select({ id: forums.id }) .from(forums) .where(eq(forums.did, "did:plc:test-forum")) .limit(1); // Insert test category and save the ID const [category] = await ctx.db.insert(categories).values({ did: "did:plc:test-forum", rkey: "cat1", cid: "bafycat", name: "Test Category", forumId: forum.id, createdAt: new Date(), indexedAt: new Date(), }).returning(); testCategoryId = category.id; }); afterEach(async () => { // Clean up in correct FK order: boards -> categories -> forums await ctx.db.delete(boards).where(eq(boards.did, "did:plc:test-forum")); await ctx.cleanup(); }); it("handleBoardCreate indexes board record", async () => { const event: CommitCreateEvent<"space.atbb.forum.board"> = { kind: "commit", commit: { rev: "abc123", operation: "create", collection: "space.atbb.forum.board", rkey: "board1", record: { $type: "space.atbb.forum.board", name: "General Discussion", description: "Talk about anything", slug: "general", sortOrder: 1, category: { category: { uri: "at://did:plc:test-forum/space.atbb.forum.category/cat1", cid: "bafycat", }, }, createdAt: "2026-02-13T00:00:00Z", } as any, cid: "bafyboard", }, did: "did:plc:test-forum", time_us: 1000000, }; await indexer.handleBoardCreate(event); const [board] = await ctx.db .select() .from(boards) .where(eq(boards.rkey, "board1")); expect(board).toBeDefined(); expect(board.name).toBe("General Discussion"); expect(board.slug).toBe("general"); expect(board.sortOrder).toBe(1); expect(board.categoryId).toBe(testCategoryId); expect(board.categoryUri).toBe( "at://did:plc:test-forum/space.atbb.forum.category/cat1" ); }); it("handleBoardCreate throws when category not found", async () => { const event: CommitCreateEvent<"space.atbb.forum.board"> = { kind: "commit", commit: { rev: "abc123", operation: "create", collection: "space.atbb.forum.board", rkey: "board2", record: { $type: "space.atbb.forum.board", name: "Orphan Board", category: { category: { uri: "at://did:plc:test-forum/space.atbb.forum.category/nonexistent", cid: "bafynonexistent", }, }, createdAt: "2026-02-13T00:00:00Z", } as any, cid: "bafyboard2", }, did: "did:plc:test-forum", time_us: 1000000, }; await expect(indexer.handleBoardCreate(event)).rejects.toThrow( "Category not found: at://did:plc:test-forum/space.atbb.forum.category/nonexistent" ); const results = await ctx.db.select().from(boards); expect(results).toHaveLength(0); }); it("handleBoardUpdate updates existing board", async () => { // First create a board const createEvent: CommitCreateEvent<"space.atbb.forum.board"> = { kind: "commit", commit: { rev: "abc123", operation: "create", collection: "space.atbb.forum.board", rkey: "board1", record: { $type: "space.atbb.forum.board", name: "General Discussion", description: "Talk about anything", slug: "general", sortOrder: 1, category: { category: { uri: "at://did:plc:test-forum/space.atbb.forum.category/cat1", cid: "bafycat", }, }, createdAt: "2026-02-13T00:00:00Z", } as any, cid: "bafyboard", }, did: "did:plc:test-forum", time_us: 1000000, }; await indexer.handleBoardCreate(createEvent); // Now update it const updateEvent: CommitUpdateEvent<"space.atbb.forum.board"> = { kind: "commit", commit: { rev: "def456", operation: "update", collection: "space.atbb.forum.board", rkey: "board1", record: { $type: "space.atbb.forum.board", name: "Updated Board Name", description: "Updated description", slug: "updated-general", sortOrder: 2, category: { category: { uri: "at://did:plc:test-forum/space.atbb.forum.category/cat1", cid: "bafycat", }, }, createdAt: "2026-02-13T00:00:00Z", } as any, cid: "bafyboard-updated", }, did: "did:plc:test-forum", time_us: 2000000, }; await indexer.handleBoardUpdate(updateEvent); const [board] = await ctx.db .select() .from(boards) .where(eq(boards.rkey, "board1")); expect(board).toBeDefined(); expect(board.name).toBe("Updated Board Name"); expect(board.description).toBe("Updated description"); expect(board.slug).toBe("updated-general"); expect(board.sortOrder).toBe(2); expect(board.cid).toBe("bafyboard-updated"); }); it("handleBoardDelete removes board", async () => { // First create a board const createEvent: CommitCreateEvent<"space.atbb.forum.board"> = { kind: "commit", commit: { rev: "abc123", operation: "create", collection: "space.atbb.forum.board", rkey: "board1", record: { $type: "space.atbb.forum.board", name: "General Discussion", category: { category: { uri: "at://did:plc:test-forum/space.atbb.forum.category/cat1", cid: "bafycat", }, }, createdAt: "2026-02-13T00:00:00Z", } as any, cid: "bafyboard", }, did: "did:plc:test-forum", time_us: 1000000, }; await indexer.handleBoardCreate(createEvent); // Verify it exists let results = await ctx.db.select().from(boards); expect(results).toHaveLength(1); // Now delete it const deleteEvent: CommitDeleteEvent<"space.atbb.forum.board"> = { kind: "commit", commit: { rev: "ghi789", operation: "delete", collection: "space.atbb.forum.board", rkey: "board1", }, did: "did:plc:test-forum", time_us: 3000000, }; await indexer.handleBoardDelete(deleteEvent); // Verify it's gone results = await ctx.db.select().from(boards); expect(results).toHaveLength(0); }); });