Extend message features

This commit is contained in:
jude committed 2026-10-11 13:16:02 +01:00
1 parent 2665c61d33
commit 439575acd0
20 files changed
+1326 -155

No files matched your search

+186
View File
@@ -0,0 +1,186 @@
import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import test from "node:test";
import ts from "typescript";
// Run the pure editor helpers without a browser or additional test dependencies.
const source = await readFile(
new URL("../src/components/Reminder/message.ts", import.meta.url),
"utf8",
);
const { outputText } = ts.transpileModule(source, {
compilerOptions: { module: ts.ModuleKind.ESNext, target: ts.ScriptTarget.ES2020 },
});
const {
addEmbed,
embedFields,
prepareReminder,
reminderEmbeds,
removeEmbed,
updateEmbed,
addLinkButton,
canAddLinkButton,
linkButtons,
updateLinkButton,
} = await import(`data:text/javascript;base64,${Buffer.from(outputText).toString("base64")}`);
function reminder(embeds) {
return {
content: "hello",
tts: false,
username: "",
avatar: null,
attachment_name: null,
uid: "unchanged",
utc_time: "2026-10-12T12:00:00",
...embedFields(embeds?.[0] || {}),
message_json: embeds ? { embeds, allowed_mentions: { parse: [] } } : null,
};
}
test("editing one embed preserves the others and unedited payload properties", () => {
const original = reminder([
{ title: "first" },
{ description: "second", author: { name: "author", url: "https://example.com" } },
]);
const edited = updateEmbed(original, 1, (r) => ({ ...r, embed_description: "updated" }));
const payload = prepareReminder(edited).message_json;
assert.equal(payload.embeds[0].title, "first");
assert.equal(payload.embeds[1].description, "updated");
assert.equal(payload.embeds[1].author.url, "https://example.com");
assert.deepEqual(payload.allowed_mentions, { parse: [] });
assert.equal(edited.uid, original.uid);
assert.equal(original.message_json.embeds[1].description, "second");
});
test("adding stops at ten embeds and removal permits another", () => {
let value = reminder([{ title: "first" }]);
for (let i = 0; i < 12; i++) value = addEmbed(value);
assert.equal(reminderEmbeds(value).length, 10);
assert.equal(addEmbed(value), value);
value = removeEmbed(value, 0);
assert.equal(reminderEmbeds(value).length, 9);
value = updateEmbed(value, 0, (r) => ({ ...r, embed_title: "new first" }));
assert.equal(prepareReminder(value).message_json.embeds[0].title, "new first");
assert.equal(reminderEmbeds(addEmbed(value)).length, 10);
});
test("saving and reloading multiple embeds preserves order and drops blank editors", () => {
let value = addEmbed(reminder([{ description: "first" }]));
value = updateEmbed(value, 1, (r) => ({ ...r, embed_description: "second" }));
value = addEmbed(value);
const saved = prepareReminder(value);
assert.deepEqual(
saved.message_json.embeds.map((embed) => embed.description),
["first", "second"],
);
assert.deepEqual(reminderEmbeds(JSON.parse(JSON.stringify(saved))), saved.message_json.embeds);
assert.deepEqual(prepareReminder(reminder()).message_json.embeds, []);
});
test("legacy embeds are retained when a second embed is added", () => {
const legacy = {
...reminder(),
embed_title: "legacy",
embed_fields: [{ title: "name", value: "value", inline: true }],
};
const saved = prepareReminder(addEmbed(legacy));
assert.equal(saved.message_json.embeds[0].title, "legacy");
assert.deepEqual(saved.message_json.embeds[0].fields, [
{ name: "name", value: "value", inline: true },
]);
});
test("combined embed text accepts 6000 characters and rejects 6001", () => {
const embeds = [{ description: "x".repeat(3000) }, { description: "y".repeat(3000) }];
assert.equal(prepareReminder(reminder(embeds)).message_json.embeds.length, 2);
assert.throws(
() => prepareReminder(reminder([embeds[0], { description: "y".repeat(3001) }])),
/6000/,
);
assert.throws(
() => prepareReminder(reminder(Array.from({ length: 11 }, () => ({ title: "embed" })))),
/10 embeds/,
);
});
test("link buttons can be added, edited, saved, reloaded and removed without losing embeds", () => {
const original = reminder([{ title: "first" }, { title: "second" }]);
let value = addLinkButton(original);
value = updateLinkButton(value, 0, 0, { label: "Visit", url: "https://example.com" });
const saved = prepareReminder(value);
assert.deepEqual(saved.message_json.components, [
{
type: 1,
components: [{ type: 2, style: 5, label: "Visit", url: "https://example.com" }],
},
]);
assert.deepEqual(saved.message_json.embeds, original.message_json.embeds);
assert.deepEqual(saved.message_json.allowed_mentions, { parse: [] });
assert.equal(
linkButtons(JSON.parse(JSON.stringify(saved)))[0].button.url,
"https://example.com",
);
assert.deepEqual(
prepareReminder(updateLinkButton(saved, 0, 0, null)).message_json.components,
[],
);
assert.equal(original.message_json.components, undefined);
const legacy = updateLinkButton(addLinkButton({ ...reminder(), embed_title: "legacy" }), 0, 0, {
url: "https://example.com",
});
assert.equal(prepareReminder(legacy).message_json.embeds[0].title, "legacy");
});
test("link buttons fill five rows of five and preserve other components", () => {
let value = reminder();
for (let i = 0; i < 26; i++) value = addLinkButton(value);
assert.equal(linkButtons(value).length, 25);
assert.deepEqual(
value.message_json.components.map((row) => row.components.length),
[5, 5, 5, 5, 5],
);
assert.equal(canAddLinkButton(value), false);
assert.equal(addLinkButton(value), value);
value = updateLinkButton(value, 2, 2, null);
assert.equal(canAddLinkButton(value), true);
assert.equal(linkButtons(addLinkButton(value)).length, 25);
const other = { type: 1, id: 7, components: [{ type: 3, custom_id: "select", options: [] }] };
value = { ...reminder(), message_json: { components: [other] } };
value = addLinkButton(value);
assert.deepEqual(value.message_json.components[0], other);
assert.equal(linkButtons(value)[0].rowIndex, 1);
});
test("invalid link button URLs, labels and row limits are rejected on save", () => {
let value = addLinkButton(reminder());
assert.throws(() => prepareReminder(value), /URL/);
value = updateLinkButton(value, 0, 0, {
url: "https://example.com/" + "x".repeat(492),
label: "x".repeat(80),
});
assert.equal(prepareReminder(value).message_json.components.length, 1);
for (const change of [
{ url: "invalid" },
{ url: "javascript:alert(1)" },
{ url: "https://example.com/" + "x".repeat(493) },
{ label: "" },
{ label: "x".repeat(81) },
])
assert.throws(() => prepareReminder(updateLinkButton(value, 0, 0, change)));
const row = value.message_json.components[0];
assert.throws(
() => prepareReminder({ ...value, message_json: { components: Array(6).fill(row) } }),
/5 button rows/,
);
assert.throws(
() =>
prepareReminder({
...value,
message_json: {
components: [{ ...row, components: Array(6).fill(row.components[0]) }],
},
}),
/5 components/,
);
});