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 main 116 lines 3.4 kB view raw
1import { describe, it, expect, vi } from "vitest"; 2import { createForumRecord } from "../lib/steps/create-forum.js"; 3 4describe("createForumRecord", () => { 5 const forumDid = "did:plc:testforum"; 6 7 function mockDb() { 8 return { 9 insert: vi.fn().mockReturnValue({ 10 values: vi.fn().mockResolvedValue(undefined), 11 }), 12 } as any; 13 } 14 15 // XRPC "RecordNotFound" error mimics @atproto/api behavior 16 function recordNotFoundError() { 17 const err = Object.assign(new Error("Record not found"), { 18 status: 400, 19 error: "RecordNotFound", 20 }); 21 return err; 22 } 23 24 function mockAgent(overrides: Record<string, any> = {}) { 25 return { 26 com: { 27 atproto: { 28 repo: { 29 getRecord: vi.fn().mockRejectedValue(recordNotFoundError()), 30 createRecord: vi.fn().mockResolvedValue({ 31 data: { uri: `at://${forumDid}/space.atbb.forum.forum/self`, cid: "bafytest" }, 32 }), 33 ...overrides, 34 }, 35 }, 36 }, 37 } as any; 38 } 39 40 it("creates forum record and inserts into DB when it does not exist", async () => { 41 const db = mockDb(); 42 const agent = mockAgent(); 43 44 const result = await createForumRecord(db, agent, forumDid, { 45 name: "My Forum", 46 description: "A test forum", 47 }); 48 49 expect(result.created).toBe(true); 50 expect(result.cid).toBe("bafytest"); 51 expect(result.uri).toContain("space.atbb.forum.forum/self"); 52 expect(agent.com.atproto.repo.createRecord).toHaveBeenCalledWith( 53 expect.objectContaining({ 54 repo: forumDid, 55 collection: "space.atbb.forum.forum", 56 rkey: "self", 57 record: expect.objectContaining({ 58 $type: "space.atbb.forum.forum", 59 name: "My Forum", 60 description: "A test forum", 61 }), 62 }) 63 ); 64 // Verify DB insertion 65 expect(db.insert).toHaveBeenCalled(); 66 }); 67 68 it("skips creation when forum record already exists", async () => { 69 const db = mockDb(); 70 const agent = mockAgent({ 71 getRecord: vi.fn().mockResolvedValue({ 72 data: { 73 uri: `at://${forumDid}/space.atbb.forum.forum/self`, 74 cid: "bafyexisting", 75 value: { name: "Existing Forum" }, 76 }, 77 }), 78 }); 79 80 const result = await createForumRecord(db, agent, forumDid, { 81 name: "My Forum", 82 }); 83 84 expect(result.created).toBe(false); 85 expect(result.skipped).toBe(true); 86 expect(result.cid).toBe("bafyexisting"); 87 expect(agent.com.atproto.repo.createRecord).not.toHaveBeenCalled(); 88 // No DB insertion when skipped 89 expect(db.insert).not.toHaveBeenCalled(); 90 }); 91 92 it("throws when PDS write fails", async () => { 93 const db = mockDb(); 94 const agent = mockAgent({ 95 createRecord: vi.fn().mockRejectedValue(new Error("PDS write failed")), 96 }); 97 98 await expect( 99 createForumRecord(db, agent, forumDid, { name: "My Forum" }) 100 ).rejects.toThrow("PDS write failed"); 101 }); 102 103 it("re-throws non-RecordNotFound errors from getRecord", async () => { 104 const db = mockDb(); 105 const agent = mockAgent({ 106 getRecord: vi.fn().mockRejectedValue(new Error("Network timeout")), 107 }); 108 109 await expect( 110 createForumRecord(db, agent, forumDid, { name: "My Forum" }) 111 ).rejects.toThrow("Network timeout"); 112 113 // Should never attempt createRecord 114 expect(agent.com.atproto.repo.createRecord).not.toHaveBeenCalled(); 115 }); 116});