| import { MessageFlags } from "discord-api-types/v10"; |
| import { describe, expect, it, beforeEach } from "vitest"; |
| import { |
| clearDiscordComponentEntries, |
| registerDiscordComponentEntries, |
| resolveDiscordComponentEntry, |
| resolveDiscordModalEntry, |
| } from "./components-registry.js"; |
| import { |
| buildDiscordComponentMessage, |
| buildDiscordComponentMessageFlags, |
| readDiscordComponentSpec, |
| } from "./components.js"; |
|
|
| describe("discord components", () => { |
| it("builds v2 containers with modal trigger", () => { |
| const spec = readDiscordComponentSpec({ |
| text: "Choose a path", |
| blocks: [ |
| { |
| type: "actions", |
| buttons: [{ label: "Approve", style: "success" }], |
| }, |
| ], |
| modal: { |
| title: "Details", |
| fields: [{ type: "text", label: "Requester" }], |
| }, |
| }); |
| if (!spec) { |
| throw new Error("Expected component spec to be parsed"); |
| } |
|
|
| const result = buildDiscordComponentMessage({ spec }); |
| expect(result.components).toHaveLength(1); |
| expect(result.components[0]?.isV2).toBe(true); |
| expect(buildDiscordComponentMessageFlags(result.components)).toBe(MessageFlags.IsComponentsV2); |
| expect(result.modals).toHaveLength(1); |
|
|
| const trigger = result.entries.find((entry) => entry.kind === "modal-trigger"); |
| expect(trigger?.modalId).toBe(result.modals[0]?.id); |
| }); |
|
|
| it("requires options for modal select fields", () => { |
| expect(() => |
| readDiscordComponentSpec({ |
| modal: { |
| title: "Details", |
| fields: [{ type: "select", label: "Priority" }], |
| }, |
| }), |
| ).toThrow("options"); |
| }); |
|
|
| it("requires attachment references for file blocks", () => { |
| expect(() => |
| readDiscordComponentSpec({ |
| blocks: [{ type: "file", file: "https://example.com/report.pdf" }], |
| }), |
| ).toThrow("attachment://"); |
| expect(() => |
| readDiscordComponentSpec({ |
| blocks: [{ type: "file", file: "attachment://" }], |
| }), |
| ).toThrow("filename"); |
| }); |
| }); |
|
|
| describe("discord component registry", () => { |
| beforeEach(() => { |
| clearDiscordComponentEntries(); |
| }); |
|
|
| it("registers and consumes component entries", () => { |
| registerDiscordComponentEntries({ |
| entries: [{ id: "btn_1", kind: "button", label: "Confirm" }], |
| modals: [ |
| { |
| id: "mdl_1", |
| title: "Details", |
| fields: [{ id: "fld_1", name: "name", label: "Name", type: "text" }], |
| }, |
| ], |
| messageId: "msg_1", |
| ttlMs: 1000, |
| }); |
|
|
| const entry = resolveDiscordComponentEntry({ id: "btn_1", consume: false }); |
| expect(entry?.messageId).toBe("msg_1"); |
|
|
| const modal = resolveDiscordModalEntry({ id: "mdl_1", consume: false }); |
| expect(modal?.messageId).toBe("msg_1"); |
|
|
| const consumed = resolveDiscordComponentEntry({ id: "btn_1" }); |
| expect(consumed?.id).toBe("btn_1"); |
| expect(resolveDiscordComponentEntry({ id: "btn_1" })).toBeNull(); |
| }); |
| }); |
|
|