diff --git a/extensions/imessage/src/status.test.ts b/extensions/imessage/src/status.test.ts index 0bbc3f52f2e6..c805a0b15488 100644 --- a/extensions/imessage/src/status.test.ts +++ b/extensions/imessage/src/status.test.ts @@ -32,6 +32,110 @@ const setupToolsMocks = vi.hoisted(() => ({ })); const installIMessageCliMock = vi.hoisted(() => vi.fn()); +type CommandResult = Awaited>; +type RpcClient = Awaited>; +type RpcPendingRequest = { + resolve: (value: unknown) => void; + reject: (error: Error) => void; +}; +type RpcClientInternals = { + handleStdoutChunk: (chunk: Buffer | string) => void; + pending: Map; +}; +type TestPrompterOverrides = NonNullable[0]>; + +function commandResult(overrides: Partial = {}): CommandResult { + return { + stdout: "", + stderr: "", + code: 0, + signal: null, + killed: false, + termination: "exit", + ...overrides, + }; +} + +function privateStatusResult(overrides: Record = {}): Partial { + return { + stdout: JSON.stringify({ + advanced_features: true, + v2_ready: true, + selectors: {}, + rpc_methods: ["chats.list"], + ...overrides, + }), + }; +} + +function mockCommandResult(overrides: Partial) { + return vi + .spyOn(processRuntime, "runCommandWithTimeout") + .mockResolvedValue(commandResult(overrides)); +} + +function mockCommandSequence(...results: Array>) { + 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, 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; + confirm: NonNullable; + 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()), ...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>); + 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>); + }, + ); + 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>); + 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>); + 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>); + 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>); + }, + { 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 --option --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 --option --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 --option ", - stderr: "", - code: 0, - signal: null, - killed: false, - termination: "exit", - }); + mockCommandSequence( + privateStatusResult({ selectors: { pollPayloadMessage: true } }), + { stdout: "send-rich --file" }, + { stdout: "poll send --question --option " }, + ); 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>); + 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 () => {