import { afterEach, describe, expect, it, vi } from "vitest"; import { createDiscordNotificationService, formatPairingMessage, type DiscordFetch } from "../plugin/notifications/discord.js"; const request = { identifier: "client-a", pairingCode: "PAIR-1234-CODE", expiresAt: 1_710_000_300, ttlSeconds: 300, createdAt: 1_710_000_000 }; afterEach(() => { vi.restoreAllMocks(); }); describe("Discord notification service", () => { it("formats pairing requests as a DM-friendly message", () => { const message = formatPairingMessage(request); expect(message).toContain("Yonexus Pairing Request"); expect(message).toContain("`client-a`"); expect(message).toContain("`PAIR-1234-CODE`"); expect(message).toContain("TTL:** 300 seconds"); }); it("creates a DM channel and posts the pairing message", async () => { const fetcher = vi .fn() .mockResolvedValueOnce({ ok: true, status: 200, json: async () => ({ id: "dm-channel-1" }) }) .mockResolvedValueOnce({ ok: true, status: 200, json: async () => ({ id: "message-1" }) }); const service = createDiscordNotificationService( { botToken: "discord-bot-token", adminUserId: "123456789012345678" }, { fetcher } ); await expect(service.sendPairingNotification(request)).resolves.toBe(true); expect(fetcher).toHaveBeenCalledTimes(2); expect(fetcher).toHaveBeenNthCalledWith( 1, "https://discord.com/api/v10/users/@me/channels", expect.objectContaining({ method: "POST", headers: expect.objectContaining({ Authorization: "Bot discord-bot-token" }), body: JSON.stringify({ recipient_id: "123456789012345678" }) }) ); expect(fetcher).toHaveBeenNthCalledWith( 2, "https://discord.com/api/v10/channels/dm-channel-1/messages", expect.objectContaining({ method: "POST" }) ); }); it("returns false when Discord rejects DM channel creation", async () => { const fetcher = vi.fn().mockResolvedValueOnce({ ok: false, status: 403, json: async () => ({ message: "Missing Access" }) }); const service = createDiscordNotificationService( { botToken: "discord-bot-token", adminUserId: "123456789012345678" }, { fetcher } ); await expect(service.sendPairingNotification(request)).resolves.toBe(false); expect(fetcher).toHaveBeenCalledTimes(1); }); it("returns false when config is missing required Discord credentials", async () => { const fetcher = vi.fn(); const service = createDiscordNotificationService( { botToken: "", adminUserId: "" }, { fetcher } ); await expect(service.sendPairingNotification(request)).resolves.toBe(false); expect(fetcher).not.toHaveBeenCalled(); }); });