diff --git a/extensions/clickclack/src/inbound.test.ts b/extensions/clickclack/src/inbound.test.ts index 472e95ce576..102c96648e8 100644 --- a/extensions/clickclack/src/inbound.test.ts +++ b/extensions/clickclack/src/inbound.test.ts @@ -7,6 +7,18 @@ import type { CoreConfig, ResolvedClickClackAccount } from "./types.js"; const sendClickClackTextMock = vi.hoisted(() => vi.fn()); +type LlmCompleteMock = ReturnType< + typeof vi.fn< + (params: { + agentId?: string; + model?: string; + maxTokens?: number; + purpose?: string; + messages?: unknown[]; + }) => Promise + > +>; + vi.mock("./outbound.js", () => ({ sendClickClackText: sendClickClackTextMock, })); @@ -115,7 +127,7 @@ describe("handleClickClackInbound", () => { expect(runtime.channel.turn.runPrepared).not.toHaveBeenCalled(); expect(runtime.agent.runEmbeddedPiAgent).not.toHaveBeenCalled(); - const completionRequest = runtime.llm.complete.mock.calls[0]?.[0]; + const completionRequest = (runtime.llm.complete as LlmCompleteMock).mock.calls[0]?.[0]; expect(completionRequest?.agentId).toBe("service-bot"); expect(completionRequest?.model).toBe("openai/gpt-5.4-mini"); expect(completionRequest?.maxTokens).toBe(96); diff --git a/extensions/diffs/src/browser.test.ts b/extensions/diffs/src/browser.test.ts index 6eaaebeb6eb..4a851346617 100644 --- a/extensions/diffs/src/browser.test.ts +++ b/extensions/diffs/src/browser.test.ts @@ -624,7 +624,7 @@ function createMockBrowser( options?: { boundingBox?: { x: number; y: number; width: number; height: number } }, ) { const browser = { - newPage: vi.fn(async () => { + newPage: vi.fn(async (_options?: unknown) => { const page = createMockPage(options); pages.push(page); return page; diff --git a/extensions/qqbot/src/bridge/tools/remind.test.ts b/extensions/qqbot/src/bridge/tools/remind.test.ts index f14f761da29..2145900ef22 100644 --- a/extensions/qqbot/src/bridge/tools/remind.test.ts +++ b/extensions/qqbot/src/bridge/tools/remind.test.ts @@ -88,7 +88,7 @@ describe("bridge/tools/remind", () => { }); it("supports injected cron scheduler dependencies for engine-level tests", async () => { - const callCron = vi.fn(async () => ({ id: "job-1" })); + const callCron = vi.fn(async (_params: unknown) => ({ id: "job-1" })); const tool = createRemindTool( { senderIsOwner: true, @@ -118,7 +118,7 @@ describe("bridge/tools/remind", () => { }); it("does not schedule when sender ownership is missing", async () => { - const callCron = vi.fn(async () => ({ id: "job-1" })); + const callCron = vi.fn(async (_params: unknown) => ({ id: "job-1" })); const tool = createRemindTool( { deliveryContext: { to: "qqbot:c2c:user-openid", accountId: "bot2" }, diff --git a/extensions/qqbot/src/engine/commands/slash-commands-impl.test.ts b/extensions/qqbot/src/engine/commands/slash-commands-impl.test.ts index 99bf39e3321..eb285fa10cf 100644 --- a/extensions/qqbot/src/engine/commands/slash-commands-impl.test.ts +++ b/extensions/qqbot/src/engine/commands/slash-commands-impl.test.ts @@ -5,8 +5,6 @@ import { getWrittenQQBotConfig, installCommandRuntime } from "./slash-command-te import { getFrameworkCommands, matchSlashCommand } from "./slash-commands-impl.js"; import { SlashCommandRegistry, type SlashCommandContext } from "./slash-commands.js"; -type FrameworkCommand = ReturnType[number]; - function createStreamingContext(overrides: Partial = {}): SlashCommandContext { return { type: "c2c", @@ -66,8 +64,8 @@ describe("QQBot framework slash commands", () => { expect(commands.map((command) => command.name)).toEqual(["private-admin", "shared-admin"]); const privateAdmin = commands.find((command) => command.name === "private-admin"); const sharedAdmin = commands.find((command) => command.name === "shared-admin"); - expect((privateAdmin as FrameworkCommand | undefined)?.c2cOnly).toBe(true); - expect((sharedAdmin as FrameworkCommand | undefined)?.c2cOnly).toBeUndefined(); + expect(privateAdmin?.c2cOnly).toBe(true); + expect(sharedAdmin?.c2cOnly).toBeUndefined(); }); it("routes bot-streaming through the auth-gated framework registry", () => { diff --git a/extensions/qqbot/src/engine/gateway/outbound-dispatch.test.ts b/extensions/qqbot/src/engine/gateway/outbound-dispatch.test.ts index 64323f8f69b..f1712d14cd1 100644 --- a/extensions/qqbot/src/engine/gateway/outbound-dispatch.test.ts +++ b/extensions/qqbot/src/engine/gateway/outbound-dispatch.test.ts @@ -7,7 +7,7 @@ const sendVoiceMessageMock = vi.hoisted(() => vi.fn(async () => ({ id: "voice-1", timestamp: "2026-04-25T00:00:00.000Z" })), ); const sendMediaMock = vi.hoisted(() => - vi.fn(async () => ({ id: "media-1", timestamp: "2026-04-25T00:00:00.000Z" })), + vi.fn(async (_params: unknown) => ({ id: "media-1", timestamp: "2026-04-25T00:00:00.000Z" })), ); const sendTextMock = vi.hoisted(() => vi.fn(async () => ({ id: "text-1", timestamp: "2026-04-25T00:00:00.000Z" })), diff --git a/extensions/searxng/src/searxng-client.test.ts b/extensions/searxng/src/searxng-client.test.ts index c96d1200628..822c0d9f913 100644 --- a/extensions/searxng/src/searxng-client.test.ts +++ b/extensions/searxng/src/searxng-client.test.ts @@ -101,11 +101,17 @@ describe("searxng client", () => { expect(result.provider).toBe("searxng"); expect(result.query).toBe("beijing hourly weather"); expect(result.count).toBe(1); - expect(result.results).toHaveLength(1); - expect(result.results[0]?.url).toBe("https://example.com/weather"); - expect(result.results[0]?.siteName).toBe("example.com"); - expect(result.results[0]?.title).toContain("Beijing hourly weather"); - expect(result.results[0]?.snippet).toContain("Hourly forecast"); + const results = result.results as Array<{ + url?: string; + siteName?: string; + title?: string; + snippet?: string; + }>; + expect(results).toHaveLength(1); + expect(results[0]?.url).toBe("https://example.com/weather"); + expect(results[0]?.siteName).toBe("example.com"); + expect(results[0]?.title).toContain("Beijing hourly weather"); + expect(results[0]?.snippet).toContain("Hourly forecast"); expect(result.externalContent).toEqual({ provider: "searxng", source: "web_search", diff --git a/extensions/tavily/src/tavily-tools.test.ts b/extensions/tavily/src/tavily-tools.test.ts index 0467ed795a3..f9d8f423472 100644 --- a/extensions/tavily/src/tavily-tools.test.ts +++ b/extensions/tavily/src/tavily-tools.test.ts @@ -18,6 +18,13 @@ const { runTavilySearch, runTavilyExtract } = vi.hoisted(() => ({ runTavilyExtract: vi.fn(async (params: unknown) => ({ ok: true, params })), })); +type TavilyExtractParams = { + cfg?: unknown; + urls?: string[]; + query?: string; + chunksPerSource?: number; +}; + vi.mock("./tavily-client.js", () => ({ runTavilySearch, runTavilyExtract, @@ -211,7 +218,7 @@ describe("tavily tools", () => { const searchParams = runTavilySearch.mock.calls[0]?.[0]; expect(searchParams?.cfg).toBe(runtimeConfig); expect(searchParams?.query).toBe("openclaw"); - const extractParams = runTavilyExtract.mock.calls[0]?.[0]; + const extractParams = runTavilyExtract.mock.calls[0]?.[0] as TavilyExtractParams | undefined; expect(extractParams?.cfg).toBe(runtimeConfig); expect(extractParams?.urls).toEqual(["https://example.com"]); }); @@ -249,7 +256,7 @@ describe("tavily tools", () => { chunks_per_source: 2, }); - const extractParams = runTavilyExtract.mock.calls[0]?.[0]; + const extractParams = runTavilyExtract.mock.calls[0]?.[0] as TavilyExtractParams | undefined; expect(extractParams?.cfg).toEqual({}); expect(extractParams?.urls).toEqual(["https://example.com"]); expect(extractParams?.query).toBe("pricing"); diff --git a/src/cli/daemon-cli/restart-health.test.ts b/src/cli/daemon-cli/restart-health.test.ts index 2176c4dae73..1f3011cc783 100644 --- a/src/cli/daemon-cli/restart-health.test.ts +++ b/src/cli/daemon-cli/restart-health.test.ts @@ -54,7 +54,7 @@ function makeGatewayService( } as unknown as GatewayService; } -function firstCallArg(mock: { mock: { calls: unknown[][] } }): T { +function firstCallArg(mock: { mock: { calls: unknown[][] } }, _type?: (value: T) => T): T { const call = mock.mock.calls[0]; expect(call).toBeDefined(); return call?.[0] as T; diff --git a/src/commands/auth-choice.test.ts b/src/commands/auth-choice.test.ts index 9b3f01802ff..9396b65a060 100644 --- a/src/commands/auth-choice.test.ts +++ b/src/commands/auth-choice.test.ts @@ -627,7 +627,10 @@ describe("applyAuthChoice", () => { expect(profile?.mode).toBe(expected.mode); } function promptMessages(mock: { mock: { calls: unknown[][] } }): string[] { - return mock.mock.calls.map((call) => String((call[0] as { message?: unknown })?.message ?? "")); + return mock.mock.calls.map((call) => { + const message = (call[0] as { message?: unknown }).message; + return typeof message === "string" ? message : ""; + }); } function expectPromptMessageContaining(mock: { mock: { calls: unknown[][] } }, expected: string) { expect(promptMessages(mock).some((message) => message.includes(expected))).toBe(true); @@ -635,7 +638,7 @@ describe("applyAuthChoice", () => { function expectPromptMessage(mock: { mock: { calls: unknown[][] } }, expected: string) { expect(promptMessages(mock)).toContain(expected); } - function firstCallArg(mock: { mock: { calls: unknown[][] } }): T { + function firstCallArg(mock: { mock: { calls: unknown[][] } }, _type?: (value: T) => T): T { const call = mock.mock.calls[0]; expect(call).toBeDefined(); return call?.[0] as T; diff --git a/src/gateway/server.sessions.reset-hooks.test.ts b/src/gateway/server.sessions.reset-hooks.test.ts index d6106155e78..1157d339af3 100644 --- a/src/gateway/server.sessions.reset-hooks.test.ts +++ b/src/gateway/server.sessions.reset-hooks.test.ts @@ -175,7 +175,7 @@ test("sessions.reset emits enriched session_end and session_start hooks", async expect(endEvent.sessionKey).toBe("agent:main:main"); expect(endEvent.reason).toBe("new"); expect(endEvent.transcriptArchived).toBe(true); - expect(String(endEvent.sessionFile ?? "")).toContain(".jsonl.reset."); + expect(endEvent.sessionFile).toEqual(expect.stringContaining(".jsonl.reset.")); expect(endEvent.nextSessionId).toBe(startEvent.sessionId); expectMainHookContext(endContext, "sess-main"); expect(startEvent.sessionKey).toBe("agent:main:main"); @@ -371,7 +371,7 @@ test("sessions.create with emitCommandHooks=true emits reset lifecycle hooks aga expect(startEvent.resumedFrom).toBe("sess-parent-hooks"); expect(startEvent.sessionId).toBeTypeOf("string"); expect(startEvent.sessionId).not.toBe(""); - expect(String(startEvent.sessionKey ?? "")).toMatch(/^agent:main:dashboard:/); + expect(startEvent.sessionKey).toEqual(expect.stringMatching(/^agent:main:dashboard:/)); }); test("sessions.create with emitCommandHooks=true resets parent in place when session.dmScope is 'main' (#77434)", async () => { diff --git a/src/infra/outbound/delivery-queue.recovery.test.ts b/src/infra/outbound/delivery-queue.recovery.test.ts index 35ae778ec23..45f59d7af81 100644 --- a/src/infra/outbound/delivery-queue.recovery.test.ts +++ b/src/infra/outbound/delivery-queue.recovery.test.ts @@ -22,14 +22,18 @@ vi.mock("./channel-resolution.js", () => ({ resolveOutboundChannelMessageAdapter: resolveOutboundChannelMessageAdapterMock, })); -function mockCallArg(mock: { mock: { calls: unknown[][] } }, index = 0): T { +function mockCallArg( + mock: { mock: { calls: unknown[][] } }, + index = 0, + _type?: (value: T) => T, +): T { const call = mock.mock.calls[index]; expect(call).toBeDefined(); return call[0] as T; } function expectMockMessageContaining(mock: { mock: { calls: unknown[][] } }, expected: string) { - const messages = mock.mock.calls.map((call) => String(call[0] ?? "")); + const messages = mock.mock.calls.map((call) => (typeof call[0] === "string" ? call[0] : "")); expect(messages.some((message) => message.includes(expected))).toBe(true); }