test(signal): dedupe receive event fixtures and add mention clamp case

This commit is contained in:
Peter Steinberger
2026-02-18 12:37:38 +00:00
parent 9c2b82362e
commit 9b68af5f4f
4 changed files with 63 additions and 56 deletions

View File

@@ -1,5 +1,8 @@
import { beforeEach, describe, expect, it, vi } from "vitest"; import { beforeEach, describe, expect, it, vi } from "vitest";
import { createBaseSignalEventHandlerDeps } from "./monitor/event-handler.test-harness.js"; import {
createBaseSignalEventHandlerDeps,
createSignalReceiveEvent,
} from "./monitor/event-handler.test-harness.js";
const sendTypingMock = vi.fn(); const sendTypingMock = vi.fn();
const sendReadReceiptMock = vi.fn(); const sendReadReceiptMock = vi.fn();
@@ -51,19 +54,13 @@ describe("signal event handler typing + read receipts", () => {
}), }),
); );
await handler({ await handler(
event: "receive", createSignalReceiveEvent({
data: JSON.stringify({ dataMessage: {
envelope: { message: "hi",
sourceNumber: "+15550001111",
sourceName: "Alice",
timestamp: 1700000000000,
dataMessage: {
message: "hi",
},
}, },
}), }),
}); );
expect(sendTypingMock).toHaveBeenCalledWith("signal:+15550001111", expect.any(Object)); expect(sendTypingMock).toHaveBeenCalledWith("signal:+15550001111", expect.any(Object));
expect(sendReadReceiptMock).toHaveBeenCalledWith( expect(sendReadReceiptMock).toHaveBeenCalledWith(

View File

@@ -13,7 +13,10 @@ vi.mock("../../auto-reply/dispatch.js", async (importOriginal) => {
}); });
import { createSignalEventHandler } from "./event-handler.js"; import { createSignalEventHandler } from "./event-handler.js";
import { createBaseSignalEventHandlerDeps } from "./event-handler.test-harness.js"; import {
createBaseSignalEventHandlerDeps,
createSignalReceiveEvent,
} from "./event-handler.test-harness.js";
describe("signal createSignalEventHandler inbound contract", () => { describe("signal createSignalEventHandler inbound contract", () => {
it("passes a finalized MsgContext to dispatchInboundMessage", async () => { it("passes a finalized MsgContext to dispatchInboundMessage", async () => {
@@ -27,21 +30,15 @@ describe("signal createSignalEventHandler inbound contract", () => {
}), }),
); );
await handler({ await handler(
event: "receive", createSignalReceiveEvent({
data: JSON.stringify({ dataMessage: {
envelope: { message: "hi",
sourceNumber: "+15550001111", attachments: [],
sourceName: "Alice", groupInfo: { groupId: "g1", groupName: "Test Group" },
timestamp: 1700000000000,
dataMessage: {
message: "hi",
attachments: [],
groupInfo: { groupId: "g1", groupName: "Test Group" },
},
}, },
}), }),
}); );
expect(capturedCtx).toBeTruthy(); expect(capturedCtx).toBeTruthy();
expectInboundContextContract(capturedCtx!); expectInboundContextContract(capturedCtx!);
@@ -63,20 +60,17 @@ describe("signal createSignalEventHandler inbound contract", () => {
}), }),
); );
await handler({ await handler(
event: "receive", createSignalReceiveEvent({
data: JSON.stringify({ sourceNumber: "+15550002222",
envelope: { sourceName: "Bob",
sourceNumber: "+15550002222", timestamp: 1700000000001,
sourceName: "Bob", dataMessage: {
timestamp: 1700000000001, message: "hello",
dataMessage: { attachments: [],
message: "hello",
attachments: [],
},
}, },
}), }),
}); );
expect(capturedCtx).toBeTruthy(); expect(capturedCtx).toBeTruthy();
const context = capturedCtx as unknown as { const context = capturedCtx as unknown as {

View File

@@ -2,7 +2,10 @@ import { describe, expect, it, vi } from "vitest";
import { buildDispatchInboundCaptureMock } from "../../../test/helpers/dispatch-inbound-capture.js"; import { buildDispatchInboundCaptureMock } from "../../../test/helpers/dispatch-inbound-capture.js";
import type { MsgContext } from "../../auto-reply/templating.js"; import type { MsgContext } from "../../auto-reply/templating.js";
import type { OpenClawConfig } from "../../config/types.js"; import type { OpenClawConfig } from "../../config/types.js";
import { createBaseSignalEventHandlerDeps } from "./event-handler.test-harness.js"; import {
createBaseSignalEventHandlerDeps,
createSignalReceiveEvent,
} from "./event-handler.test-harness.js";
type SignalMsgContext = Pick<MsgContext, "Body" | "WasMentioned"> & { type SignalMsgContext = Pick<MsgContext, "Body" | "WasMentioned"> & {
Body?: string; Body?: string;
@@ -38,23 +41,15 @@ type GroupEventOpts = {
}; };
function makeGroupEvent(opts: GroupEventOpts) { function makeGroupEvent(opts: GroupEventOpts) {
return { return createSignalReceiveEvent({
event: "receive", dataMessage: {
data: JSON.stringify({ message: opts.message ?? "",
envelope: { attachments: opts.attachments ?? [],
sourceNumber: "+15550001111", quote: opts.quoteText ? { text: opts.quoteText } : undefined,
sourceName: "Alice", mentions: opts.mentions ?? undefined,
timestamp: 1700000000000, groupInfo: { groupId: "g1", groupName: "Test Group" },
dataMessage: { },
message: opts.message ?? "", });
attachments: opts.attachments ?? [],
quote: opts.quoteText ? { text: opts.quoteText } : undefined,
mentions: opts.mentions ?? undefined,
groupInfo: { groupId: "g1", groupName: "Test Group" },
},
},
}),
};
} }
function createMentionGatedHistoryHandler() { function createMentionGatedHistoryHandler() {
@@ -250,4 +245,11 @@ describe("renderSignalMentions", () => {
expect(normalized).toBe("@valid hi"); expect(normalized).toBe("@valid hi");
}); });
it("clamps and truncates fractional mention offsets", () => {
const message = `${PLACEHOLDER} ping`;
const normalized = renderSignalMentions(message, [{ uuid: "valid", start: -0.7, length: 1.9 }]);
expect(normalized).toBe("@valid ping");
});
}); });

View File

@@ -33,3 +33,17 @@ export function createBaseSignalEventHandlerDeps(
...overrides, ...overrides,
}; };
} }
export function createSignalReceiveEvent(envelopeOverrides: Record<string, unknown> = {}) {
return {
event: "receive",
data: JSON.stringify({
envelope: {
sourceNumber: "+15550001111",
sourceName: "Alice",
timestamp: 1700000000000,
...envelopeOverrides,
},
}),
};
}