From 74dc2a6830be3ec29bc535a38afeaedb35d1ceab Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 10 May 2026 06:22:55 +0100 Subject: [PATCH] test: clear acp manager broad matchers --- src/acp/control-plane/manager.test.ts | 537 +++++++++++++------------- 1 file changed, 262 insertions(+), 275 deletions(-) diff --git a/src/acp/control-plane/manager.test.ts b/src/acp/control-plane/manager.test.ts index 4cc83654ac7..39cc5432da3 100644 --- a/src/acp/control-plane/manager.test.ts +++ b/src/acp/control-plane/manager.test.ts @@ -97,6 +97,60 @@ function createDeferred(): { promise: Promise; resolve: () => void } { return { promise, resolve }; } +function expectRecordFields(record: unknown, expected: Record) { + expect(record).toBeDefined(); + const actual = record as Record; + for (const [key, value] of Object.entries(expected)) { + expect(actual[key]).toEqual(value); + } + return actual; +} + +async function expectRejectedRecord(promise: Promise, expected: Record) { + await promise.then( + () => { + throw new Error("Expected promise to reject."); + }, + (error) => { + expectRecordFields(error, expected); + }, + ); +} + +function mockCallArg(mock: ReturnType, callIndex = 0): Record { + const call = mock.mock.calls[callIndex]; + if (!call) { + throw new Error(`Expected mock call ${callIndex}`); + } + return call[0] as Record; +} + +function mockCallArgs(mock: ReturnType): Array> { + return mock.mock.calls.map((call) => call[0] as Record); +} + +function findMockCallFields(mock: ReturnType, expected: Record) { + return mockCallArgs(mock).find((actual) => + Object.entries(expected).every(([key, value]) => Object.is(actual[key], value)), + ); +} + +function expectMockCallFields(mock: ReturnType, expected: Record) { + expect(findMockCallFields(mock, expected)).toBeDefined(); +} + +function expectNoMockCallFields(mock: ReturnType, expected: Record) { + expect(findMockCallFields(mock, expected)).toBeUndefined(); +} + +function requireTaskByRunId(runId: string) { + const task = findTaskByRunId(runId); + if (!task) { + throw new Error(`Expected task for run ${runId}`); + } + return task; +} + function createRuntime(): { runtime: AcpRuntime; ensureSession: ReturnType; @@ -295,18 +349,14 @@ describe("AcpSessionManager", () => { requestId: "r-main", }); - expect(hoisted.readAcpSessionEntryMock).toHaveBeenCalledWith( - expect.objectContaining({ - cfg, - sessionKey: "agent:main:main", - }), - ); - expect(runtimeState.ensureSession).toHaveBeenCalledWith( - expect.objectContaining({ - agent: "main", - sessionKey: "agent:main:main", - }), - ); + expectRecordFields(mockCallArg(hoisted.readAcpSessionEntryMock), { + cfg, + sessionKey: "agent:main:main", + }); + expectRecordFields(mockCallArg(runtimeState.ensureSession), { + agent: "main", + sessionKey: "agent:main:main", + }); }); it("tracks parented direct ACP turns in the task registry", async () => { @@ -387,7 +437,7 @@ describe("AcpSessionManager", () => { }); await flushMicrotasks(); - expect(findTaskByRunId("direct-parented-run")).toMatchObject({ + expectRecordFields(requireTaskByRunId("direct-parented-run"), { runtime: "acp", ownerKey: "agent:quant:telegram:quant:direct:822430204", scopeKind: "session", @@ -473,7 +523,7 @@ describe("AcpSessionManager", () => { }); await flushMicrotasks(); - expect(findTaskByRunId("direct-parented-korean-path-run")).toMatchObject({ + expectRecordFields(requireTaskByRunId("direct-parented-korean-path-run"), { runtime: "acp", ownerKey: "agent:quant:telegram:quant:direct:822430204", scopeKind: "session", @@ -618,7 +668,7 @@ describe("AcpSessionManager", () => { return; } expect(secondOutcome.error).toBeInstanceOf(AcpRuntimeError); - expect(secondOutcome.error).toMatchObject({ + expectRecordFields(secondOutcome.error, { code: "ACP_TURN_FAILED", message: "ACP operation aborted.", }); @@ -683,7 +733,7 @@ describe("AcpSessionManager", () => { await vi.advanceTimersByTimeAsync(3_500); - await expect(first).rejects.toMatchObject({ + await expectRejectedRecord(first, { code: "ACP_TURN_FAILED", message: "ACP turn timed out after 1s.", }); @@ -691,22 +741,17 @@ describe("AcpSessionManager", () => { expect(runtimeState.ensureSession).toHaveBeenCalledTimes(1); expect(runtimeState.runTurn).toHaveBeenCalledTimes(2); - expect(runtimeState.cancel).toHaveBeenCalledWith( - expect.objectContaining({ - reason: "turn-timeout", - }), - ); + expectRecordFields(mockCallArg(runtimeState.cancel), { + reason: "turn-timeout", + }); expect(runtimeState.close).not.toHaveBeenCalled(); - expect(manager.getObservabilitySnapshot(cfg)).toMatchObject({ - runtimeCache: { - activeSessions: 1, - }, - turns: { - active: 0, - queueDepth: 0, - completed: 1, - failed: 1, - }, + const snapshot = manager.getObservabilitySnapshot(cfg); + expect(snapshot.runtimeCache.activeSessions).toBe(1); + expectRecordFields(snapshot.turns, { + active: 0, + queueDepth: 0, + completed: 1, + failed: 1, }); const states = extractStatesFromUpserts(); @@ -778,13 +823,13 @@ describe("AcpSessionManager", () => { await vi.advanceTimersByTimeAsync(4_500); - await expect(first).rejects.toMatchObject({ + await expectRejectedRecord(first, { code: "ACP_TURN_FAILED", message: "ACP turn timed out after 1s.", }); expect(manager.getObservabilitySnapshot(cfg).runtimeCache.activeSessions).toBe(1); - await expect( + await expectRejectedRecord( manager.runTurn({ cfg, sessionKey: "agent:codex:acp:session-b", @@ -792,10 +837,11 @@ describe("AcpSessionManager", () => { mode: "prompt", requestId: "r2", }), - ).rejects.toMatchObject({ - code: "ACP_SESSION_INIT_FAILED", - message: expect.stringContaining("max concurrent sessions"), - }); + { + code: "ACP_SESSION_INIT_FAILED", + message: "ACP max concurrent sessions reached (1/1).", + }, + ); expect(runtimeState.ensureSession).toHaveBeenCalledTimes(1); } finally { vi.useRealTimers(); @@ -1080,13 +1126,11 @@ describe("AcpSessionManager", () => { requestId: "r-binding-restart", }); - expect(runtimeState.ensureSession).toHaveBeenCalledWith( - expect.objectContaining({ - sessionKey, - agent: "codex", - resumeSessionId: "acpx-sid-1", - }), - ); + expectRecordFields(mockCallArg(runtimeState.ensureSession), { + sessionKey, + agent: "codex", + resumeSessionId: "acpx-sid-1", + }); }); it("prefers the persisted agent session id when reopening an ACP runtime after restart", async () => { @@ -1125,13 +1169,11 @@ describe("AcpSessionManager", () => { requestId: "r-binding-restart-gemini", }); - expect(runtimeState.ensureSession).toHaveBeenCalledWith( - expect.objectContaining({ - sessionKey, - agent: "gemini", - resumeSessionId: "gemini-sid-1", - }), - ); + expectRecordFields(mockCallArg(runtimeState.ensureSession), { + sessionKey, + agent: "gemini", + resumeSessionId: "gemini-sid-1", + }); }); it("passes persisted cwd runtime options into ensureSession after restart", async () => { @@ -1165,12 +1207,10 @@ describe("AcpSessionManager", () => { requestId: "r-binding-restart-cwd", }); - expect(runtimeState.ensureSession).toHaveBeenCalledWith( - expect.objectContaining({ - sessionKey, - cwd: "/workspace/project", - }), - ); + expectRecordFields(mockCallArg(runtimeState.ensureSession), { + sessionKey, + cwd: "/workspace/project", + }); }); it("passes persisted model runtime options into ensureSession after restart", async () => { @@ -1203,12 +1243,10 @@ describe("AcpSessionManager", () => { requestId: "r-binding-restart-model", }); - expect(runtimeState.ensureSession).toHaveBeenCalledWith( - expect.objectContaining({ - sessionKey, - model: "openai-codex/gpt-5.4", - }), - ); + expectRecordFields(mockCallArg(runtimeState.ensureSession), { + sessionKey, + model: "openai-codex/gpt-5.4", + }); }); it("passes persisted thinking runtime options into ensureSession after restart", async () => { @@ -1241,12 +1279,10 @@ describe("AcpSessionManager", () => { requestId: "r-binding-restart-thinking", }); - expect(runtimeState.ensureSession).toHaveBeenCalledWith( - expect.objectContaining({ - sessionKey, - thinking: "high", - }), - ); + expectRecordFields(mockCallArg(runtimeState.ensureSession), { + sessionKey, + thinking: "high", + }); }); it("does not resume persisted ACP identity for oneshot sessions after restart", async () => { @@ -1288,7 +1324,7 @@ describe("AcpSessionManager", () => { const ensureInput = runtimeState.ensureSession.mock.calls[0]?.[0] as | { resumeSessionId?: string; mode?: string } | undefined; - expect(ensureInput).toMatchObject({ + expectRecordFields(ensureInput, { sessionKey, agent: "codex", mode: "oneshot", @@ -1375,7 +1411,7 @@ describe("AcpSessionManager", () => { }); expect(runtimeState.ensureSession).toHaveBeenCalledTimes(2); - expect(runtimeState.ensureSession.mock.calls[0]?.[0]).toMatchObject({ + expectRecordFields(mockCallArg(runtimeState.ensureSession), { sessionKey, agent: "codex", resumeSessionId: "agent-sid-stale", @@ -1426,7 +1462,7 @@ describe("AcpSessionManager", () => { requestId: "r1", }); - await expect( + await expectRejectedRecord( manager.runTurn({ cfg: limitedCfg, sessionKey: "agent:codex:acp:session-b", @@ -1434,10 +1470,11 @@ describe("AcpSessionManager", () => { mode: "prompt", requestId: "r2", }), - ).rejects.toMatchObject({ - code: "ACP_SESSION_INIT_FAILED", - message: expect.stringContaining("max concurrent sessions"), - }); + { + code: "ACP_SESSION_INIT_FAILED", + message: "ACP max concurrent sessions reached (1/1).", + }, + ); expect(runtimeState.ensureSession).toHaveBeenCalledTimes(1); }); @@ -1467,17 +1504,18 @@ describe("AcpSessionManager", () => { mode: "persistent", }); - await expect( + await expectRejectedRecord( manager.initializeSession({ cfg: limitedCfg, sessionKey: "agent:codex:acp:session-b", agent: "codex", mode: "persistent", }), - ).rejects.toMatchObject({ - code: "ACP_SESSION_INIT_FAILED", - message: expect.stringContaining("max concurrent sessions"), - }); + { + code: "ACP_SESSION_INIT_FAILED", + message: "ACP max concurrent sessions reached (1/1).", + }, + ); expect(runtimeState.ensureSession).toHaveBeenCalledTimes(1); }); @@ -1514,13 +1552,11 @@ describe("AcpSessionManager", () => { model: "openai-codex/gpt-5.4", thinking: "high", }); - expect(runtimeState.ensureSession).toHaveBeenCalledWith( - expect.objectContaining({ - sessionKey: "agent:codex:acp:session-a", - model: "openai-codex/gpt-5.4", - thinking: "high", - }), - ); + expectRecordFields(mockCallArg(runtimeState.ensureSession), { + sessionKey: "agent:codex:acp:session-a", + model: "openai-codex/gpt-5.4", + thinking: "high", + }); }); it("preserves runtimeOptions cwd when initializeSession cwd is omitted", async () => { @@ -1551,12 +1587,10 @@ describe("AcpSessionManager", () => { }, }); - expect(runtimeState.ensureSession).toHaveBeenCalledWith( - expect.objectContaining({ - sessionKey: "agent:codex:acp:session-cwd-runtime-options", - cwd: "/workspace/from-runtime-options", - }), - ); + expectRecordFields(mockCallArg(runtimeState.ensureSession), { + sessionKey: "agent:codex:acp:session-cwd-runtime-options", + cwd: "/workspace/from-runtime-options", + }); expect(extractRuntimeOptionsFromUpserts()).toContainEqual({ cwd: "/workspace/from-runtime-options", }); @@ -1760,7 +1794,7 @@ describe("AcpSessionManager", () => { expect(result.runtimeClosed).toBe(true); expect(entry.acp?.state).toBe("idle"); expect(entry.acp?.lastError).toBeUndefined(); - expect(entry.acp?.identity).toMatchObject({ + expectRecordFields(entry.acp?.identity, { state: "pending", acpxRecordId: sessionKey, source: "status", @@ -1833,11 +1867,9 @@ describe("AcpSessionManager", () => { expect(runtimeState.prepareFreshSession).toHaveBeenCalledWith({ sessionKey, }); - expect(runtimeState.ensureSession).toHaveBeenCalledWith( - expect.objectContaining({ - sessionKey, - }), - ); + expectRecordFields(mockCallArg(runtimeState.ensureSession), { + sessionKey, + }); expect(runtimeState.prepareFreshSession.mock.invocationCallOrder[0]).toBeLessThan( runtimeState.ensureSession.mock.invocationCallOrder[0], ); @@ -1898,7 +1930,7 @@ describe("AcpSessionManager", () => { }); expect(runtimeState.ensureSession).not.toHaveBeenCalled(); expect(runtimeState.close).not.toHaveBeenCalled(); - expect(entry.acp?.identity).toMatchObject({ + expectRecordFields(entry.acp?.identity, { state: "pending", acpxRecordId: sessionKey, source: "ensure", @@ -1956,14 +1988,13 @@ describe("AcpSessionManager", () => { }); expect(runtimeState.ensureSession).toHaveBeenCalledTimes(2); - expect(runtimeState.close).toHaveBeenCalledWith( - expect.objectContaining({ - reason: "idle-evicted", - handle: expect.objectContaining({ - sessionKey: "agent:codex:acp:session-a", - }), - }), - ); + const closeInput = mockCallArg(runtimeState.close); + expectRecordFields(closeInput, { + reason: "idle-evicted", + }); + expectRecordFields(closeInput.handle, { + sessionKey: "agent:codex:acp:session-a", + }); } finally { vi.useRealTimers(); } @@ -2001,7 +2032,7 @@ describe("AcpSessionManager", () => { mode: "prompt", requestId: "ok", }); - await expect( + await expectRejectedRecord( manager.runTurn({ cfg: baseCfg, sessionKey: "agent:codex:acp:session-1", @@ -2009,9 +2040,8 @@ describe("AcpSessionManager", () => { mode: "prompt", requestId: "fail", }), - ).rejects.toMatchObject({ - code: "ACP_TURN_FAILED", - }); + { code: "ACP_TURN_FAILED" }, + ); const snapshot = manager.getObservabilitySnapshot(baseCfg); expect(snapshot.turns.completed).toBe(1); @@ -2038,14 +2068,13 @@ describe("AcpSessionManager", () => { mode: "persistent", }), ).rejects.toThrow("disk full"); - expect(runtimeState.close).toHaveBeenCalledWith( - expect.objectContaining({ - reason: "init-meta-failed", - handle: expect.objectContaining({ - sessionKey: "agent:codex:acp:session-1", - }), - }), - ); + const closeInput = mockCallArg(runtimeState.close); + expectRecordFields(closeInput, { + reason: "init-meta-failed", + }); + expectRecordFields(closeInput.handle, { + sessionKey: "agent:codex:acp:session-1", + }); }); it("preempts an active turn on cancel and returns to idle state", async () => { @@ -2096,11 +2125,9 @@ describe("AcpSessionManager", () => { await runPromise; expect(runtimeState.cancel).toHaveBeenCalledTimes(1); - expect(runtimeState.cancel).toHaveBeenCalledWith( - expect.objectContaining({ - reason: "manual-cancel", - }), - ); + expectRecordFields(mockCallArg(runtimeState.cancel), { + reason: "manual-cancel", + }); const states = extractStatesFromUpserts(); expect(states).toContain("running"); expect(states).toContain("idle"); @@ -2167,7 +2194,7 @@ describe("AcpSessionManager", () => { }); const manager = new AcpSessionManager(); - await expect( + await expectRejectedRecord( manager.runTurn({ cfg: baseCfg, sessionKey: "agent:codex:acp:session-1", @@ -2175,10 +2202,11 @@ describe("AcpSessionManager", () => { mode: "prompt", requestId: "run-1", }), - ).rejects.toMatchObject({ - code: "ACP_TURN_FAILED", - message: "acpx exited with code 1", - }); + { + code: "ACP_TURN_FAILED", + message: "acpx exited with code 1", + }, + ); const states = extractStatesFromUpserts(); expect(states).toContain("running"); @@ -2206,7 +2234,7 @@ describe("AcpSessionManager", () => { }); const manager = new AcpSessionManager(); - await expect( + await expectRejectedRecord( manager.runTurn({ cfg: baseCfg, sessionKey: "agent:codex:acp:session-1", @@ -2214,10 +2242,11 @@ describe("AcpSessionManager", () => { mode: "prompt", requestId: "run-1", }), - ).rejects.toMatchObject({ - code: "ACP_TURN_FAILED", - message: "ACP turn ended without a terminal done event.", - }); + { + code: "ACP_TURN_FAILED", + message: "ACP turn ended without a terminal done event.", + }, + ); const states = extractStatesFromUpserts(); expect(states).toContain("running"); @@ -2241,7 +2270,7 @@ describe("AcpSessionManager", () => { }); const manager = new AcpSessionManager(); - await expect( + await expectRejectedRecord( manager.runTurn({ cfg: baseCfg, sessionKey: "agent:codex:acp:session-1", @@ -2249,10 +2278,11 @@ describe("AcpSessionManager", () => { mode: "prompt", requestId: "run-1", }), - ).rejects.toMatchObject({ - code: "ACP_SESSION_INIT_FAILED", - message: "acpx exited with code 1", - }); + { + code: "ACP_SESSION_INIT_FAILED", + message: "acpx exited with code 1", + }, + ); const states = extractStatesFromUpserts(); expect(states).not.toContain("running"); @@ -2395,7 +2425,7 @@ describe("AcpSessionManager", () => { sessionKey, }); expect(runtimeState.ensureSession).toHaveBeenCalledTimes(2); - expect(runtimeState.ensureSession.mock.calls[0]?.[0]).toMatchObject({ + expectRecordFields(mockCallArg(runtimeState.ensureSession), { sessionKey, resumeSessionId: "acpx-sid-stale", }); @@ -2430,11 +2460,9 @@ describe("AcpSessionManager", () => { runtimeMode: "plan", }); - expect(runtimeState.setMode).toHaveBeenCalledWith( - expect.objectContaining({ - mode: "plan", - }), - ); + expectMockCallFields(runtimeState.setMode, { + mode: "plan", + }); expect(options.runtimeMode).toBe("plan"); const persistedRuntimeModes = extractRuntimeOptionsFromUpserts().map( (entry) => entry?.runtimeMode, @@ -2499,11 +2527,9 @@ describe("AcpSessionManager", () => { requestId: "run-1", }); - expect(runtimeState.setMode).toHaveBeenCalledWith( - expect.objectContaining({ - mode: "plan", - }), - ); + expectMockCallFields(runtimeState.setMode, { + mode: "plan", + }); }); it("reconciles persisted ACP session identifiers from runtime status after a turn", async () => { @@ -2632,7 +2658,7 @@ describe("AcpSessionManager", () => { mode: "oneshot", }); - expect(currentMeta?.identity).toMatchObject({ + expectRecordFields(currentMeta?.identity, { state: "pending", acpxSessionId: "acpx-oneshot", source: "ensure", @@ -2647,14 +2673,15 @@ describe("AcpSessionManager", () => { }); expect(runtimeState.getStatus).toHaveBeenCalledTimes(2); - expect(runtimeState.close).toHaveBeenCalledWith({ - handle: expect.objectContaining({ - backendSessionId: "acpx-oneshot", - agentSessionId: "agent-oneshot", - }), + const closeInput = mockCallArg(runtimeState.close); + expectRecordFields(closeInput, { reason: "oneshot-complete", }); - expect(currentMeta?.identity).toMatchObject({ + expectRecordFields(closeInput.handle, { + backendSessionId: "acpx-oneshot", + agentSessionId: "agent-oneshot", + }); + expectRecordFields(currentMeta?.identity, { state: "resolved", acpxSessionId: "acpx-oneshot", agentSessionId: "agent-oneshot", @@ -2974,35 +3001,25 @@ describe("AcpSessionManager", () => { requestId: "run-1", }); - expect(runtimeState.setMode).toHaveBeenCalledWith( - expect.objectContaining({ - mode: "plan", - }), - ); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "model", - value: "openai-codex/gpt-5.4", - }), - ); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "thinking", - value: "high", - }), - ); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "approval_policy", - value: "strict", - }), - ); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "timeout", - value: "120", - }), - ); + expectMockCallFields(runtimeState.setMode, { + mode: "plan", + }); + expectMockCallFields(runtimeState.setConfigOption, { + key: "model", + value: "openai-codex/gpt-5.4", + }); + expectMockCallFields(runtimeState.setConfigOption, { + key: "thinking", + value: "high", + }); + expectMockCallFields(runtimeState.setConfigOption, { + key: "approval_policy", + value: "strict", + }); + expectMockCallFields(runtimeState.setConfigOption, { + key: "timeout", + value: "120", + }); }); it("maps persisted thinking runtime options to advertised effort config keys before running turns", async () => { @@ -3035,17 +3052,13 @@ describe("AcpSessionManager", () => { requestId: "run-1", }); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "effort", - value: "high", - }), - ); - expect(runtimeState.setConfigOption).not.toHaveBeenCalledWith( - expect.objectContaining({ - key: "thinking", - }), - ); + expectMockCallFields(runtimeState.setConfigOption, { + key: "effort", + value: "high", + }); + expectNoMockCallFields(runtimeState.setConfigOption, { + key: "thinking", + }); }); it("maps persisted runtime options to backend-advertised aliases before running turns", async () => { @@ -3081,39 +3094,27 @@ describe("AcpSessionManager", () => { requestId: "run-1", }); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "thought_level", - value: "high", - }), - ); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "permissions", - value: "strict", - }), - ); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "timeout_seconds", - value: "120", - }), - ); - expect(runtimeState.setConfigOption).not.toHaveBeenCalledWith( - expect.objectContaining({ - key: "thinking", - }), - ); - expect(runtimeState.setConfigOption).not.toHaveBeenCalledWith( - expect.objectContaining({ - key: "approval_policy", - }), - ); - expect(runtimeState.setConfigOption).not.toHaveBeenCalledWith( - expect.objectContaining({ - key: "timeout", - }), - ); + expectMockCallFields(runtimeState.setConfigOption, { + key: "thought_level", + value: "high", + }); + expectMockCallFields(runtimeState.setConfigOption, { + key: "permissions", + value: "strict", + }); + expectMockCallFields(runtimeState.setConfigOption, { + key: "timeout_seconds", + value: "120", + }); + expectNoMockCallFields(runtimeState.setConfigOption, { + key: "thinking", + }); + expectNoMockCallFields(runtimeState.setConfigOption, { + key: "approval_policy", + }); + expectNoMockCallFields(runtimeState.setConfigOption, { + key: "timeout", + }); }); it("re-ensures runtime handles after cwd runtime option updates", async () => { @@ -3180,13 +3181,10 @@ describe("AcpSessionManager", () => { }); expect(runtimeState.ensureSession).toHaveBeenCalledTimes(2); - expect(runtimeState.ensureSession).toHaveBeenNthCalledWith( - 2, - expect.objectContaining({ - sessionKey, - cwd: "/workspace/next", - }), - ); + expectRecordFields(mockCallArg(runtimeState.ensureSession, 1), { + sessionKey, + cwd: "/workspace/next", + }); }); it("returns unsupported-control error when backend does not support set_config_option", async () => { @@ -3209,16 +3207,15 @@ describe("AcpSessionManager", () => { }); const manager = new AcpSessionManager(); - await expect( + await expectRejectedRecord( manager.setSessionConfigOption({ cfg: baseCfg, sessionKey: "agent:codex:acp:session-1", key: "model", value: "gpt-5.4", }), - ).rejects.toMatchObject({ - code: "ACP_BACKEND_UNSUPPORTED_CONTROL", - }); + { code: "ACP_BACKEND_UNSUPPORTED_CONTROL" }, + ); }); it("maps explicit thinking config updates to advertised effort keys", async () => { @@ -3245,12 +3242,10 @@ describe("AcpSessionManager", () => { value: "high", }); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "effort", - value: "high", - }), - ); + expectMockCallFields(runtimeState.setConfigOption, { + key: "effort", + value: "high", + }); expect(nextOptions).toEqual({ thinking: "high" }); }); @@ -3284,12 +3279,10 @@ describe("AcpSessionManager", () => { }); expect(runtimeState.getStatus).toHaveBeenCalled(); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "effort", - value: "high", - }), - ); + expectMockCallFields(runtimeState.setConfigOption, { + key: "effort", + value: "high", + }); expect(nextOptions).toEqual({ thinking: "high" }); }); @@ -3317,12 +3310,10 @@ describe("AcpSessionManager", () => { value: "high", }); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "effort", - value: "high", - }), - ); + expectMockCallFields(runtimeState.setConfigOption, { + key: "effort", + value: "high", + }); expect(nextOptions).toEqual({ thinking: "high" }); }); @@ -3350,12 +3341,10 @@ describe("AcpSessionManager", () => { value: "strict", }); - expect(runtimeState.setConfigOption).toHaveBeenCalledWith( - expect.objectContaining({ - key: "permission_mode", - value: "strict", - }), - ); + expectMockCallFields(runtimeState.setConfigOption, { + key: "permission_mode", + value: "strict", + }); expect(nextOptions).toEqual({ permissionProfile: "strict" }); }); @@ -3372,27 +3361,25 @@ describe("AcpSessionManager", () => { }); const manager = new AcpSessionManager(); - await expect( + await expectRejectedRecord( manager.setSessionConfigOption({ cfg: baseCfg, sessionKey: "agent:codex:acp:session-1", key: "timeout", value: "not-a-number", }), - ).rejects.toMatchObject({ - code: "ACP_INVALID_RUNTIME_OPTION", - }); + { code: "ACP_INVALID_RUNTIME_OPTION" }, + ); expect(runtimeState.setConfigOption).not.toHaveBeenCalled(); - await expect( + await expectRejectedRecord( manager.updateSessionRuntimeOptions({ cfg: baseCfg, sessionKey: "agent:codex:acp:session-1", patch: { cwd: "relative/path" }, }), - ).rejects.toMatchObject({ - code: "ACP_INVALID_RUNTIME_OPTION", - }); + { code: "ACP_INVALID_RUNTIME_OPTION" }, + ); }); it("can close and clear metadata when backend is unavailable", async () => {