test: add quote reply regression coverage
This commit is contained in:
parent
75505e49db
commit
55798ae175
@ -345,6 +345,49 @@ describe("signal quote reply handling", () => {
|
||||
expect(String(ctx?.Body ?? "")).toContain("[Quoting +15550002222 id:1700000000001]");
|
||||
});
|
||||
|
||||
it("does not poison the quote-author cache from attacker-controlled quote metadata", async () => {
|
||||
const handler = createQuoteHandler();
|
||||
|
||||
await handler(
|
||||
createSignalReceiveEvent({
|
||||
sourceNumber: "+15550002222",
|
||||
sourceName: "Bob",
|
||||
timestamp: 1700000000001,
|
||||
dataMessage: {
|
||||
message: "Forwarding this",
|
||||
groupInfo: { groupId: "g1", groupName: "Test Group" },
|
||||
quote: {
|
||||
id: 1700000000000,
|
||||
authorNumber: "+15550009999",
|
||||
text: "Mallory wrote this",
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
capturedCtx = undefined;
|
||||
|
||||
await handler(
|
||||
createSignalReceiveEvent({
|
||||
sourceNumber: "+15550003333",
|
||||
sourceName: "Alice",
|
||||
timestamp: 1700000000002,
|
||||
dataMessage: {
|
||||
message: "Replying to Bob",
|
||||
groupInfo: { groupId: "g1", groupName: "Test Group" },
|
||||
quote: {
|
||||
id: 1700000000001,
|
||||
text: "Forwarding this",
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const ctx = getCapturedCtx();
|
||||
expect(ctx?.ReplyToSender).toBe("+15550002222");
|
||||
expect(String(ctx?.Body ?? "")).toContain("[Quoting +15550002222 id:1700000000001]");
|
||||
});
|
||||
|
||||
it("resolves cached uuid senders with a uuid: prefix", async () => {
|
||||
const handler = createQuoteHandler();
|
||||
const senderUuid = "123e4567-e89b-12d3-a456-426614174000";
|
||||
|
||||
@ -2,10 +2,33 @@ import { describe, expect, it } from "vitest";
|
||||
import { setActivePluginRegistry } from "../../plugins/runtime.js";
|
||||
import { createTestRegistry } from "../../test-utils/channel-plugins.js";
|
||||
import {
|
||||
applyReplyThreading,
|
||||
filterMessagingToolMediaDuplicates,
|
||||
shouldSuppressMessagingToolReplies,
|
||||
} from "./reply-payloads.js";
|
||||
|
||||
describe("applyReplyThreading", () => {
|
||||
it("treats whitespace-only replyToId as unset so implicit replies still apply", () => {
|
||||
const result = applyReplyThreading({
|
||||
payloads: [{ text: "hello", replyToId: " \n\t " }],
|
||||
replyToMode: "all",
|
||||
currentMessageId: "123",
|
||||
});
|
||||
|
||||
expect(result).toEqual([{ text: "hello", replyToId: "123" }]);
|
||||
});
|
||||
|
||||
it("preserves explicit null replyToId as do-not-reply", () => {
|
||||
const result = applyReplyThreading({
|
||||
payloads: [{ text: "hello", replyToId: null }],
|
||||
replyToMode: "all",
|
||||
currentMessageId: "123",
|
||||
});
|
||||
|
||||
expect(result).toEqual([{ text: "hello", replyToId: null }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("filterMessagingToolMediaDuplicates", () => {
|
||||
it("strips mediaUrl when it matches sentMediaUrls", () => {
|
||||
const result = filterMessagingToolMediaDuplicates({
|
||||
|
||||
@ -3,6 +3,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite
|
||||
import { markdownToSignalTextChunks } from "../../../extensions/signal/src/format.js";
|
||||
import {
|
||||
signalOutbound,
|
||||
slackOutbound,
|
||||
telegramOutbound,
|
||||
whatsappOutbound,
|
||||
} from "../../../test/channel-outbounds.js";
|
||||
@ -1027,6 +1028,45 @@ describe("deliverOutboundPayloads", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps inherited Slack thread context across all payloads", async () => {
|
||||
const sendSlack = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce({ messageId: "sl1", channelId: "C123" })
|
||||
.mockResolvedValueOnce({ messageId: "sl2", channelId: "C123" });
|
||||
setActivePluginRegistry(
|
||||
createTestRegistry([
|
||||
{
|
||||
pluginId: "slack",
|
||||
plugin: createOutboundTestPlugin({ id: "slack", outbound: slackOutbound }),
|
||||
source: "test",
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
await deliverOutboundPayloads({
|
||||
cfg: { channels: { slack: {} } },
|
||||
channel: "slack",
|
||||
to: "C123",
|
||||
payloads: [{ text: "first" }, { text: "second" }],
|
||||
replyToId: "thread-123",
|
||||
deps: { sendSlack },
|
||||
});
|
||||
|
||||
expect(sendSlack).toHaveBeenCalledTimes(2);
|
||||
expect(sendSlack).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
"C123",
|
||||
"first",
|
||||
expect.objectContaining({ threadTs: "thread-123" }),
|
||||
);
|
||||
expect(sendSlack).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
"C123",
|
||||
"second",
|
||||
expect.objectContaining({ threadTs: "thread-123" }),
|
||||
);
|
||||
});
|
||||
|
||||
it("passes normalized payload to onError", async () => {
|
||||
const sendWhatsApp = vi.fn().mockRejectedValue(new Error("boom"));
|
||||
const onError = vi.fn();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user