Files
openclaw/src/discord/components.test.ts

99 lines
2.9 KiB
TypeScript

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