























@@ -105,6 +105,34 @@ function buildResetParams(
105105};
106106}
107107108+function mockCall(mock: unknown, index = 0): Array<unknown> {
109+const calls = (mock as { mock?: { calls?: Array<Array<unknown>> } }).mock?.calls ?? [];
110+const call = calls.at(index);
111+expect(call, `mock call ${index + 1}`).toBeDefined();
112+return call as Array<unknown>;
113+}
114+115+function requireRecord(value: unknown, label: string): Record<string, unknown> {
116+expect(value, label).toBeTypeOf("object");
117+expect(value, label).not.toBeNull();
118+return value as Record<string, unknown>;
119+}
120+121+function expectObjectFields(
122+value: unknown,
123+expected: Record<string, unknown>,
124+label = "object",
125+): void {
126+const record = requireRecord(value, label);
127+for (const [key, expectedValue] of Object.entries(expected)) {
128+expect(record[key], `${label}.${key}`).toEqual(expectedValue);
129+}
130+}
131+132+function firstHookEvent(): Record<string, unknown> {
133+return requireRecord(mockCall(triggerInternalHookMock)[0], "hook event");
134+}
135+108136describe("handleCommands reset hooks", () => {
109137let clearBootstrapSnapshotSpy: ReturnType<typeof vi.spyOn>;
110138@@ -128,7 +156,7 @@ describe("handleCommands reset hooks", () => {
128156commands: { text: true },
129157channels: { whatsapp: { allowFrom: ["*"] } },
130158} as OpenClawConfig),
131-expectedCall: expect.objectContaining({ type: "command", action: "new" }),
159+expectedEvent: { type: "command", action: "new" },
132160},
133161{
134162name: "native command routed to target session",
@@ -154,20 +182,24 @@ describe("handleCommands reset hooks", () => {
154182params.sessionKey = "agent:main:telegram:direct:123";
155183return params;
156184})(),
157-expectedCall: expect.objectContaining({
185+expectedEvent: {
158186type: "command",
159187action: "new",
160188sessionKey: "agent:main:telegram:direct:123",
161- context: expect.objectContaining({
162- workspaceDir: "/tmp/openclaw-commands",
163-}),
164-}),
189+},
190+expectedContext: {
191+workspaceDir: "/tmp/openclaw-commands",
192+},
165193},
166194] as const;
167195168196for (const testCase of cases) {
169197await maybeHandleResetCommand(testCase.params);
170-expect(triggerInternalHookMock, testCase.name).toHaveBeenCalledWith(testCase.expectedCall);
198+const event = firstHookEvent();
199+expectObjectFields(event, testCase.expectedEvent, testCase.name);
200+if ("expectedContext" in testCase) {
201+expectObjectFields(event.context, testCase.expectedContext, `${testCase.name}.context`);
202+}
171203triggerInternalHookMock.mockClear();
172204}
173205});
@@ -191,8 +223,13 @@ describe("handleCommands reset hooks", () => {
191223192224const result = await maybeHandleResetCommand(params);
193225194-expect(resetMocks.resetConfiguredBindingTargetInPlace).toHaveBeenCalledWith({
195-cfg: expect.any(Object),
226+const resetArgs = requireRecord(
227+mockCall(resetMocks.resetConfiguredBindingTargetInPlace)[0],
228+"reset args",
229+);
230+expect(resetArgs.cfg).toBeTypeOf("object");
231+expect(resetArgs.cfg).not.toBeNull();
232+expectObjectFields(resetArgs, {
196233sessionKey: "agent:claude:acp:binding:discord:default:9373ab192b2317f4",
197234reason: "reset",
198235commandSource: "discord:native",
@@ -253,15 +290,13 @@ describe("handleCommands reset hooks", () => {
253290254291const result = await maybeHandleResetCommand(params);
255292256-expect(routeReplyMock).toHaveBeenCalledWith(
257-expect.objectContaining({
258-requesterSenderId: "id:whatsapp:123",
259-requesterSenderName: "Alice",
260-requesterSenderUsername: "alice_u",
261-requesterSenderE164: "+15551234567",
262-threadId: "thread-1",
263-}),
264-);
293+expectObjectFields(mockCall(routeReplyMock)[0], {
294+requesterSenderId: "id:whatsapp:123",
295+requesterSenderName: "Alice",
296+requesterSenderUsername: "alice_u",
297+requesterSenderE164: "+15551234567",
298+threadId: "thread-1",
299+});
265300expect(result).toEqual({ shouldContinue: false });
266301});
267302@@ -283,15 +318,9 @@ describe("handleCommands reset hooks", () => {
283318284319await maybeHandleResetCommand(params);
285320286-expect(triggerInternalHookMock).toHaveBeenCalledWith(
287-expect.objectContaining({
288-context: expect.objectContaining({
289-sessionEntry: expect.objectContaining({
290-sessionId: "target-session",
291-}),
292-}),
293-}),
294-);
321+const event = firstHookEvent();
322+const context = requireRecord(event.context, "hook context");
323+expectObjectFields(context.sessionEntry, { sessionId: "target-session" }, "session entry");
295324});
296325297326it("marks soft reset turns and emits reset hooks", async () => {
@@ -315,17 +344,10 @@ describe("handleCommands reset hooks", () => {
315344const result = await maybeHandleResetCommand(params);
316345317346expect(result).toBeNull();
318-expect(triggerInternalHookMock).toHaveBeenCalledWith(
319-expect.objectContaining({
320-type: "command",
321-action: "reset",
322-context: expect.objectContaining({
323-previousSessionEntry: expect.objectContaining({
324-sessionId: "session-1",
325-}),
326-}),
327-}),
328-);
347+const event = firstHookEvent();
348+expectObjectFields(event, { type: "command", action: "reset" }, "hook event");
349+const context = requireRecord(event.context, "hook context");
350+expectObjectFields(context.previousSessionEntry, { sessionId: "session-1" }, "session entry");
329351expect(params.command.resetHookTriggered).toBe(true);
330352expect(params.command.softResetTriggered).toBe(true);
331353expect(params.command.softResetTail).toBe("");
@@ -444,9 +466,7 @@ describe("handleCommands reset hooks", () => {
444466shouldContinue: false,
445467reply: { text: "✅ Session reset." },
446468});
447-expect(triggerInternalHookMock).toHaveBeenCalledWith(
448-expect.objectContaining({ type: "command", action: "reset" }),
449-);
469+expectObjectFields(firstHookEvent(), { type: "command", action: "reset" }, "hook event");
450470});
451471452472it("acknowledges bare /new without falling through to model execution", async () => {
@@ -461,9 +481,7 @@ describe("handleCommands reset hooks", () => {
461481shouldContinue: false,
462482reply: { text: "✅ New session started." },
463483});
464-expect(triggerInternalHookMock).toHaveBeenCalledWith(
465-expect.objectContaining({ type: "command", action: "new" }),
466-);
484+expectObjectFields(firstHookEvent(), { type: "command", action: "new" }, "hook event");
467485});
468486469487it("keeps reset tails falling through so the model receives the user input", async () => {
@@ -475,8 +493,6 @@ describe("handleCommands reset hooks", () => {
475493const result = await maybeHandleResetCommand(params);
476494477495expect(result).toBeNull();
478-expect(triggerInternalHookMock).toHaveBeenCalledWith(
479-expect.objectContaining({ type: "command", action: "new" }),
480-);
496+expectObjectFields(firstHookEvent(), { type: "command", action: "new" }, "hook event");
481497});
482498});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。