/* * Slopbot backend tests: discord.js message mapping and paging. Offline, fake fetcher. * Run with: pnpm test:media (from poc/). */ import assert from "node:assert/strict"; import { SlopbotBackend, type SlopbotFetcher } from "../slopbot/backend.js"; import { mapSlopbotMessage } from "../slopbot/backend.js"; import { countMessages } from "../slopbot/client.js"; let failures = 0; async function test(name: string, fn: () => void | Promise): Promise { try { await fn(); console.log(`ok - ${name}`); } catch (error) { failures++; console.error(`not ok - ${name}`); console.error(error); } } const noFlags = { has: () => false }; const voiceFlags = { has: (bit: number) => (bit & (1 << 13)) !== 0 }; function discordMessage(extra: Record = {}) { return { id: "1000", author: { id: "7", username: "user", avatar: "abc" }, content: "hello", createdAt: new Date("2026-09-16T12:00:00.000Z"), editedAt: null, reference: null, flags: noFlags, attachments: new Map(), embeds: [], stickers: new Map(), messageSnapshots: new Map(), ...extra }; } class FakeFetcher implements SlopbotFetcher { readonly calls: Array<{ channelId: string; limit: number; before?: string }> = []; constructor(private readonly pages: unknown[][]) {} async fetchMessages(channelId: string, options: { limit: number; before?: string }): Promise { this.calls.push({ channelId, ...options }); return this.pages.shift() ?? []; } } void (async () => { await test("maps attachments, embeds, stickers, and replies", () => { const mapped = mapSlopbotMessage( discordMessage({ reference: { messageId: "900" }, attachments: new Map([ [ "a1", { id: "a1", name: "pic.png", url: "https://cdn.discordapp.com/attachments/1/pic.png", contentType: "image/png", size: 10, width: 5, height: 6, duration: null } ] ]), embeds: [ { data: { type: "video", url: "https://www.youtube.com/watch?v=x", provider: { name: "YouTube" }, video: { url: "https://www.youtube.com/embed/x" }, image: null, thumbnail: { url: "https://i.ytimg.com/vi/x/hqdefault.jpg" } } } ], stickers: new Map([["s1", { id: "s1", name: "wave", format: 4 }]]) }) ); assert.equal(mapped.attachments[0].filename, "pic.png"); assert.equal(mapped.attachments[0].contentType, "image/png"); assert.equal(mapped.attachments[0].size, 10); assert.equal(mapped.embeds[0].provider, "YouTube"); assert.equal(mapped.embeds[0].videoUrl, "https://www.youtube.com/embed/x"); assert.equal(mapped.stickerItems[0].formatType, 4); assert.equal(mapped.replyTo?.id, "900"); assert.equal(mapped.voiceMessage, false); assert.equal(mapped.timestamp, "2026-09-16T12:00:00.000Z"); }); await test("maps forwarded snapshots and voice flags", () => { const mapped = mapSlopbotMessage( discordMessage({ flags: voiceFlags, messageSnapshots: new Map([ [ "s1", { content: "forwarded", createdAt: new Date("2026-09-15T00:00:00.000Z"), flags: noFlags, attachments: new Map([ [ "a2", { id: "a2", name: "clip.webm", url: "https://cdn.discordapp.com/attachments/1/clip.webm", contentType: "video/webm", size: null, width: null, height: null, duration: null } ] ]), embeds: [], stickers: new Map() } ] ]) }) ); assert.equal(mapped.voiceMessage, true); assert.equal(mapped.forwarded.length, 1); assert.equal(mapped.forwarded[0].content, "forwarded"); assert.equal(mapped.forwarded[0].attachments[0].filename, "clip.webm"); }); await test("countMessages reads guild search totals", async () => { const calls: string[] = []; const rest = { async get(path: string, options?: { query?: URLSearchParams }) { calls.push(`${path}?${options?.query?.toString() ?? ""}`); return { total_results: 7 }; } }; const count = await countMessages(rest, { channelId: "1", guildId: "2", afterId: "100", beforeId: "200" }); assert.equal(count, 7); assert.equal(calls[0], "/guilds/2/messages/search?channel_id=1&limit=1&min_id=100&max_id=200"); const failed = await countMessages( { async get() { throw new Error("nope"); } }, { channelId: "1", guildId: "2" } ); assert.equal(failed, null); }); await test("backend pages oldest first and passes before and limit", async () => { const fetcher = new FakeFetcher([ [discordMessage({ id: "1002" }), discordMessage({ id: "1001" })], [discordMessage({ id: "999" })] ]); const backend = new SlopbotBackend(fetcher); const page = await backend.fetchPage("123", null, 2); assert.deepEqual( page.messages.map(message => message.id), ["1001", "1002"] ); assert.deepEqual(fetcher.calls[0], { channelId: "123", limit: 2 }); const next = await backend.fetchPage("123", "1001", 2); assert.deepEqual( next.messages.map(message => message.id), ["999"] ); assert.deepEqual(fetcher.calls[1], { channelId: "123", limit: 2, before: "1001" }); }); if (failures > 0) { console.error(`${failures} test(s) failed`); process.exit(1); } console.log("all slopbot tests passed"); })();