mirror of
https://git.quad4.io/RNS-Things/MeshChatX.git
synced 2026-05-27 11:33:59 +00:00
131 lines
4.7 KiB
JavaScript
131 lines
4.7 KiB
JavaScript
import { describe, expect, it } from "vitest";
|
|
import { mergeLxmfReactionRowsIntoMessages } from "../../meshchatx/src/frontend/js/lxmfReactions";
|
|
|
|
describe("mergeLxmfReactionRowsIntoMessages", () => {
|
|
it("returns an empty array when input is not an array", () => {
|
|
expect(mergeLxmfReactionRowsIntoMessages(undefined)).toEqual([]);
|
|
expect(mergeLxmfReactionRowsIntoMessages(null)).toEqual([]);
|
|
});
|
|
|
|
it("merges reaction rows onto parents and drops reaction-only rows", () => {
|
|
const parentHash = "a".repeat(32);
|
|
const incoming = [
|
|
{
|
|
hash: parentHash,
|
|
source_hash: "b".repeat(32),
|
|
content: "hello",
|
|
is_reaction: false,
|
|
},
|
|
{
|
|
hash: "c".repeat(32),
|
|
source_hash: "d".repeat(32),
|
|
content: "",
|
|
is_reaction: true,
|
|
reaction_to: parentHash,
|
|
reaction_emoji: "\u{1F44D}",
|
|
reaction_sender: "e".repeat(32),
|
|
},
|
|
];
|
|
const out = mergeLxmfReactionRowsIntoMessages(incoming);
|
|
expect(out).toHaveLength(1);
|
|
expect(out[0].hash).toBe(parentHash);
|
|
expect(out[0].reactions).toHaveLength(1);
|
|
expect(out[0].reactions[0].emoji).toBe("\u{1F44D}");
|
|
expect(out[0].reactions[0].sender).toBe("e".repeat(32));
|
|
});
|
|
|
|
it("matches reaction_to to parent hash case-insensitively", () => {
|
|
const parentHash = "Aa".repeat(16);
|
|
const incoming = [
|
|
{ hash: parentHash, content: "hi", is_reaction: false },
|
|
{
|
|
hash: "c".repeat(32),
|
|
is_reaction: true,
|
|
reaction_to: parentHash.toLowerCase(),
|
|
reaction_emoji: "\u{1F44D}",
|
|
reaction_sender: "e".repeat(32),
|
|
},
|
|
];
|
|
const out = mergeLxmfReactionRowsIntoMessages(incoming);
|
|
expect(out[0].reactions).toHaveLength(1);
|
|
});
|
|
|
|
it("dedupes same sender and emoji", () => {
|
|
const parentHash = "a".repeat(32);
|
|
const sender = "e".repeat(32);
|
|
const incoming = [
|
|
{ hash: parentHash, content: "x", is_reaction: false },
|
|
{
|
|
hash: "r1",
|
|
is_reaction: true,
|
|
reaction_to: parentHash,
|
|
reaction_emoji: "\u{1F44D}",
|
|
reaction_sender: sender,
|
|
},
|
|
{
|
|
hash: "r2",
|
|
is_reaction: true,
|
|
reaction_to: parentHash,
|
|
reaction_emoji: "\u{1F44D}",
|
|
reaction_sender: sender,
|
|
},
|
|
];
|
|
const out = mergeLxmfReactionRowsIntoMessages(incoming);
|
|
expect(out[0].reactions).toHaveLength(1);
|
|
});
|
|
|
|
it("preserves XSS-like emoji strings as opaque data for UI escaping", () => {
|
|
const parentHash = "a".repeat(32);
|
|
const emoji = "<img src=x onerror=1>";
|
|
const incoming = [
|
|
{ hash: parentHash, content: "x", is_reaction: false },
|
|
{
|
|
hash: "r1",
|
|
is_reaction: true,
|
|
reaction_to: parentHash,
|
|
reaction_emoji: emoji,
|
|
reaction_sender: "e".repeat(32),
|
|
},
|
|
];
|
|
const out = mergeLxmfReactionRowsIntoMessages(incoming);
|
|
expect(out[0].reactions[0].emoji).toBe(emoji);
|
|
});
|
|
|
|
it("ignores reactions with missing parent or reaction_to", () => {
|
|
const incoming = [
|
|
{ hash: "a".repeat(32), content: "x", is_reaction: false },
|
|
{
|
|
hash: "r1",
|
|
is_reaction: true,
|
|
reaction_to: "no_such_parent_hash_xxxxxxxxxxxxxx",
|
|
reaction_emoji: "\u{1F44D}",
|
|
reaction_sender: "e".repeat(32),
|
|
},
|
|
{
|
|
hash: "r2",
|
|
is_reaction: true,
|
|
reaction_emoji: "\u{1F602}",
|
|
reaction_sender: "f".repeat(32),
|
|
},
|
|
];
|
|
const out = mergeLxmfReactionRowsIntoMessages(incoming);
|
|
expect(out[0].reactions).toHaveLength(0);
|
|
});
|
|
|
|
it("handles many reactions without throwing", () => {
|
|
const parentHash = "a".repeat(32);
|
|
const incoming = [{ hash: parentHash, content: "x", is_reaction: false }];
|
|
for (let i = 0; i < 200; i++) {
|
|
incoming.push({
|
|
hash: `r${i}`.padEnd(32, "0"),
|
|
is_reaction: true,
|
|
reaction_to: parentHash,
|
|
reaction_emoji: String.fromCodePoint(0x1f600 + (i % 16)),
|
|
reaction_sender: `${i.toString(16)}`.padStart(32, "0"),
|
|
});
|
|
}
|
|
const out = mergeLxmfReactionRowsIntoMessages(incoming);
|
|
expect(out[0].reactions.length).toBe(200);
|
|
});
|
|
});
|