From f3ee9e26f946e8294efbd206e6c010e80bdcc69b Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 10 May 2026 16:39:05 +0100 Subject: [PATCH] test: clear broad mock helper lint --- .../run-attempt.context-engine.test.ts | 7 ++-- .../discord/src/monitor/provider.test.ts | 4 ++- extensions/googlechat/src/channel.test.ts | 13 +++++-- extensions/irc/src/inbound.behavior.test.ts | 6 ++-- extensions/line/src/bot-handlers.test.ts | 4 +-- extensions/line/src/setup-surface.test.ts | 4 ++- .../memory-core/src/dreaming-phases.test.ts | 2 +- extensions/memory-core/src/dreaming.test.ts | 2 +- .../src/inbound.behavior.test.ts | 4 ++- .../src/send.cfg-threading.test.ts | 2 +- extensions/slack/src/monitor/media.test.ts | 2 +- extensions/synology-chat/src/channel.test.ts | 2 +- extensions/telegram/src/webhook.test.ts | 4 ++- src/agents/harness/v2.test.ts | 16 ++++----- src/agents/tools/video-generate-tool.test.ts | 34 +++++++++++-------- src/wizard/setup.finalize.test.ts | 27 ++++++++------- 16 files changed, 80 insertions(+), 53 deletions(-) diff --git a/extensions/codex/src/app-server/run-attempt.context-engine.test.ts b/extensions/codex/src/app-server/run-attempt.context-engine.test.ts index 51c1da99da7..6392fd5a03d 100644 --- a/extensions/codex/src/app-server/run-attempt.context-engine.test.ts +++ b/extensions/codex/src/app-server/run-attempt.context-engine.test.ts @@ -206,7 +206,7 @@ function requireRecord(value: unknown, label: string): Record { return value as Record; } -function requireFirstCallArg(mock: unknown, label: string): T { +function requireFirstCallArg(mock: unknown, label: string, _type?: (value: T) => T): T { const call = (mock as MockCallReader).mock.calls.at(0); if (!call) { throw new Error(`expected ${label} to be called`); @@ -238,7 +238,7 @@ function expectRequestInputTextContains( expect( input.some((entry) => { const item = requireRecord(entry, "turn/start input entry"); - return item.type === "text" && String(item.text ?? "").includes(expected); + return item.type === "text" && typeof item.text === "string" && item.text.includes(expected); }), ).toBe(true); } @@ -297,7 +297,8 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => { expect(assembleParams.availableTools).toEqual(new Set()); const threadStartParams = requireRequestParams(harness, "thread/start"); - expect(String(threadStartParams.developerInstructions ?? "")).toContain( + const developerInstructions = threadStartParams.developerInstructions; + expect(typeof developerInstructions === "string" ? developerInstructions : "").toContain( "context-engine system", ); expectRequestInputTextContains(harness, "OpenClaw assembled context for this turn:"); diff --git a/extensions/discord/src/monitor/provider.test.ts b/extensions/discord/src/monitor/provider.test.ts index 6a3354d97e0..0ab42878b4f 100644 --- a/extensions/discord/src/monitor/provider.test.ts +++ b/extensions/discord/src/monitor/provider.test.ts @@ -105,7 +105,9 @@ function createConfigWithDiscordAccount(overrides: Record = {}) type MockCallReader = { mock: { calls: unknown[][] } }; function mockMessages(mock: unknown): string[] { - return (mock as MockCallReader).mock.calls.map((call) => String(call[0] ?? "")); + return (mock as MockCallReader).mock.calls.map((call) => + typeof call[0] === "string" ? call[0] : "", + ); } function expectMockLogContains(mock: unknown, expected: string): void { diff --git a/extensions/googlechat/src/channel.test.ts b/extensions/googlechat/src/channel.test.ts index cc605a9b9d4..df94ac0bc08 100644 --- a/extensions/googlechat/src/channel.test.ts +++ b/extensions/googlechat/src/channel.test.ts @@ -215,7 +215,12 @@ function setupRuntimeMediaMocks(params: { loadFileName: string; loadBytes: strin return { loadOutboundMediaFromUrl, fetchRemoteMedia }; } -function requireMockArg(mock: ReturnType, callIndex = 0, argIndex = 0): T { +function requireMockArg( + mock: ReturnType, + callIndex = 0, + argIndex = 0, + _type?: (value: T) => T, +): T { const call = mock.mock.calls[callIndex]; if (!call) { throw new Error(`expected mock call ${callIndex}`); @@ -223,7 +228,11 @@ function requireMockArg(mock: ReturnType, callIndex = 0, argInd return call[argIndex] as T; } -function requireMockArgs(mock: ReturnType, callIndex = 0): T { +function requireMockArgs( + mock: ReturnType, + callIndex = 0, + _type?: (value: T) => T, +): T { const call = mock.mock.calls[callIndex]; if (!call) { throw new Error(`expected mock call ${callIndex}`); diff --git a/extensions/irc/src/inbound.behavior.test.ts b/extensions/irc/src/inbound.behavior.test.ts index 933d9bf686b..4b2916b7798 100644 --- a/extensions/irc/src/inbound.behavior.test.ts +++ b/extensions/irc/src/inbound.behavior.test.ts @@ -129,7 +129,7 @@ describe("irc inbound behavior", () => { expect.stringContaining("Your IRC id: alice!ident@example.com"), undefined, ); - const replyMessages = sendReply.mock.calls.map((call) => String(call[1])); + const replyMessages = (sendReply.mock.calls as unknown[][]).map((call) => String(call[1])); expect(replyMessages.some((message) => message.includes("CODE"))).toBe(true); }); @@ -185,7 +185,9 @@ describe("irc inbound behavior", () => { sendReply: vi.fn(async () => {}), }); - const assembledRequest = coreRuntime.channel.turn.runAssembled.mock.calls[0]?.[0]; + const assembledRequest = ( + coreRuntime.channel.turn.runAssembled as unknown as { mock: { calls: unknown[][] } } + ).mock.calls[0]?.[0] as { replyPipeline?: unknown } | undefined; expect(assembledRequest?.replyPipeline).toEqual({}); }); }); diff --git a/extensions/line/src/bot-handlers.test.ts b/extensions/line/src/bot-handlers.test.ts index f6ba9c99c29..3710b6649f1 100644 --- a/extensions/line/src/bot-handlers.test.ts +++ b/extensions/line/src/bot-handlers.test.ts @@ -609,7 +609,7 @@ describe("handleLineWebhookEvents", () => { }); expect(processMessage).not.toHaveBeenCalled(); - const pairingRequest = upsertPairingRequestMock.mock.calls[0]?.[0] as + const pairingRequest = (upsertPairingRequestMock.mock.calls as unknown[][])[0]?.[0] as | { accountId?: string; channel?: string; id?: string } | undefined; expect(pairingRequest?.channel).toBe("line"); @@ -656,7 +656,7 @@ describe("handleLineWebhookEvents", () => { expect(readAllowFromStoreMock).toHaveBeenCalledWith("line", undefined, "work"); expect(processMessage).not.toHaveBeenCalled(); - const pairingRequest = upsertPairingRequestMock.mock.calls[0]?.[0] as + const pairingRequest = (upsertPairingRequestMock.mock.calls as unknown[][])[0]?.[0] as | { accountId?: string; channel?: string; id?: string } | undefined; expect(pairingRequest?.channel).toBe("line"); diff --git a/extensions/line/src/setup-surface.test.ts b/extensions/line/src/setup-surface.test.ts index 993e4ac51d9..dc43a06ce07 100644 --- a/extensions/line/src/setup-surface.test.ts +++ b/extensions/line/src/setup-surface.test.ts @@ -466,7 +466,9 @@ describe("linePlugin gateway.startAccount", () => { await vi.waitFor(() => { expect(monitorLineProvider).toHaveBeenCalledTimes(1); }); - const startupParams = monitorLineProvider.mock.calls[0]?.[0]; + const startupParams = (monitorLineProvider.mock.calls as unknown[][])[0]?.[0] as + | { accountId?: string; channelAccessToken?: string; channelSecret?: string } + | undefined; expect(startupParams?.channelAccessToken).toBe("token"); expect(startupParams?.channelSecret).toBe("secret"); expect(startupParams?.accountId).toBe("default"); diff --git a/extensions/memory-core/src/dreaming-phases.test.ts b/extensions/memory-core/src/dreaming-phases.test.ts index 65dd23a7b86..879e4b15d21 100644 --- a/extensions/memory-core/src/dreaming-phases.test.ts +++ b/extensions/memory-core/src/dreaming-phases.test.ts @@ -77,7 +77,7 @@ function requireCandidateKeyByPath( } function mockStringMessages(mock: { mock: { calls: unknown[][] } }): string[] { - return mock.mock.calls.map((call) => String(call[0] ?? "")); + return mock.mock.calls.map((call) => (typeof call[0] === "string" ? call[0] : "")); } function expectIncludesSubstring(values: readonly string[], expected: string): void { diff --git a/extensions/memory-core/src/dreaming.test.ts b/extensions/memory-core/src/dreaming.test.ts index 595cd809178..1db53dc8322 100644 --- a/extensions/memory-core/src/dreaming.test.ts +++ b/extensions/memory-core/src/dreaming.test.ts @@ -149,7 +149,7 @@ function createCronHarness( } function mockStringMessages(mock: { mock: { calls: unknown[][] } }): string[] { - return mock.mock.calls.map((call) => String(call[0] ?? "")); + return mock.mock.calls.map((call) => (typeof call[0] === "string" ? call[0] : "")); } function expectLogContains(mock: { mock: { calls: unknown[][] } }, expected: string): void { diff --git a/extensions/nextcloud-talk/src/inbound.behavior.test.ts b/extensions/nextcloud-talk/src/inbound.behavior.test.ts index 7e740bd026a..8d3db88c377 100644 --- a/extensions/nextcloud-talk/src/inbound.behavior.test.ts +++ b/extensions/nextcloud-talk/src/inbound.behavior.test.ts @@ -279,7 +279,9 @@ describe("nextcloud-talk inbound behavior", () => { runtime: createRuntimeEnv(), }); - const assembledRequest = coreRuntime.channel.turn.runAssembled.mock.calls[0]?.[0]; + const assembledRequest = ( + coreRuntime.channel.turn.runAssembled as unknown as { mock: { calls: unknown[][] } } + ).mock.calls[0]?.[0] as { replyPipeline?: unknown } | undefined; expect(assembledRequest?.replyPipeline).toEqual({}); }); }); diff --git a/extensions/nextcloud-talk/src/send.cfg-threading.test.ts b/extensions/nextcloud-talk/src/send.cfg-threading.test.ts index 6ed05b4ee6b..a8a5c93e69c 100644 --- a/extensions/nextcloud-talk/src/send.cfg-threading.test.ts +++ b/extensions/nextcloud-talk/src/send.cfg-threading.test.ts @@ -221,7 +221,7 @@ describe("nextcloud-talk send cfg threading", () => { expect(mediaSendCall?.[0]).toBe( "https://nextcloud.example.com/ocs/v2.php/apps/spreed/api/v1/bot/abc123/message", ); - expect((mediaSendCall?.[1] as RequestInit | undefined)?.body).toBe( + expect(mediaSendCall?.[1]?.body).toBe( JSON.stringify({ message: "image\n\nAttachment: https://example.com/image.png", }), diff --git a/extensions/slack/src/monitor/media.test.ts b/extensions/slack/src/monitor/media.test.ts index b7df2ef7418..37a7c5e96ce 100644 --- a/extensions/slack/src/monitor/media.test.ts +++ b/extensions/slack/src/monitor/media.test.ts @@ -141,7 +141,7 @@ function expectSaveMediaBufferCall(mock: unknown, contentType: string, maxBytes: } function expectVerboseLogContains(expected: string): void { - const messages = vi.mocked(logVerbose).mock.calls.map((call) => String(call[0] ?? "")); + const messages = vi.mocked(logVerbose).mock.calls.map((call) => call[0]); expect(messages.some((message) => message.includes(expected))).toBe(true); } diff --git a/extensions/synology-chat/src/channel.test.ts b/extensions/synology-chat/src/channel.test.ts index 338bda78dae..b25078147b3 100644 --- a/extensions/synology-chat/src/channel.test.ts +++ b/extensions/synology-chat/src/channel.test.ts @@ -31,7 +31,7 @@ function expectIncludesSubstring(values: readonly string[], expected: string): v } function mockStringMessages(mock: { mock: { calls: unknown[][] } }): string[] { - return mock.mock.calls.map((call) => String(call[0] ?? "")); + return mock.mock.calls.map((call) => (typeof call[0] === "string" ? call[0] : "")); } const clientModule = await import("./client.js"); diff --git a/extensions/telegram/src/webhook.test.ts b/extensions/telegram/src/webhook.test.ts index 348626a7b3c..359967db33f 100644 --- a/extensions/telegram/src/webhook.test.ts +++ b/extensions/telegram/src/webhook.test.ts @@ -136,7 +136,9 @@ function requireMockCall(mock: unknown, index: number, label: string): unknown[] } function mockMessages(mock: unknown): string[] { - return (mock as MockCallReader).mock.calls.map((call) => String(call[0] ?? "")); + return (mock as MockCallReader).mock.calls.map((call) => + typeof call[0] === "string" ? call[0] : "", + ); } function expectMockMessageContains(mock: unknown, expected: string): void { diff --git a/src/agents/harness/v2.test.ts b/src/agents/harness/v2.test.ts index 090f01b98a5..9405146df2e 100644 --- a/src/agents/harness/v2.test.ts +++ b/src/agents/harness/v2.test.ts @@ -83,10 +83,10 @@ function captureDiagnosticEvents(): { return { events, unsubscribe }; } -function mockCallArg(mock: { mock: { calls: unknown[][] } }, index = 0): T { +function mockCallArg(mock: { mock: { calls: unknown[][] } }, index = 0): unknown { const call = mock.mock.calls[index]; expect(call).toBeDefined(); - return call[0] as T; + return call[0]; } describe("AgentHarness V2 compatibility adapter", () => { @@ -287,11 +287,11 @@ describe("AgentHarness V2 compatibility adapter", () => { await expect(runAgentHarnessV2LifecycleAttempt(harness, params)).rejects.toThrow( "codex app-server send failed", ); - const cleanupInput = mockCallArg<{ + const cleanupInput = mockCallArg(cleanup) as { error?: unknown; prepared?: { lifecycleState?: string }; session?: { lifecycleState?: string }; - }>(cleanup); + }; expect(cleanupInput.error).toBe(sendError); expect(cleanupInput.prepared?.lifecycleState).toBe("prepared"); expect(cleanupInput.session?.lifecycleState).toBe("started"); @@ -322,11 +322,11 @@ describe("AgentHarness V2 compatibility adapter", () => { await expect(runAgentHarnessV2LifecycleAttempt(harness, params)).rejects.toThrow( "codex app-server start failed", ); - const cleanupInput = mockCallArg<{ + const cleanupInput = mockCallArg(cleanup) as { error?: unknown; prepared?: { lifecycleState?: string }; session?: unknown; - }>(cleanup); + }; expect(cleanupInput.error).toBe(startError); expect(cleanupInput.prepared?.lifecycleState).toBe("prepared"); expect(cleanupInput.session).toBeUndefined(); @@ -358,12 +358,12 @@ describe("AgentHarness V2 compatibility adapter", () => { await expect(runAgentHarnessV2LifecycleAttempt(harness, params)).rejects.toThrow( "outcome classification failed", ); - const cleanupInput = mockCallArg<{ + const cleanupInput = mockCallArg(cleanup) as { error?: unknown; result?: unknown; prepared?: { lifecycleState?: string }; session?: { lifecycleState?: string }; - }>(cleanup); + }; expect(cleanupInput.error).toBe(outcomeError); expect(cleanupInput.result).toBe(rawResult); expect(cleanupInput.prepared?.lifecycleState).toBe("prepared"); diff --git a/src/agents/tools/video-generate-tool.test.ts b/src/agents/tools/video-generate-tool.test.ts index acd666ddbc5..8af509bf9b6 100644 --- a/src/agents/tools/video-generate-tool.test.ts +++ b/src/agents/tools/video-generate-tool.test.ts @@ -153,10 +153,10 @@ function resultDetails(result: { details?: unknown }): Record { return result.details as Record; } -function firstMockCallArg(mock: { mock: { calls: unknown[][] } }): T { +function firstMockCallArg(mock: { mock: { calls: unknown[][] } }): unknown { const firstCall = mock.mock.calls[0]; expect(firstCall).toBeDefined(); - return firstCall[0] as T; + return firstCall[0]; } function resetVideoGenerateMocks() { @@ -570,21 +570,22 @@ describe("createVideoGenerateTool", () => { } await scheduledWork(); expect(saveSpy).not.toHaveBeenCalled(); - const progress = firstMockCallArg<{ runId: string; progressSummary: string }>( - taskExecutorMocks.recordTaskRunProgressByRunId, - ); + const progress = firstMockCallArg(taskExecutorMocks.recordTaskRunProgressByRunId) as { + runId: string; + progressSummary: string; + }; expect(progress.runId).toMatch(/^tool:video_generate:/); expect(progress.progressSummary).toBe("Generating video"); - const completion = firstMockCallArg<{ runId: string }>( - taskExecutorMocks.completeTaskRunByRunId, - ); + const completion = firstMockCallArg(taskExecutorMocks.completeTaskRunByRunId) as { + runId: string; + }; expect(completion.runId).toMatch(/^tool:video_generate:/); - const wake = firstMockCallArg<{ + const wake = firstMockCallArg(wakeSpy) as { handle: { taskId?: string }; status: string; mediaUrls: string[]; result: string; - }>(wakeSpy); + }; expect(wake.handle.taskId).toBe("task-123"); expect(wake.status).toBe("ok"); expect(wake.mediaUrls).toEqual(["https://example.com/generated-lobster.mp4"]); @@ -959,9 +960,10 @@ describe("createVideoGenerateTool", () => { providerOptions: { seed: 42, draft: true }, }); - const input = firstMockCallArg<{ autoProviderFallback?: boolean; providerOptions?: unknown }>( - generateSpy, - ); + const input = firstMockCallArg(generateSpy) as { + autoProviderFallback?: boolean; + providerOptions?: unknown; + }; expect(input.autoProviderFallback).toBe(false); expect(input.providerOptions).toEqual({ seed: 42, draft: true }); }); @@ -1083,7 +1085,9 @@ describe("createVideoGenerateTool", () => { aspectRatio: "adaptive", }); - expect(firstMockCallArg<{ aspectRatio?: string }>(generateSpy).aspectRatio).toBe("adaptive"); + expect((firstMockCallArg(generateSpy) as { aspectRatio?: string }).aspectRatio).toBe( + "adaptive", + ); }); it("accepts provider-specific aspectRatio and resolution values and forwards them to the runtime", async () => { @@ -1097,7 +1101,7 @@ describe("createVideoGenerateTool", () => { resolution: "draft-large", }); - const input = firstMockCallArg<{ aspectRatio?: string; resolution?: string }>(generateSpy); + const input = firstMockCallArg(generateSpy) as { aspectRatio?: string; resolution?: string }; expect(input.aspectRatio).toBe("17:9"); expect(input.resolution).toBe("draft-large"); }); diff --git a/src/wizard/setup.finalize.test.ts b/src/wizard/setup.finalize.test.ts index f0a813a9064..21360db2306 100644 --- a/src/wizard/setup.finalize.test.ts +++ b/src/wizard/setup.finalize.test.ts @@ -239,12 +239,12 @@ function createAdvancedFinalizeArgs(params: AdvancedFinalizeArgs = {}) { }; } -function requireMockArg(mock: ReturnType, callIndex = 0, argIndex = 0): T { +function requireMockArg(mock: ReturnType, callIndex = 0, argIndex = 0): unknown { const call = mock.mock.calls[callIndex]; if (!call) { throw new Error(`expected mock call ${callIndex}`); } - return call[argIndex] as T; + return call[argIndex]; } function expectNoteContains( @@ -253,7 +253,7 @@ function expectNoteContains( title: string, ): void { const calls = vi.mocked(prompter.note).mock.calls; - expect(calls.some((call) => String(call[0]).includes(expected) && call[1] === title)).toBe(true); + expect(calls.some((call) => call[0].includes(expected) && call[1] === title)).toBe(true); } function expectNoteTitleNotCalled( @@ -364,7 +364,10 @@ describe("finalizeSetupWizard", () => { } } - const probeParams = requireMockArg<{ url?: string; password?: string }>(probeGatewayReachable); + const probeParams = requireMockArg(probeGatewayReachable) as { + url?: string; + password?: string; + }; expect(probeParams.url).toBe("ws://127.0.0.1:18789"); expect(probeParams.password).toBe("resolved-gateway-password"); // pragma: allowlist secret expect(launchTuiCli).toHaveBeenCalledWith({ @@ -668,18 +671,18 @@ describe("finalizeSetupWizard", () => { runtime: createRuntime(), }); - const healthArgs = requireMockArg<{ + const healthArgs = requireMockArg(healthCommand) as { json?: boolean; timeoutMs?: number; token?: string; config?: OpenClawConfig; - }>(healthCommand); + }; expect(healthArgs.json).toBe(false); expect(healthArgs.timeoutMs).toBe(10_000); expect(healthArgs.token).toBe("session-token"); expect(healthArgs.config?.gateway?.auth?.mode).toBe("token"); expect(healthArgs.config?.gateway?.auth?.token).toBe("session-token"); - expect(requireMockArg(healthCommand, 0, 1)).toBeTypeOf("object"); + expect(requireMockArg(healthCommand, 0, 1)).toBeTypeOf("object"); }); it("uses the resolved setup password for health checks", async () => { @@ -722,27 +725,27 @@ describe("finalizeSetupWizard", () => { runtime: createRuntime(), }); - const waitArgs = requireMockArg<{ + const waitArgs = requireMockArg(waitForGatewayReachable) as { url?: string; token?: string; password?: string; - }>(waitForGatewayReachable); + }; expect(waitArgs.url).toBe("ws://127.0.0.1:18789"); expect(waitArgs.token).toBeUndefined(); expect(waitArgs.password).toBe("session-password"); - const healthArgs = requireMockArg<{ + const healthArgs = requireMockArg(healthCommand) as { json?: boolean; timeoutMs?: number; token?: string; password?: string; config?: OpenClawConfig; - }>(healthCommand); + }; expect(healthArgs.json).toBe(false); expect(healthArgs.timeoutMs).toBe(10_000); expect(healthArgs.token).toBeUndefined(); expect(healthArgs.password).toBe("session-password"); expect(healthArgs.config?.gateway?.auth?.mode).toBe("password"); - expect(requireMockArg(healthCommand, 0, 1)).toBeTypeOf("object"); + expect(requireMockArg(healthCommand, 0, 1)).toBeTypeOf("object"); }); it("shows actionable gateway guidance instead of a hard error in no-daemon onboarding", async () => {