From 2afca355774f0942e4fb92aa19b8b3c20557c67a Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 12 May 2026 09:34:09 +0100 Subject: [PATCH] test: guard agent four-hit mock calls --- .../attempt.model-diagnostic-events.test.ts | 8 +++--- src/agents/session-file-repair.test.ts | 8 +++--- src/agents/skills-install-fallback.test.ts | 8 +++--- src/agents/subagent-announce.test.ts | 8 +++--- src/agents/subagent-orphan-recovery.test.ts | 25 ++++++++++++++++--- .../subagent-registry.steer-restart.test.ts | 8 +++--- 6 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/agents/pi-embedded-runner/run/attempt.model-diagnostic-events.test.ts b/src/agents/pi-embedded-runner/run/attempt.model-diagnostic-events.test.ts index 90490d8797b..212bc600da9 100644 --- a/src/agents/pi-embedded-runner/run/attempt.model-diagnostic-events.test.ts +++ b/src/agents/pi-embedded-runner/run/attempt.model-diagnostic-events.test.ts @@ -395,7 +395,7 @@ describe("wrapStreamFnWithDiagnosticModelCallEvents", () => { "model.call.started", "model.call.completed", ]); - const startedEvent = requireRecord(started.mock.calls[0]?.[0], "started hook event"); + const startedEvent = requireRecord(started.mock.calls.at(0)?.[0], "started hook event"); expect(startedEvent.runId).toBe("run-1"); expect(startedEvent.callId).toBe("call-hook"); expect(startedEvent.sessionKey).toBe("session-key"); @@ -404,20 +404,20 @@ describe("wrapStreamFnWithDiagnosticModelCallEvents", () => { expect(startedEvent.model).toBe("gpt-5.4"); expect(startedEvent.api).toBe("openai-responses"); expect(startedEvent.transport).toBe("http"); - const startedCtx = requireRecord(started.mock.calls[0]?.[1], "started hook context"); + const startedCtx = requireRecord(started.mock.calls.at(0)?.[1], "started hook context"); expect(startedCtx.runId).toBe("run-1"); expect(startedCtx.sessionKey).toBe("session-key"); expect(startedCtx.sessionId).toBe("session-id"); expect(startedCtx.modelProviderId).toBe("openai"); expect(startedCtx.modelId).toBe("gpt-5.4"); - const endedEvent = requireRecord(ended.mock.calls[0]?.[0], "ended hook event"); + const endedEvent = requireRecord(ended.mock.calls.at(0)?.[0], "ended hook event"); expect(endedEvent.runId).toBe("run-1"); expect(endedEvent.callId).toBe("call-hook"); expect(endedEvent.outcome).toBe("completed"); expectNumberField(endedEvent, "durationMs"); expectNumberField(endedEvent, "responseStreamBytes"); expectNumberField(endedEvent, "timeToFirstByteMs"); - const endedCtx = requireRecord(ended.mock.calls[0]?.[1], "ended hook context"); + const endedCtx = requireRecord(ended.mock.calls.at(0)?.[1], "ended hook context"); expect(endedCtx.runId).toBe("run-1"); expect(Object.isFrozen(startedEvent)).toBe(true); expect(Object.isFrozen(startedCtx)).toBe(true); diff --git a/src/agents/session-file-repair.test.ts b/src/agents/session-file-repair.test.ts index bc7df346f2f..2066e5da4ec 100644 --- a/src/agents/session-file-repair.test.ts +++ b/src/agents/session-file-repair.test.ts @@ -93,7 +93,7 @@ describe("repairSessionFileIfNeeded", () => { expect(result.repaired).toBe(false); expect(result.reason).toBe("invalid session header"); expect(warn).toHaveBeenCalledTimes(1); - expect(warn.mock.calls[0]?.[0]).toContain("invalid session header"); + expect(warn.mock.calls.at(0)?.[0]).toContain("invalid session header"); }); it("returns a detailed reason when read errors are not ENOENT", async () => { @@ -145,7 +145,7 @@ describe("repairSessionFileIfNeeded", () => { expect(result.rewrittenAssistantMessages).toBe(1); await expect(fs.readFile(requireBackupPath(result), "utf-8")).resolves.toBe(original); expect(debug).toHaveBeenCalledTimes(1); - const debugMessage = debug.mock.calls[0]?.[0] as string; + const debugMessage = debug.mock.calls.at(0)?.[0] as string; expect(debugMessage).toContain("rewrote 1 assistant message(s)"); expect(debugMessage).not.toContain("dropped"); @@ -182,7 +182,7 @@ describe("repairSessionFileIfNeeded", () => { expect(result.repaired).toBe(true); expect(result.rewrittenUserMessages).toBe(1); expect(result.droppedBlankUserMessages).toBe(0); - expect(debug.mock.calls[0]?.[0]).toContain("rewrote 1 user message(s)"); + expect(debug.mock.calls.at(0)?.[0]).toContain("rewrote 1 user message(s)"); const repaired = await fs.readFile(file, "utf-8"); const repairedLines = repaired.trim().split("\n"); @@ -279,7 +279,7 @@ describe("repairSessionFileIfNeeded", () => { expect(result.repaired).toBe(true); expect(result.droppedLines).toBe(1); expect(result.rewrittenAssistantMessages).toBe(1); - const debugMessage = debug.mock.calls[0]?.[0] as string; + const debugMessage = debug.mock.calls.at(0)?.[0] as string; expect(debugMessage).toContain("dropped 1 malformed line(s)"); expect(debugMessage).toContain("rewrote 1 assistant message(s)"); }); diff --git a/src/agents/skills-install-fallback.test.ts b/src/agents/skills-install-fallback.test.ts index 662e203c000..3421e9e2556 100644 --- a/src/agents/skills-install-fallback.test.ts +++ b/src/agents/skills-install-fallback.test.ts @@ -141,7 +141,7 @@ describe("skills-install fallback edge cases", () => { expect(result.ok, testCase.label).toBe(false); testCase.assert(result); - const sudoCall = runCommandWithTimeoutMock.mock.calls[0] as + const sudoCall = runCommandWithTimeoutMock.mock.calls.at(0) as | [string[], { timeoutMs?: number }] | undefined; expect(sudoCall?.[0], testCase.label).toEqual(["sudo", "-n", "true"]); @@ -205,10 +205,10 @@ describe("skills-install fallback edge cases", () => { }); expect(result.ok).toBe(true); - const brewInstallCall = runCommandWithTimeoutMock.mock.calls[0] as + const brewInstallCall = runCommandWithTimeoutMock.mock.calls.at(0) as | [string[], { timeoutMs?: number }] | undefined; - const brewPrefixCall = runCommandWithTimeoutMock.mock.calls[1] as + const brewPrefixCall = runCommandWithTimeoutMock.mock.calls.at(1) as | [string[], { timeoutMs?: number }] | undefined; expect(brewInstallCall?.[0]).toEqual(["/safe/homebrew/bin/brew", "install", "go"]); @@ -257,7 +257,7 @@ describe("skills-install fallback edge cases", () => { }); expect(result.ok).toBe(true); - const firstCall = runCommandWithTimeoutMock.mock.calls[0] as + const firstCall = runCommandWithTimeoutMock.mock.calls.at(0) as | [string[], { timeoutMs?: number; env?: Record }] | undefined; expect(firstCall?.[0]).toEqual(["uv", "tool", "install", "example-package"]); diff --git a/src/agents/subagent-announce.test.ts b/src/agents/subagent-announce.test.ts index 8749f84ee72..1ba18a08337 100644 --- a/src/agents/subagent-announce.test.ts +++ b/src/agents/subagent-announce.test.ts @@ -369,7 +369,7 @@ describe("subagent announce seam flow", () => { }); expect(didAnnounce).toBe(true); - const queuedCall = queueEmbeddedPiMessageWithOutcomeMock.mock.calls[0]; + const queuedCall = queueEmbeddedPiMessageWithOutcomeMock.mock.calls.at(0); expect(queuedCall?.[0]).toBe("session-origin-provider-steer"); expect(queuedCall?.[1]).toContain("[Internal task completion event]"); expect(queuedCall?.[1]).toContain("task: do thing"); @@ -402,7 +402,7 @@ describe("subagent announce seam flow", () => { expect(didAnnounce).toBe(true); expect(agentSpy).toHaveBeenCalledTimes(1); - const agentCall = agentSpy.mock.calls[0]?.[0]; + const agentCall = agentSpy.mock.calls.at(0)?.[0]; expect(agentCall?.method).toBe("agent"); expect(agentCall?.params?.sessionKey).toBe("agent:main:main"); expect(agentCall?.params?.deliver).toBe(false); @@ -435,7 +435,7 @@ describe("subagent announce seam flow", () => { expect(didAnnounce).toBe(true); expect(agentSpy).toHaveBeenCalledTimes(1); - const call = agentSpy.mock.calls[0]?.[0]; + const call = agentSpy.mock.calls.at(0)?.[0]; const params = call?.params ?? {}; expect(params.sessionKey).toBe("agent:main:subagent:orchestrator"); expect(params.deliver).toBe(false); @@ -476,7 +476,7 @@ describe("subagent announce seam flow", () => { expect(didAnnounce).toBe(true); expect(agentSpy).toHaveBeenCalledTimes(1); - const agentCall = agentSpy.mock.calls[0]?.[0]; + const agentCall = agentSpy.mock.calls.at(0)?.[0]; expect(agentCall?.params?.deliver).toBe(true); expect(agentCall?.params?.channel).toBe("telegram"); expect(agentCall?.params?.accountId).toBe("bot-123"); diff --git a/src/agents/subagent-orphan-recovery.test.ts b/src/agents/subagent-orphan-recovery.test.ts index 97cee29def6..0569502da54 100644 --- a/src/agents/subagent-orphan-recovery.test.ts +++ b/src/agents/subagent-orphan-recovery.test.ts @@ -91,7 +91,7 @@ async function expectSkippedRecovery(store: ReturnType { // Should have called callGateway to resume the session expect(gateway.callGateway).toHaveBeenCalledOnce(); - const callArgs = vi.mocked(gateway.callGateway).mock.calls[0]; + const callArgs = vi.mocked(gateway.callGateway).mock.calls.at(0); + if (callArgs === undefined) { + throw new Error("expected gateway resume call"); + } const opts = callArgs[0]; expect(opts.method).toBe("agent"); const params = opts.params as Record; @@ -369,7 +372,14 @@ describe("subagent-orphan-recovery", () => { getActiveRuns: () => createActiveRuns(createTestRunRecord()), }); - const [, updater] = vi.mocked(sessions.updateSessionStore).mock.calls[0]; + const updateCall = vi.mocked(sessions.updateSessionStore).mock.calls.at(0); + if (updateCall === undefined) { + throw new Error("expected update session store call"); + } + const updater = updateCall[1]; + if (typeof updater !== "function") { + throw new Error("expected update session store callback"); + } const mockStore: ReturnType = { "agent:main:subagent:test-session-1": { sessionId: "session-abc", @@ -414,7 +424,14 @@ describe("subagent-orphan-recovery", () => { expect(gateway.callGateway).not.toHaveBeenCalled(); expect(sessions.updateSessionStore).toHaveBeenCalledOnce(); - const [, updater] = vi.mocked(sessions.updateSessionStore).mock.calls[0]; + const updateCall = vi.mocked(sessions.updateSessionStore).mock.calls.at(0); + if (updateCall === undefined) { + throw new Error("expected update session store call"); + } + const updater = updateCall[1]; + if (typeof updater !== "function") { + throw new Error("expected update session store callback"); + } const mockStore: ReturnType = { "agent:main:subagent:test-session-1": { sessionId: "session-abc", diff --git a/src/agents/subagent-registry.steer-restart.test.ts b/src/agents/subagent-registry.steer-restart.test.ts index 8f3d679beff..d1ca43c4016 100644 --- a/src/agents/subagent-registry.steer-restart.test.ts +++ b/src/agents/subagent-registry.steer-restart.test.ts @@ -103,7 +103,7 @@ function requireSubagentEndedHookCall(runId: string): { } function requireSessionLifecycleEventCall(label: string): Record { - const call = emitSessionLifecycleEventMock.mock.calls[0]; + const call = emitSessionLifecycleEventMock.mock.calls.at(0); if (!call) { throw new Error(`expected ${label}`); } @@ -332,7 +332,7 @@ describe("subagent registry steer restarts", () => { expect(hookCall.event.runId).toBe("run-new"); expect(hookCall.ctx.runId).toBe("run-new"); - const announce = (announceSpy.mock.calls[0]?.[0] ?? {}) as { childRunId?: string }; + const announce = (announceSpy.mock.calls.at(0)?.[0] ?? {}) as { childRunId?: string }; expect(announce.childRunId).toBe("run-new"); } }); @@ -572,7 +572,7 @@ describe("subagent registry steer restarts", () => { await flushAnnounce(); expect(announceSpy).toHaveBeenCalledTimes(1); - const announce = (announceSpy.mock.calls[0]?.[0] ?? {}) as { childRunId?: string }; + const announce = (announceSpy.mock.calls.at(0)?.[0] ?? {}) as { childRunId?: string }; expect(announce.childRunId).toBe("run-failed-restart"); }); @@ -668,7 +668,7 @@ describe("subagent registry steer restarts", () => { await flushAnnounce(); expect(announceSpy).toHaveBeenCalledTimes(1); - const announce = (announceSpy.mock.calls[0]?.[0] ?? {}) as { childRunId?: string }; + const announce = (announceSpy.mock.calls.at(0)?.[0] ?? {}) as { childRunId?: string }; expect(announce.childRunId).toBe("run-kill-race"); const run = listMainRuns()[0];