From 7b46f2c17fa41121712dfa697e39b211f7f59648 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 18 Feb 2026 13:01:37 +0000 Subject: [PATCH] test(imessage): dedupe send test scaffolding --- src/imessage/send.test.ts | 117 +++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 66 deletions(-) diff --git a/src/imessage/send.test.ts b/src/imessage/send.test.ts index 1e985a229a..6055d12895 100644 --- a/src/imessage/send.test.ts +++ b/src/imessage/send.test.ts @@ -1,5 +1,6 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import type { ResolvedIMessageAccount } from "./accounts.js"; +import type { IMessageRpcClient } from "./client.js"; import { sendMessageIMessage } from "./send.js"; const requestMock = vi.fn(); @@ -12,6 +13,30 @@ const defaultAccount: ResolvedIMessageAccount = { config: {}, }; +function createClient(): IMessageRpcClient { + return { + request: (...args: unknown[]) => requestMock(...args), + stop: (...args: unknown[]) => stopMock(...args), + } as unknown as IMessageRpcClient; +} + +async function sendWithDefaults( + to: string, + text: string, + opts: Parameters[2] = {}, +) { + return await sendMessageIMessage(to, text, { + account: defaultAccount, + config: {}, + client: createClient(), + ...opts, + }); +} + +function getSentParams() { + return requestMock.mock.calls[0]?.[1] as Record; +} + describe("sendMessageIMessage", () => { beforeEach(() => { requestMock.mockReset().mockResolvedValue({ ok: true }); @@ -19,119 +44,79 @@ describe("sendMessageIMessage", () => { }); it("sends to chat_id targets", async () => { - await sendMessageIMessage("chat_id:123", "hi", { - account: defaultAccount, - config: {}, - client: { - request: (...args: unknown[]) => requestMock(...args), - stop: (...args: unknown[]) => stopMock(...args), - } as unknown as import("./client.js").IMessageRpcClient, - }); - const params = requestMock.mock.calls[0]?.[1] as Record; + await sendWithDefaults("chat_id:123", "hi"); + const params = getSentParams(); expect(requestMock).toHaveBeenCalledWith("send", expect.any(Object), expect.any(Object)); expect(params.chat_id).toBe(123); expect(params.text).toBe("hi"); }); it("applies sms service prefix", async () => { - await sendMessageIMessage("sms:+1555", "hello", { - account: defaultAccount, - config: {}, - client: { - request: (...args: unknown[]) => requestMock(...args), - stop: (...args: unknown[]) => stopMock(...args), - } as unknown as import("./client.js").IMessageRpcClient, - }); - const params = requestMock.mock.calls[0]?.[1] as Record; + await sendWithDefaults("sms:+1555", "hello"); + const params = getSentParams(); expect(params.service).toBe("sms"); expect(params.to).toBe("+1555"); }); it("adds file attachment with placeholder text", async () => { - await sendMessageIMessage("chat_id:7", "", { + await sendWithDefaults("chat_id:7", "", { mediaUrl: "http://x/y.jpg", - account: defaultAccount, - config: {}, resolveAttachmentImpl: async () => ({ path: "/tmp/imessage-media.jpg", contentType: "image/jpeg", }), - client: { - request: (...args: unknown[]) => requestMock(...args), - stop: (...args: unknown[]) => stopMock(...args), - } as unknown as import("./client.js").IMessageRpcClient, }); - const params = requestMock.mock.calls[0]?.[1] as Record; + const params = getSentParams(); expect(params.file).toBe("/tmp/imessage-media.jpg"); expect(params.text).toBe(""); }); it("returns message id when rpc provides one", async () => { requestMock.mockResolvedValue({ ok: true, id: 123 }); - const result = await sendMessageIMessage("chat_id:7", "hello", { - account: defaultAccount, - config: {}, - client: { - request: (...args: unknown[]) => requestMock(...args), - stop: (...args: unknown[]) => stopMock(...args), - } as unknown as import("./client.js").IMessageRpcClient, - }); + const result = await sendWithDefaults("chat_id:7", "hello"); expect(result.messageId).toBe("123"); }); it("prepends reply tag as the first token when replyToId is provided", async () => { - await sendMessageIMessage("chat_id:123", " hello\nworld", { + await sendWithDefaults("chat_id:123", " hello\nworld", { replyToId: "abc-123", - account: defaultAccount, - config: {}, - client: { - request: (...args: unknown[]) => requestMock(...args), - stop: (...args: unknown[]) => stopMock(...args), - } as unknown as import("./client.js").IMessageRpcClient, }); - const params = requestMock.mock.calls[0]?.[1] as Record; + const params = getSentParams(); expect(params.text).toBe("[[reply_to:abc-123]] hello\nworld"); }); it("rewrites an existing leading reply tag to keep the requested id first", async () => { - await sendMessageIMessage("chat_id:123", " [[reply_to:old-id]] hello", { + await sendWithDefaults("chat_id:123", " [[reply_to:old-id]] hello", { replyToId: "new-id", - account: defaultAccount, - config: {}, - client: { - request: (...args: unknown[]) => requestMock(...args), - stop: (...args: unknown[]) => stopMock(...args), - } as unknown as import("./client.js").IMessageRpcClient, }); - const params = requestMock.mock.calls[0]?.[1] as Record; + const params = getSentParams(); expect(params.text).toBe("[[reply_to:new-id]] hello"); }); it("sanitizes replyToId before writing the leading reply tag", async () => { - await sendMessageIMessage("chat_id:123", "hello", { + await sendWithDefaults("chat_id:123", "hello", { replyToId: " [ab]\n\u0000c\td ] ", - account: defaultAccount, - config: {}, - client: { - request: (...args: unknown[]) => requestMock(...args), - stop: (...args: unknown[]) => stopMock(...args), - } as unknown as import("./client.js").IMessageRpcClient, }); - const params = requestMock.mock.calls[0]?.[1] as Record; + const params = getSentParams(); expect(params.text).toBe("[[reply_to:abcd]] hello"); }); it("skips reply tagging when sanitized replyToId is empty", async () => { - await sendMessageIMessage("chat_id:123", "hello", { + await sendWithDefaults("chat_id:123", "hello", { replyToId: "[]\u0000\n\r", - account: defaultAccount, - config: {}, - client: { - request: (...args: unknown[]) => requestMock(...args), - stop: (...args: unknown[]) => stopMock(...args), - } as unknown as import("./client.js").IMessageRpcClient, }); - const params = requestMock.mock.calls[0]?.[1] as Record; + const params = getSentParams(); expect(params.text).toBe("hello"); }); + + it("normalizes string message_id values from rpc result", async () => { + requestMock.mockResolvedValue({ ok: true, message_id: " guid-1 " }); + const result = await sendWithDefaults("chat_id:7", "hello"); + expect(result.messageId).toBe("guid-1"); + }); + + it("does not stop an injected client", async () => { + await sendWithDefaults("chat_id:123", "hello"); + expect(stopMock).not.toHaveBeenCalled(); + }); });