refactor(imessage): consolidate status test fixtures (#118249)

This commit is contained in:
Peter Steinberger
2026-08-02 17:06:51 -07:00
committed by GitHub
parent cef675233b
commit 2a635f21df
+202 -383
View File
@@ -32,6 +32,110 @@ const setupToolsMocks = vi.hoisted(() => ({
}));
const installIMessageCliMock = vi.hoisted(() => vi.fn());
type CommandResult = Awaited<ReturnType<typeof processRuntime.runCommandWithTimeout>>;
type RpcClient = Awaited<ReturnType<typeof clientModule.createIMessageRpcClient>>;
type RpcPendingRequest = {
resolve: (value: unknown) => void;
reject: (error: Error) => void;
};
type RpcClientInternals = {
handleStdoutChunk: (chunk: Buffer | string) => void;
pending: Map<string, RpcPendingRequest>;
};
type TestPrompterOverrides = NonNullable<Parameters<typeof createTestWizardPrompter>[0]>;
function commandResult(overrides: Partial<CommandResult> = {}): CommandResult {
return {
stdout: "",
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
...overrides,
};
}
function privateStatusResult(overrides: Record<string, unknown> = {}): Partial<CommandResult> {
return {
stdout: JSON.stringify({
advanced_features: true,
v2_ready: true,
selectors: {},
rpc_methods: ["chats.list"],
...overrides,
}),
};
}
function mockCommandResult(overrides: Partial<CommandResult>) {
return vi
.spyOn(processRuntime, "runCommandWithTimeout")
.mockResolvedValue(commandResult(overrides));
}
function mockCommandSequence(...results: Array<Partial<CommandResult>>) {
const runCommand = vi.spyOn(processRuntime, "runCommandWithTimeout");
for (const result of results) {
runCommand.mockResolvedValueOnce(commandResult(result));
}
return runCommand;
}
function mockRpcClient(requestResult: unknown = { chats: [] }) {
const request = vi.fn().mockResolvedValue(requestResult);
const stop = vi.fn().mockResolvedValue(undefined);
const create = vi.spyOn(clientModule, "createIMessageRpcClient").mockResolvedValue({
request,
stop,
} as unknown as RpcClient);
return { create, request, stop };
}
function rpcClientInternals(client: RpcClient): RpcClientInternals {
return client as unknown as RpcClientInternals;
}
function mockSuccessfulInstall(detected: boolean, version: string): void {
setupToolsMocks.detectBinary.mockResolvedValueOnce(detected);
installIMessageCliMock.mockResolvedValueOnce({
ok: true,
cliPath: "/opt/homebrew/bin/imsg",
version,
});
}
async function getSetupStatus(imessage: Record<string, unknown>, accountId?: string) {
return await getIMessageSetupStatus({
cfg: { channels: { imessage } } as never,
accountOverrides: accountId ? { imessage: accountId } : {},
});
}
async function prepareIMessage(params: {
platform: NodeJS.Platform;
cliPath?: string;
prepare?: NonNullable<typeof imessageSetupWizard.prepare>;
confirm: NonNullable<TestPrompterOverrides["confirm"]>;
note?: TestPrompterOverrides["note"];
}) {
return await withPlatform(params.platform, () =>
runSetupWizardPrepare({
prepare: params.prepare ?? imessageSetupWizard.prepare,
cfg: {
channels: {
imessage: params.cliPath ? { cliPath: params.cliPath } : {},
},
} as never,
options: { allowIMessageInstall: true },
prompter: createTestWizardPrompter({
confirm: params.confirm,
...(params.note ? { note: params.note } : {}),
}),
}),
);
}
vi.mock("openclaw/plugin-sdk/setup-tools", async (importOriginal) => ({
...(await importOriginal<typeof import("openclaw/plugin-sdk/setup-tools")>()),
...setupToolsMocks,
@@ -128,16 +232,7 @@ describe("createIMessageRpcClient", () => {
async (_, separator) => {
const { IMessageRpcClient } = await import("./client.js");
const client = new IMessageRpcClient();
const internals = client as unknown as {
handleStdoutChunk: (chunk: Buffer | string) => void;
pending: Map<
string,
{
resolve: (value: unknown) => void;
reject: (error: Error) => void;
}
>;
};
const internals = rpcClientInternals(client);
const result = new Promise((resolve, reject) => {
internals.pending.set("1", { resolve, reject });
});
@@ -162,16 +257,7 @@ describe("createIMessageRpcClient", () => {
it("handles multiple LF-delimited stdout responses in one chunk", async () => {
const { IMessageRpcClient } = await import("./client.js");
const client = new IMessageRpcClient();
const internals = client as unknown as {
handleStdoutChunk: (chunk: Buffer | string) => void;
pending: Map<
string,
{
resolve: (value: unknown) => void;
reject: (error: Error) => void;
}
>;
};
const internals = rpcClientInternals(client);
const first = new Promise((resolve, reject) => {
internals.pending.set("1", { resolve, reject });
});
@@ -218,65 +304,43 @@ describe("imessage setup status", () => {
});
it("does not inherit configured state from a sibling account", async () => {
const result = await getIMessageSetupStatus({
cfg: {
channels: {
imessage: {
accounts: {
default: {
cliPath: "/usr/local/bin/imsg",
},
work: {},
},
},
const result = await getSetupStatus(
{
accounts: {
default: { cliPath: "/usr/local/bin/imsg" },
work: {},
},
},
accountOverrides: {
imessage: "work",
},
});
"work",
);
expect(result.configured).toBe(false);
expect(result.statusLines).toContain("iMessage: needs setup");
});
it("uses configured defaultAccount for omitted setup status cliPath", async () => {
const status = await getIMessageSetupStatus({
cfg: {
channels: {
imessage: {
cliPath: "/tmp/root-imsg",
defaultAccount: "work",
accounts: {
work: {
cliPath: "/tmp/work-imsg",
},
},
},
const status = await getSetupStatus({
cliPath: "/tmp/root-imsg",
defaultAccount: "work",
accounts: {
work: {
cliPath: "/tmp/work-imsg",
},
} as never,
accountOverrides: {},
},
});
expect(status.statusLines).toContain("imsg: missing (/tmp/work-imsg)");
});
it("does not inherit configured state from a sibling when defaultAccount is named", async () => {
const status = await getIMessageSetupStatus({
cfg: {
channels: {
imessage: {
defaultAccount: "work",
accounts: {
default: {
cliPath: "/usr/local/bin/imsg",
},
work: {},
},
},
const status = await getSetupStatus({
defaultAccount: "work",
accounts: {
default: {
cliPath: "/usr/local/bin/imsg",
},
} as never,
accountOverrides: {},
work: {},
},
});
expect(status.configured).toBe(false);
@@ -284,34 +348,23 @@ describe("imessage setup status", () => {
});
it("setup status lines use the selected account cliPath", async () => {
const status = await getIMessageSetupStatus({
cfg: {
channels: {
imessage: {
cliPath: "/tmp/root-imsg",
accounts: {
work: {
cliPath: "/tmp/work-imsg",
},
},
const status = await getSetupStatus(
{
cliPath: "/tmp/root-imsg",
accounts: {
work: {
cliPath: "/tmp/work-imsg",
},
},
} as never,
accountOverrides: { imessage: "work" },
});
},
"work",
);
expect(status.statusLines).toContain("imsg: missing (/tmp/work-imsg)");
});
it("setup status explains how to install imsg when the binary is missing", async () => {
const status = await getIMessageSetupStatus({
cfg: {
channels: {
imessage: {},
},
} as never,
accountOverrides: {},
});
const status = await getSetupStatus({});
expect(status.statusLines).toContain(
"Install imsg on the Messages Mac: brew install steipete/tap/imsg",
@@ -319,23 +372,11 @@ describe("imessage setup status", () => {
});
it("prepare offers to install imsg and returns the installed cliPath", async () => {
setupToolsMocks.detectBinary.mockResolvedValueOnce(false);
installIMessageCliMock.mockResolvedValueOnce({
ok: true,
cliPath: "/opt/homebrew/bin/imsg",
version: "0.13.0",
});
mockSuccessfulInstall(false, "0.13.0");
const confirm = vi.fn(async () => true);
const note = vi.fn(async () => {});
const result = await withPlatform("darwin", () =>
runSetupWizardPrepare({
prepare: imessageSetupWizard.prepare,
cfg: { channels: { imessage: {} } },
options: { allowIMessageInstall: true },
prompter: createTestWizardPrompter({ confirm, note }),
}),
);
const result = await prepareIMessage({ platform: "darwin", confirm, note });
expect(confirm).toHaveBeenCalledWith({
message: "imsg not found. Install now?",
@@ -351,16 +392,7 @@ describe("imessage setup status", () => {
});
it("setup status preserves an explicit PATH-based imsg wrapper", async () => {
const status = await getIMessageSetupStatus({
cfg: {
channels: {
imessage: {
cliPath: "imsg",
},
},
} as never,
accountOverrides: {},
});
const status = await getSetupStatus({ cliPath: "imsg" });
expect(status.statusLines).toContain(
"imsg command not found (imsg). Check the configured cliPath or wrapper.",
@@ -368,29 +400,16 @@ describe("imessage setup status", () => {
});
it("prepare offers to update Homebrew-managed imsg paths", async () => {
setupToolsMocks.detectBinary.mockResolvedValueOnce(true);
installIMessageCliMock.mockResolvedValueOnce({
ok: true,
cliPath: "/opt/homebrew/bin/imsg",
version: "0.13.1",
});
mockSuccessfulInstall(true, "0.13.1");
const confirm = vi.fn(async () => true);
const note = vi.fn(async () => {});
const result = await withPlatform("darwin", () =>
runSetupWizardPrepare({
prepare: imessageSetupWizard.prepare,
cfg: {
channels: {
imessage: {
cliPath: "/opt/homebrew/bin/imsg",
},
},
} as never,
options: { allowIMessageInstall: true },
prompter: createTestWizardPrompter({ confirm, note }),
}),
);
const result = await prepareIMessage({
platform: "darwin",
cliPath: "/opt/homebrew/bin/imsg",
confirm,
note,
});
expect(confirm).toHaveBeenCalledWith({
message: "imsg detected. Reinstall/update now?",
@@ -405,23 +424,15 @@ describe("imessage setup status", () => {
});
it("setup wizard proxy delegates imsg install preparation", async () => {
setupToolsMocks.detectBinary.mockResolvedValueOnce(false);
installIMessageCliMock.mockResolvedValueOnce({
ok: true,
cliPath: "/opt/homebrew/bin/imsg",
version: "0.13.0",
});
mockSuccessfulInstall(false, "0.13.0");
const proxy = createIMessageSetupWizardProxy(async () => imessageSetupWizard);
const confirm = vi.fn(async () => true);
const result = await withPlatform("darwin", () =>
runSetupWizardPrepare({
prepare: proxy.prepare,
cfg: { channels: { imessage: {} } },
options: { allowIMessageInstall: true },
prompter: createTestWizardPrompter({ confirm }),
}),
);
const result = await prepareIMessage({
platform: "darwin",
prepare: proxy.prepare,
confirm,
});
expect(confirm).toHaveBeenCalledWith({
message: "imsg not found. Install now?",
@@ -437,20 +448,11 @@ describe("imessage setup status", () => {
it("prepare preserves custom imsg cliPath values", async () => {
const confirm = vi.fn(async () => true);
const result = await withPlatform("darwin", () =>
runSetupWizardPrepare({
prepare: imessageSetupWizard.prepare,
cfg: {
channels: {
imessage: {
cliPath: "ssh imessage-host imsg",
},
},
} as never,
options: { allowIMessageInstall: true },
prompter: createTestWizardPrompter({ confirm }),
}),
);
const result = await prepareIMessage({
platform: "darwin",
cliPath: "ssh imessage-host imsg",
confirm,
});
expect(result).toBeUndefined();
expect(setupToolsMocks.detectBinary).not.toHaveBeenCalled();
@@ -461,20 +463,7 @@ describe("imessage setup status", () => {
it("prepare preserves explicit PATH-based imsg wrappers", async () => {
const confirm = vi.fn(async () => true);
const result = await withPlatform("darwin", () =>
runSetupWizardPrepare({
prepare: imessageSetupWizard.prepare,
cfg: {
channels: {
imessage: {
cliPath: "imsg",
},
},
} as never,
options: { allowIMessageInstall: true },
prompter: createTestWizardPrompter({ confirm }),
}),
);
const result = await prepareIMessage({ platform: "darwin", cliPath: "imsg", confirm });
expect(result).toBeUndefined();
expect(setupToolsMocks.detectBinary).not.toHaveBeenCalled();
@@ -485,14 +474,7 @@ describe("imessage setup status", () => {
it("prepare skips automatic imsg install on non-macOS hosts", async () => {
const confirm = vi.fn(async () => true);
const result = await withPlatform("linux", () =>
runSetupWizardPrepare({
prepare: imessageSetupWizard.prepare,
cfg: { channels: { imessage: {} } },
options: { allowIMessageInstall: true },
prompter: createTestWizardPrompter({ confirm }),
}),
);
const result = await prepareIMessage({ platform: "linux", confirm });
expect(result).toBeUndefined();
expect(setupToolsMocks.detectBinary).not.toHaveBeenCalled();
@@ -520,39 +502,26 @@ describe("probeIMessage", () => {
vi.restoreAllMocks();
spawnMock.mockClear();
vi.spyOn(setupRuntime, "detectBinary").mockResolvedValue(true);
vi.spyOn(processRuntime, "runCommandWithTimeout").mockResolvedValue({
stdout: "",
mockCommandResult({
stderr: 'unknown command "rpc" for "imsg"',
code: 1,
signal: null,
killed: false,
termination: "exit",
});
});
it("marks unknown rpc subcommand as fatal", async () => {
const createIMessageRpcClientMock = vi
.spyOn(clientModule, "createIMessageRpcClient")
.mockResolvedValue({
request: vi.fn(),
stop: vi.fn(),
} as unknown as Awaited<ReturnType<typeof clientModule.createIMessageRpcClient>>);
const { create } = mockRpcClient();
const result = await probeIMessage(1000, { cliPath: "imsg-test-rpc" });
expect(result.ok).toBe(false);
expect(result.fatal).toBe(true);
expect(result.error).toMatch(/rpc/i);
expect(result.error).toContain("brew update && brew upgrade imsg");
expect(createIMessageRpcClientMock).not.toHaveBeenCalled();
expect(create).not.toHaveBeenCalled();
});
it("explains how to update imsg when its private status subcommand is unsupported", async () => {
const runCommand = vi.spyOn(processRuntime, "runCommandWithTimeout").mockResolvedValueOnce({
stdout: "",
const runCommand = mockCommandSequence({
stderr: "Unknown subcommand 'status' for command 'imsg'",
code: 1,
signal: null,
killed: false,
termination: "exit",
});
await expect(
@@ -576,30 +545,14 @@ describe("probeIMessage", () => {
});
it("keeps foundational RPC healthy when an older imsg lacks private status", async () => {
const runCommand = vi
.spyOn(processRuntime, "runCommandWithTimeout")
.mockResolvedValueOnce({
stdout: "rpc help",
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
})
.mockResolvedValueOnce({
stdout: "",
const runCommand = mockCommandSequence(
{ stdout: "rpc help" },
{
stderr: "Unknown subcommand 'status' for command 'imsg'",
code: 1,
signal: null,
killed: false,
termination: "exit",
});
const request = vi.fn().mockResolvedValue({ chats: [] });
const stop = vi.fn().mockResolvedValue(undefined);
vi.spyOn(clientModule, "createIMessageRpcClient").mockResolvedValue({
request,
stop,
} as unknown as Awaited<ReturnType<typeof clientModule.createIMessageRpcClient>>);
},
);
const { request, stop } = mockRpcClient();
await expect(
probeIMessage(1000, { cliPath: "imsg-legacy-foundational-rpc", platform: "darwin" }),
@@ -618,12 +571,7 @@ describe("probeIMessage", () => {
it("explains how to install imsg when the default binary is missing", async () => {
vi.spyOn(setupRuntime, "detectBinary").mockResolvedValue(false);
const createIMessageRpcClientMock = vi
.spyOn(clientModule, "createIMessageRpcClient")
.mockResolvedValue({
request: vi.fn(),
stop: vi.fn(),
} as unknown as Awaited<ReturnType<typeof clientModule.createIMessageRpcClient>>);
const { create } = mockRpcClient();
const result = await probeIMessage(1000, { platform: "darwin" });
@@ -632,17 +580,12 @@ describe("probeIMessage", () => {
"imsg not found (imsg). Install imsg on the Messages Mac: brew install steipete/tap/imsg",
);
expect(processRuntime.runCommandWithTimeout).not.toHaveBeenCalled();
expect(createIMessageRpcClientMock).not.toHaveBeenCalled();
expect(create).not.toHaveBeenCalled();
});
it("explains how to fix an explicit PATH-based imsg wrapper", async () => {
vi.spyOn(setupRuntime, "detectBinary").mockResolvedValue(false);
const createIMessageRpcClientMock = vi
.spyOn(clientModule, "createIMessageRpcClient")
.mockResolvedValue({
request: vi.fn(),
stop: vi.fn(),
} as unknown as Awaited<ReturnType<typeof clientModule.createIMessageRpcClient>>);
const { create } = mockRpcClient();
const result = await probeIMessage(1000, { cliPath: "imsg", platform: "darwin" });
@@ -651,17 +594,12 @@ describe("probeIMessage", () => {
"imsg command not found (imsg). Check the configured iMessage cliPath or wrapper.",
);
expect(processRuntime.runCommandWithTimeout).not.toHaveBeenCalled();
expect(createIMessageRpcClientMock).not.toHaveBeenCalled();
expect(create).not.toHaveBeenCalled();
});
it("explains how to fix a missing custom imsg wrapper", async () => {
vi.spyOn(setupRuntime, "detectBinary").mockResolvedValue(false);
const createIMessageRpcClientMock = vi
.spyOn(clientModule, "createIMessageRpcClient")
.mockResolvedValue({
request: vi.fn(),
stop: vi.fn(),
} as unknown as Awaited<ReturnType<typeof clientModule.createIMessageRpcClient>>);
const { create } = mockRpcClient();
const result = await probeIMessage(1000, { cliPath: "/usr/local/bin/imsg-wrapper" });
@@ -670,7 +608,7 @@ describe("probeIMessage", () => {
"imsg command not found (/usr/local/bin/imsg-wrapper). Check the configured iMessage cliPath or wrapper.",
);
expect(processRuntime.runCommandWithTimeout).not.toHaveBeenCalled();
expect(createIMessageRpcClientMock).not.toHaveBeenCalled();
expect(create).not.toHaveBeenCalled();
});
it("drops cached rpc support when the current clock is not a valid date timestamp", async () => {
@@ -678,49 +616,16 @@ describe("probeIMessage", () => {
.mockReturnValueOnce(1_700_000_000_000)
.mockReturnValueOnce(Number.NaN)
.mockReturnValue(1_700_000_000_000);
const runCommand = vi
.spyOn(processRuntime, "runCommandWithTimeout")
.mockResolvedValueOnce({
stdout: "",
const runCommand = mockCommandSequence(
{
stderr: 'unknown command "rpc" for "imsg"',
code: 1,
signal: null,
killed: false,
termination: "exit",
})
.mockResolvedValueOnce({
stdout: "rpc help",
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
})
.mockResolvedValueOnce({
stdout: JSON.stringify({
advanced_features: true,
v2_ready: true,
selectors: {},
rpc_methods: ["chats.list"],
}),
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
})
.mockResolvedValueOnce({
stdout: "send-rich --file",
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
});
vi.spyOn(clientModule, "createIMessageRpcClient").mockResolvedValue({
request: vi.fn().mockResolvedValue({ chats: [] }),
stop: vi.fn().mockResolvedValue(undefined),
} as unknown as Awaited<ReturnType<typeof clientModule.createIMessageRpcClient>>);
},
{ stdout: "rpc help" },
privateStatusResult(),
{ stdout: "send-rich --file" },
);
mockRpcClient();
await expect(probeIMessage(1000, { cliPath: "imsg-invalid-rpc-clock" })).resolves.toMatchObject(
{
@@ -744,13 +649,9 @@ describe("probeIMessage", () => {
it("does not cache rpc support when the expiry timestamp would exceed the valid date range", async () => {
vi.spyOn(Date, "now").mockReturnValue(8_640_000_000_000_000);
const runCommand = vi.spyOn(processRuntime, "runCommandWithTimeout").mockResolvedValue({
stdout: "",
const runCommand = mockCommandResult({
stderr: 'unknown command "rpc" for "imsg"',
code: 1,
signal: null,
killed: false,
termination: "exit",
});
await expect(
@@ -771,14 +672,7 @@ describe("probeIMessage", () => {
it("does not cache unavailable private API status when the process clock is invalid", async () => {
vi.spyOn(Date, "now").mockReturnValue(Number.NaN);
const runCommand = vi.spyOn(processRuntime, "runCommandWithTimeout").mockResolvedValue({
stdout: "",
stderr: "bridge unavailable",
code: 1,
signal: null,
killed: false,
termination: "exit",
});
const runCommand = mockCommandResult({ stderr: "bridge unavailable", code: 1 });
await expect(
probeIMessagePrivateApi("imsg-invalid-private-status-clock", 1000),
@@ -799,29 +693,10 @@ describe("probeIMessage", () => {
it("propagates imsg's status message when advanced features are unavailable", async () => {
const note =
"System Integrity Protection (SIP) is enabled.\nAdvanced IMCore features are intentionally disabled.";
vi.spyOn(processRuntime, "runCommandWithTimeout")
.mockResolvedValueOnce({
stdout: JSON.stringify({
advanced_features: false,
v2_ready: false,
selectors: {},
rpc_methods: ["chats.list"],
message: note,
}),
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
})
.mockResolvedValueOnce({
stdout: "send-rich --help",
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
});
mockCommandSequence(
privateStatusResult({ advanced_features: false, v2_ready: false, message: note }),
{ stdout: "send-rich --help" },
);
await expect(probeIMessagePrivateApi("imsg-status-message-test", 1000)).resolves.toMatchObject({
available: false,
@@ -830,37 +705,11 @@ describe("probeIMessage", () => {
});
it("detects poll caption suppression from the exact poll send help contract", async () => {
const runCommand = vi
.spyOn(processRuntime, "runCommandWithTimeout")
.mockResolvedValueOnce({
stdout: JSON.stringify({
advanced_features: true,
v2_ready: true,
selectors: { pollPayloadMessage: true },
rpc_methods: ["chats.list"],
}),
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
})
.mockResolvedValueOnce({
stdout: "send-rich --file",
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
})
.mockResolvedValueOnce({
stdout: "poll send --question <text> --option <text> --no-comment",
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
});
const runCommand = mockCommandSequence(
privateStatusResult({ selectors: { pollPayloadMessage: true } }),
{ stdout: "send-rich --file" },
{ stdout: "poll send --question <text> --option <text> --no-comment" },
);
await expect(
probeIMessagePrivateApi("imsg-poll-no-comment-supported", 1000),
@@ -875,36 +724,11 @@ describe("probeIMessage", () => {
});
it("does not infer poll caption suppression from selectors when the flag is absent", async () => {
vi.spyOn(processRuntime, "runCommandWithTimeout")
.mockResolvedValueOnce({
stdout: JSON.stringify({
advanced_features: true,
v2_ready: true,
selectors: { pollPayloadMessage: true },
rpc_methods: ["chats.list"],
}),
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
})
.mockResolvedValueOnce({
stdout: "send-rich --file",
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
})
.mockResolvedValueOnce({
stdout: "poll send --question <text> --option <text>",
stderr: "",
code: 0,
signal: null,
killed: false,
termination: "exit",
});
mockCommandSequence(
privateStatusResult({ selectors: { pollPayloadMessage: true } }),
{ stdout: "send-rich --file" },
{ stdout: "poll send --question <text> --option <text>" },
);
await expect(
probeIMessagePrivateApi("imsg-poll-no-comment-absent", 1000),
@@ -916,12 +740,7 @@ describe("probeIMessage", () => {
});
it("fails fast for default local imsg probes on non-mac hosts", async () => {
const createIMessageRpcClientMock = vi
.spyOn(clientModule, "createIMessageRpcClient")
.mockResolvedValue({
request: vi.fn(),
stop: vi.fn(),
} as unknown as Awaited<ReturnType<typeof clientModule.createIMessageRpcClient>>);
const { create } = mockRpcClient();
const result = await probeIMessage(1000, { cliPath: "imsg", platform: "linux" });
@@ -930,7 +749,7 @@ describe("probeIMessage", () => {
expect(result.error).toMatch(/macOS/i);
expect(result.error).toMatch(/SSH wrapper/i);
expect(setupRuntime.detectBinary).not.toHaveBeenCalled();
expect(createIMessageRpcClientMock).not.toHaveBeenCalled();
expect(create).not.toHaveBeenCalled();
});
it("status probe uses account-scoped cliPath and dbPath", async () => {