


























@@ -143,6 +143,33 @@ async function runInlineStatusAction(storePath?: string) {
143143return { result, typing };
144144}
145145146+function requireRecord(value: unknown, label: string): Record<string, unknown> {
147+expect(value).toBeTypeOf("object");
148+expect(value).not.toBeNull();
149+if (!value || typeof value !== "object" || Array.isArray(value)) {
150+throw new Error(`expected ${label} to be an object`);
151+}
152+return value as Record<string, unknown>;
153+}
154+155+function mockObjectArg(mock: ReturnType<typeof vi.fn>, label: string, callIndex = 0, argIndex = 0) {
156+const call = mock.mock.calls[callIndex];
157+expect(call).toBeDefined();
158+if (!call) {
159+throw new Error(`expected ${label} mock call ${callIndex}`);
160+}
161+return requireRecord(call[argIndex], `${label} argument ${argIndex}`);
162+}
163+164+function mockCallArgs(mock: ReturnType<typeof vi.fn>, label: string, callIndex = 0): unknown[] {
165+const call = mock.mock.calls[callIndex] as unknown[] | undefined;
166+expect(call).toBeDefined();
167+if (!call) {
168+throw new Error(`expected ${label} mock call ${callIndex}`);
169+}
170+return call;
171+}
172+146173describe("handleInlineActions", () => {
147174beforeEach(() => {
148175handleCommandsMock.mockReset();
@@ -207,11 +234,7 @@ describe("handleInlineActions", () => {
207234208235expect(result).toEqual({ kind: "reply", reply: { text: "done" } });
209236expect(handleCommandsMock).toHaveBeenCalledTimes(1);
210-expect(handleCommandsMock).toHaveBeenCalledWith(
211-expect.objectContaining({
212- agentDir,
213-}),
214-);
237+expect(mockObjectArg(handleCommandsMock, "handleCommands").agentDir).toBe(agentDir);
215238});
216239217240it("prefers the target session entry when routing inline commands into handleCommands", async () => {
@@ -252,12 +275,9 @@ describe("handleInlineActions", () => {
252275);
253276254277expect(result).toEqual({ kind: "reply", reply: { text: "done" } });
255-expect(handleCommandsMock).toHaveBeenCalledWith(
256-expect.objectContaining({
257-sessionEntry: expect.objectContaining({
258-sessionId: "target-session",
259-}),
260-}),
278+const commandArgs = mockObjectArg(handleCommandsMock, "handleCommands");
279+expect(requireRecord(commandArgs.sessionEntry, "sessionEntry").sessionId).toBe(
280+"target-session",
261281);
262282});
263283@@ -266,11 +286,7 @@ describe("handleInlineActions", () => {
266286267287expect(result).toEqual({ kind: "reply", reply: undefined });
268288expect(buildStatusReplyMock).toHaveBeenCalledTimes(1);
269-expect(buildStatusReplyMock).toHaveBeenCalledWith(
270-expect.objectContaining({
271-storePath: undefined,
272-}),
273-);
289+expect(mockObjectArg(buildStatusReplyMock, "buildStatusReply").storePath).toBeUndefined();
274290expect(handleCommandsMock).not.toHaveBeenCalled();
275291expect(typing.cleanup).toHaveBeenCalled();
276292});
@@ -279,10 +295,8 @@ describe("handleInlineActions", () => {
279295const { result } = await runInlineStatusAction("/tmp/inline-status-store.json");
280296281297expect(result).toEqual({ kind: "reply", reply: undefined });
282-expect(buildStatusReplyMock).toHaveBeenCalledWith(
283-expect.objectContaining({
284-storePath: "/tmp/inline-status-store.json",
285-}),
298+expect(mockObjectArg(buildStatusReplyMock, "buildStatusReply").storePath).toBe(
299+"/tmp/inline-status-store.json",
286300);
287301expect(handleCommandsMock).not.toHaveBeenCalled();
288302});
@@ -325,15 +339,11 @@ describe("handleInlineActions", () => {
325339);
326340327341expect(result).toEqual({ kind: "reply", reply: undefined });
328-expect(buildStatusReplyMock).toHaveBeenCalledWith(
329-expect.objectContaining({
330-sessionEntry: expect.objectContaining({
331-sessionId: "target-session",
332-parentSessionKey: "target-parent",
333-}),
334-parentSessionKey: "target-parent",
335-}),
336-);
342+const statusArgs = mockObjectArg(buildStatusReplyMock, "buildStatusReply");
343+const statusSessionEntry = requireRecord(statusArgs.sessionEntry, "status sessionEntry");
344+expect(statusSessionEntry.sessionId).toBe("target-session");
345+expect(statusSessionEntry.parentSessionKey).toBe("target-parent");
346+expect(statusArgs.parentSessionKey).toBe("target-parent");
337347expect(handleCommandsMock).not.toHaveBeenCalled();
338348});
339349@@ -564,12 +574,9 @@ describe("handleInlineActions", () => {
564574expect(ctx.Body).toBe(
565575"Act as an engineering advisor.\n\nFocus on:\nbuild me a deployment plan",
566576);
567-expect(handleCommandsMock).toHaveBeenCalledWith(
568-expect.objectContaining({
569-ctx: expect.objectContaining({
570-Body: "Act as an engineering advisor.\n\nFocus on:\nbuild me a deployment plan",
571-}),
572-}),
577+const commandArgs = mockObjectArg(handleCommandsMock, "handleCommands");
578+expect(requireRecord(commandArgs.ctx, "handleCommands ctx").Body).toBe(
579+"Act as an engineering advisor.\n\nFocus on:\nbuild me a deployment plan",
573580);
574581});
575582@@ -624,11 +631,9 @@ describe("handleInlineActions", () => {
624631);
625632626633expect(result).toEqual({ kind: "reply", reply: { text: "✅ Done." } });
627-expect(createOpenClawToolsMock).toHaveBeenCalledWith(
628-expect.objectContaining({
629-requesterAgentIdOverride: "named-worker",
630-}),
631-);
634+expect(
635+mockObjectArg(createOpenClawToolsMock, "createOpenClawTools").requesterAgentIdOverride,
636+).toBe("named-worker");
632637expect(toolExecute).toHaveBeenCalled();
633638});
634639@@ -682,20 +687,15 @@ describe("handleInlineActions", () => {
682687);
683688684689expect(result).toEqual({ kind: "reply", reply: { text: "✅ Done." } });
685-expect(createOpenClawToolsMock).toHaveBeenCalledWith(
686-expect.objectContaining({
687-senderIsOwner: true,
688-}),
689-);
690-expect(toolExecute).toHaveBeenCalledWith(
691-expect.stringMatching(/^cmd_/),
692-{
693-command: "display name",
694-commandName: "set_profile",
695-skillName: "matrix-profile",
696-},
697-undefined,
698-);
690+expect(mockObjectArg(createOpenClawToolsMock, "createOpenClawTools").senderIsOwner).toBe(true);
691+const toolCall = mockCallArgs(toolExecute, "toolExecute");
692+expect(toolCall?.[0]).toMatch(/^cmd_/);
693+expect(toolCall?.[1]).toEqual({
694+command: "display name",
695+commandName: "set_profile",
696+skillName: "matrix-profile",
697+});
698+expect(toolCall?.[2]).toBeUndefined();
699699});
700700701701it("honors construction-time before-tool-call blocks for inline tool dispatch", async () => {
@@ -778,21 +778,17 @@ describe("handleInlineActions", () => {
778778kind: "reply",
779779reply: { text: "❌ Tool call blocked: denied by policy" },
780780});
781-expect(createOpenClawToolsMock).toHaveBeenCalledWith(
782-expect.objectContaining({
783-sessionId: "target-session",
784-currentChannelId: "whatsapp",
785-}),
786-);
787-expect(toolExecute).toHaveBeenCalledWith(
788-expect.stringMatching(/^cmd_/),
789-{
790-command: "display name",
791-commandName: "set_profile",
792-skillName: "matrix-profile",
793-},
794-abortController.signal,
795-);
781+const toolsArgs = mockObjectArg(createOpenClawToolsMock, "createOpenClawTools");
782+expect(toolsArgs.sessionId).toBe("target-session");
783+expect(toolsArgs.currentChannelId).toBe("whatsapp");
784+const blockedToolCall = mockCallArgs(toolExecute, "toolExecute");
785+expect(blockedToolCall?.[0]).toMatch(/^cmd_/);
786+expect(blockedToolCall?.[1]).toEqual({
787+command: "display name",
788+commandName: "set_profile",
789+skillName: "matrix-profile",
790+});
791+expect(blockedToolCall?.[2]).toBe(abortController.signal);
796792expect(typing.cleanup).toHaveBeenCalled();
797793});
798794});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。