test(imessage): exercise chat lookup through runtime boundary (#121205)

This commit is contained in:
Peter Steinberger
2026-08-09 13:33:30 -07:00
committed by GitHub
parent 5262874d64
commit 2904bbfc47
3 changed files with 111 additions and 117 deletions
@@ -72,17 +72,6 @@ function chatListCacheSet(
}
}
export function normalizeDirectChatIdentifierForTest(raw: string): string {
return normalizeDirectChatIdentifier(raw);
}
export function findChatGuidForTest(
chats: readonly Record<string, unknown>[],
target: Extract<IMessageTarget, { kind: "chat_id" | "chat_identifier" }>,
): string | null {
return findChatGuid(chats, target);
}
function findChatGuid(
chats: readonly Record<string, unknown>[],
target: Extract<IMessageTarget, { kind: "chat_id" | "chat_identifier" }>,
+110 -100
View File
@@ -2,6 +2,7 @@
import { access, readFile } from "node:fs/promises";
import { basename, dirname } from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import { normalizeDirectChatIdentifier } from "./chat-context.js";
const createIMessageRpcClientMock = vi.hoisted(() => vi.fn());
const runIMessageCliJsonCommandMock = vi.hoisted(() => vi.fn());
@@ -19,8 +20,7 @@ vi.mock("./remote-file.js", () => ({
withIMessageRemoteFile: withIMessageRemoteFileMock,
}));
const { imessageActionsRuntime, findChatGuidForTest, normalizeDirectChatIdentifierForTest } =
await import("./actions.runtime.js");
const { imessageActionsRuntime } = await import("./actions.runtime.js");
afterEach(() => {
vi.restoreAllMocks();
@@ -672,111 +672,121 @@ describe("findChatGuid cross-format identifier resolution", () => {
},
];
it("matches a synthesized iMessage;-;<phone> target against the chats.list <phone> identifier", () => {
const result = findChatGuidForTest(chatsList, {
kind: "chat_identifier",
chatIdentifier: "iMessage;-;+12069106512",
});
expect(result).toBe("any;-;+12069106512");
});
type ChatGuidCase = {
name: string;
cliPath: string;
chats: Array<Record<string, unknown>>;
target:
| { kind: "chat_id"; chatId: number }
| { kind: "chat_identifier"; chatIdentifier: string };
expected: string | null;
};
it("matches a synthesized SMS;-;<phone> target the same way", () => {
const result = findChatGuidForTest(chatsList, {
kind: "chat_identifier",
chatIdentifier: "SMS;-;+12069106512",
});
expect(result).toBe("any;-;+12069106512");
});
it.each([
{
name: "matches a synthesized iMessage;-;<phone> target against the chats.list <phone> identifier",
cliPath: "imsg-cross-format-imessage",
chats: chatsList,
target: { kind: "chat_identifier", chatIdentifier: "iMessage;-;+12069106512" },
expected: "any;-;+12069106512",
},
{
name: "matches a synthesized SMS;-;<phone> target the same way",
cliPath: "imsg-cross-format-sms",
chats: chatsList,
target: { kind: "chat_identifier", chatIdentifier: "SMS;-;+12069106512" },
expected: "any;-;+12069106512",
},
{
name: "matches a bare <phone> identifier exactly",
cliPath: "imsg-cross-format-bare",
chats: chatsList,
target: { kind: "chat_identifier", chatIdentifier: "+12069106512" },
expected: "any;-;+12069106512",
},
{
name: "matches an any;-;<phone> guid form against the chats.list guid column",
cliPath: "imsg-cross-format-any",
chats: chatsList,
target: { kind: "chat_identifier", chatIdentifier: "any;-;+12069106512" },
expected: "any;-;+12069106512",
},
{
name: "matches a group chat by exact guid",
cliPath: "imsg-cross-format-group-guid",
chats: chatsList,
target: { kind: "chat_identifier", chatIdentifier: "iMessage;+;chat0000" },
expected: "iMessage;+;chat0000",
},
{
name: "matches a group chat by chat_id",
cliPath: "imsg-cross-format-chat-id",
chats: chatsList,
target: { kind: "chat_id", chatId: 7 },
expected: "iMessage;+;chat0000",
},
{
name: "does not coerce non-decimal chat ids from chats.list",
cliPath: "imsg-cross-format-nondecimal-id",
chats: [{ id: "0x7", identifier: "wrong", guid: "iMessage;+;wrong" }],
target: { kind: "chat_id", chatId: 7 },
expected: null,
},
{
name: "returns null for a phone number that does not exist in chats.list",
cliPath: "imsg-cross-format-missing-phone",
chats: chatsList,
target: { kind: "chat_identifier", chatIdentifier: "iMessage;-;+19999999999" },
expected: null,
},
{
name: "does not cross-match different phone numbers via the prefix-stripping path",
cliPath: "imsg-cross-format-different-phone",
chats: chatsList,
target: { kind: "chat_identifier", chatIdentifier: "iMessage;-;+18001234567" },
expected: null,
},
{
name: "does not match a DM target against a group's chat_identifier",
cliPath: "imsg-cross-format-group-mismatch",
chats: chatsList,
target: { kind: "chat_identifier", chatIdentifier: "iMessage;+;chat-not-here" },
expected: null,
},
] satisfies ChatGuidCase[])("$name", async ({ cliPath, chats, target, expected }) => {
const client = mockRpcChatList(chats);
it("matches a bare <phone> identifier exactly", () => {
const result = findChatGuidForTest(chatsList, {
kind: "chat_identifier",
chatIdentifier: "+12069106512",
});
expect(result).toBe("any;-;+12069106512");
});
it("matches an any;-;<phone> guid form against the chats.list guid column", () => {
const result = findChatGuidForTest(chatsList, {
kind: "chat_identifier",
chatIdentifier: "any;-;+12069106512",
});
expect(result).toBe("any;-;+12069106512");
});
it("matches a group chat by exact guid", () => {
const result = findChatGuidForTest(chatsList, {
kind: "chat_identifier",
chatIdentifier: "iMessage;+;chat0000",
});
expect(result).toBe("iMessage;+;chat0000");
});
it("matches a group chat by chat_id", () => {
const result = findChatGuidForTest(chatsList, { kind: "chat_id", chatId: 7 });
expect(result).toBe("iMessage;+;chat0000");
});
it("does not coerce non-decimal chat ids from chats.list", () => {
const result = findChatGuidForTest(
[
{
id: "0x7",
identifier: "wrong",
guid: "iMessage;+;wrong",
},
],
{ kind: "chat_id", chatId: 7 },
await expect(
imessageActionsRuntime.resolveChatGuidForTarget({
target,
options: { cliPath },
conversationReadOrigin: "delegated",
}),
).resolves.toBe(expected);
expect(client.request).toHaveBeenCalledWith(
"chats.list",
{ limit: 1000 },
{ timeoutMs: undefined },
);
expect(result).toBeNull();
});
it("returns null for a phone number that does not exist in chats.list", () => {
const result = findChatGuidForTest(chatsList, {
kind: "chat_identifier",
chatIdentifier: "iMessage;-;+19999999999",
});
expect(result).toBeNull();
});
it("does not cross-match different phone numbers via the prefix-stripping path", () => {
const result = findChatGuidForTest(chatsList, {
kind: "chat_identifier",
chatIdentifier: "iMessage;-;+18001234567",
});
expect(result).toBeNull();
});
it("does not match a DM target against a group's chat_identifier", () => {
const result = findChatGuidForTest(chatsList, {
kind: "chat_identifier",
chatIdentifier: "iMessage;+;chat-not-here",
});
expect(result).toBeNull();
expect(client.stop).toHaveBeenCalledOnce();
});
});
describe("normalizeDirectChatIdentifier", () => {
it("strips the iMessage;-; prefix", () => {
expect(normalizeDirectChatIdentifierForTest("iMessage;-;+12069106512")).toBe("+12069106512");
});
it("strips the SMS;-; prefix", () => {
expect(normalizeDirectChatIdentifierForTest("SMS;-;+12069106512")).toBe("+12069106512");
});
it("strips the any;-; prefix", () => {
expect(normalizeDirectChatIdentifierForTest("any;-;+12069106512")).toBe("+12069106512");
});
it("matches case-insensitively", () => {
expect(normalizeDirectChatIdentifierForTest("IMESSAGE;-;+12069106512")).toBe("+12069106512");
});
it("leaves group identifiers (iMessage;+;chat...) unchanged", () => {
expect(normalizeDirectChatIdentifierForTest("iMessage;+;chat0000")).toBe("iMessage;+;chat0000");
expect(normalizeDirectChatIdentifierForTest("iMessage;+;Some@example.com")).toBe(
it.each([
["strips the iMessage;-; prefix", "iMessage;-;+12069106512", "+12069106512"],
["strips the SMS;-; prefix", "SMS;-;+12069106512", "+12069106512"],
["strips the any;-; prefix", "any;-;+12069106512", "+12069106512"],
["matches case-insensitively", "IMESSAGE;-;+12069106512", "+12069106512"],
["leaves group identifiers unchanged", "iMessage;+;chat0000", "iMessage;+;chat0000"],
[
"leaves group email identifiers unchanged",
"iMessage;+;Some@example.com",
);
});
it("leaves bare values unchanged", () => {
expect(normalizeDirectChatIdentifierForTest("+12069106512")).toBe("+12069106512");
expect(normalizeDirectChatIdentifierForTest("foo@bar.com")).toBe("foo@bar.com");
"iMessage;+;Some@example.com",
],
["leaves bare phone values unchanged", "+12069106512", "+12069106512"],
["leaves bare email values unchanged", "foo@bar.com", "foo@bar.com"],
])("%s", (_name, input, expected) => {
expect(normalizeDirectChatIdentifier(input)).toBe(expected);
});
});
+1 -6
View File
@@ -3,11 +3,7 @@ import { basename, parse, win32 } from "node:path";
import { sanitizeUntrustedFileName } from "openclaw/plugin-sdk/security-runtime";
import { resolvePreferredOpenClawTmpDir, withTempWorkspace } from "openclaw/plugin-sdk/temp-path";
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
import {
findChatGuidForTest,
normalizeDirectChatIdentifierForTest,
resolveIMessageActionChatGuid,
} from "./actions-chat-guid.js";
import { resolveIMessageActionChatGuid } from "./actions-chat-guid.js";
import {
type IMessageActionTransportOptions,
requestIMessageActionRpc,
@@ -21,7 +17,6 @@ import {
} from "./monitor-reply-cache.js";
import { sanitizeIMessageFinalOutboundText } from "./monitor/sanitize-outbound.js";
import { withIMessageRemoteFile } from "./remote-file.js";
export { findChatGuidForTest, normalizeDirectChatIdentifierForTest };
type IMessageBridgeActionOptions = IMessageActionTransportOptions & {
chatGuid: string;