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 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});