diff --git a/src/auto-reply/reply.block-streaming.test.ts b/src/auto-reply/reply.block-streaming.test.ts index c8484d5c3f..1f0e2e1d1c 100644 --- a/src/auto-reply/reply.block-streaming.test.ts +++ b/src/auto-reply/reply.block-streaming.test.ts @@ -3,6 +3,7 @@ import os from "node:os"; import path from "node:path"; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { loadModelCatalog } from "../agents/model-catalog.js"; +import type { OpenClawConfig } from "../config/config.js"; import { getReplyFromConfig } from "./reply.js"; type RunEmbeddedPiAgent = typeof import("../agents/pi-embedded.js").runEmbeddedPiAgent; @@ -11,7 +12,7 @@ type RunEmbeddedPiAgentReply = Awaited>; const piEmbeddedMock = vi.hoisted(() => ({ abortEmbeddedPiRun: vi.fn().mockReturnValue(false), - runEmbeddedPiAgent: vi.fn, Parameters>(), + runEmbeddedPiAgent: vi.fn(), queueEmbeddedPiMessage: vi.fn().mockReturnValue(false), resolveEmbeddedSessionLane: (key: string) => `session:${key.trim() || "main"}`, isEmbeddedPiRunActive: vi.fn().mockReturnValue(false), @@ -55,6 +56,8 @@ function restoreHomeEnv(snapshot: HomeEnvSnapshot) { let fixtureRoot = ""; let caseId = 0; +type GetReplyOptions = NonNullable[1]>; + function createEmbeddedReply(text: string): RunEmbeddedPiAgentReply { return { payloads: [{ text }], @@ -75,11 +78,11 @@ function createTelegramMessage(messageSid: string) { } as const; } -function createReplyConfig(home: string, streamMode?: "block") { +function createReplyConfig(home: string, streamMode?: "block"): OpenClawConfig { return { agents: { defaults: { - model: "anthropic/claude-opus-4-5", + model: { primary: "anthropic/claude-opus-4-5" }, workspace: path.join(home, "openclaw"), }, }, @@ -91,8 +94,8 @@ function createReplyConfig(home: string, streamMode?: "block") { async function runTelegramReply(params: { home: string; messageSid: string; - onBlockReply?: Parameters[1]["onBlockReply"]; - onReplyStart?: Parameters[1]["onReplyStart"]; + onBlockReply?: GetReplyOptions["onBlockReply"]; + onReplyStart?: GetReplyOptions["onReplyStart"]; disableBlockStreaming?: boolean; streamMode?: "block"; }) { @@ -220,7 +223,8 @@ describe("block streaming", () => { streamMode: "block", }); - expect(resStreamMode?.text).toBe("final"); + const streamPayload = Array.isArray(resStreamMode) ? resStreamMode[0] : resStreamMode; + expect(streamPayload?.text).toBe("final"); expect(onBlockReplyStreamMode).not.toHaveBeenCalled(); }); }); diff --git a/src/browser/server.agent-contract-snapshot-endpoints.test.ts b/src/browser/server.agent-contract-snapshot-endpoints.test.ts index e10e9eca32..8c411e0877 100644 --- a/src/browser/server.agent-contract-snapshot-endpoints.test.ts +++ b/src/browser/server.agent-contract-snapshot-endpoints.test.ts @@ -59,7 +59,7 @@ describe("browser control server", () => { it("agent contract: navigation + common act commands", async () => { const base = await startServerAndBase(); - const nav = await postJson(`${base}/navigate`, { + const nav = await postJson<{ ok: boolean; targetId?: string }>(`${base}/navigate`, { url: "https://example.com", }); expect(nav.ok).toBe(true); @@ -70,7 +70,7 @@ describe("browser control server", () => { url: "https://example.com", }); - const click = await postJson(`${base}/act`, { + const click = await postJson<{ ok: boolean }>(`${base}/act`, { kind: "click", ref: "1", button: "left", @@ -96,7 +96,7 @@ describe("browser control server", () => { /'selector' is not supported/i, ); - const type = await postJson(`${base}/act`, { + const type = await postJson<{ ok: boolean }>(`${base}/act`, { kind: "type", ref: "1", text: "", @@ -111,7 +111,7 @@ describe("browser control server", () => { slowly: false, }); - const press = await postJson(`${base}/act`, { + const press = await postJson<{ ok: boolean }>(`${base}/act`, { kind: "press", key: "Enter", }); @@ -122,7 +122,7 @@ describe("browser control server", () => { key: "Enter", }); - const hover = await postJson(`${base}/act`, { + const hover = await postJson<{ ok: boolean }>(`${base}/act`, { kind: "hover", ref: "2", }); @@ -133,7 +133,7 @@ describe("browser control server", () => { ref: "2", }); - const scroll = await postJson(`${base}/act`, { + const scroll = await postJson<{ ok: boolean }>(`${base}/act`, { kind: "scrollIntoView", ref: "2", }); @@ -144,7 +144,7 @@ describe("browser control server", () => { ref: "2", }); - const drag = await postJson(`${base}/act`, { + const drag = await postJson<{ ok: boolean }>(`${base}/act`, { kind: "drag", startRef: "3", endRef: "4", diff --git a/src/commands/onboard-channels.e2e.test.ts b/src/commands/onboard-channels.e2e.test.ts index 833f1a28d3..d263ff9c0b 100644 --- a/src/commands/onboard-channels.e2e.test.ts +++ b/src/commands/onboard-channels.e2e.test.ts @@ -62,7 +62,7 @@ describe("setupChannels", () => { }); const prompter = createPrompter({ - select, + select: select as unknown as WizardPrompter["select"], multiselect, text: text as unknown as WizardPrompter["text"], }); @@ -82,13 +82,13 @@ describe("setupChannels", () => { }); it("shows explicit dmScope config command in channel primer", async () => { - const note = vi.fn(async () => {}); + const note = vi.fn(async (_message?: string, _title?: string) => {}); const select = vi.fn(async () => "__done__"); const { multiselect, text } = createUnexpectedPromptGuards(); const prompter = createPrompter({ note, - select, + select: select as unknown as WizardPrompter["select"], multiselect, text, }); @@ -121,7 +121,7 @@ describe("setupChannels", () => { const { multiselect, text } = createUnexpectedPromptGuards(); const prompter = createPrompter({ - select, + select: select as unknown as WizardPrompter["select"], multiselect, text, }); @@ -173,7 +173,7 @@ describe("setupChannels", () => { throw new Error("unexpected multiselect"); }); const prompter = createPrompter({ - select, + select: select as unknown as WizardPrompter["select"], multiselect, text: vi.fn(async () => "") as unknown as WizardPrompter["text"], }); diff --git a/src/commands/onboard-helpers.e2e.test.ts b/src/commands/onboard-helpers.e2e.test.ts index f0d7a18435..f9af2e9599 100644 --- a/src/commands/onboard-helpers.e2e.test.ts +++ b/src/commands/onboard-helpers.e2e.test.ts @@ -8,14 +8,19 @@ import { } from "./onboard-helpers.js"; const mocks = vi.hoisted(() => ({ - runCommandWithTimeout: vi.fn(async () => ({ + runCommandWithTimeout: vi.fn< + ( + argv: string[], + options?: { timeoutMs?: number; windowsVerbatimArguments?: boolean }, + ) => Promise<{ stdout: string; stderr: string; code: number; signal: null; killed: boolean }> + >(async () => ({ stdout: "", stderr: "", code: 0, signal: null, killed: false, })), - pickPrimaryTailnetIPv4: vi.fn(() => undefined), + pickPrimaryTailnetIPv4: vi.fn<() => string | undefined>(() => undefined), })); vi.mock("../process/exec.js", () => ({ diff --git a/src/cron/service.issue-13992-regression.test.ts b/src/cron/service.issue-13992-regression.test.ts index 52a4884a67..04e1e87787 100644 --- a/src/cron/service.issue-13992-regression.test.ts +++ b/src/cron/service.issue-13992-regression.test.ts @@ -10,10 +10,16 @@ describe("issue #13992 regression - cron jobs skip execution", () => { running: false, timer: null, storeLoadedAtMs: Date.now(), + storeFileMtimeMs: null, + op: Promise.resolve(), + warnedDisabled: false, deps: { storePath: "/mock/path", cronEnabled: true, nowMs: () => Date.now(), + enqueueSystemEvent: () => {}, + requestHeartbeatNow: () => {}, + runIsolatedAgentJob: async () => ({ status: "ok" }), log: { debug: () => {}, info: () => {}, @@ -35,6 +41,7 @@ describe("issue #13992 regression - cron jobs skip execution", () => { schedule: { kind: "cron", expr: "0 8 * * *", tz: "UTC" }, payload: { kind: "systemEvent", text: "test" }, sessionTarget: "main", + wakeMode: "next-heartbeat", createdAtMs: now - 3600_000, updatedAtMs: now - 3600_000, state: { @@ -59,6 +66,7 @@ describe("issue #13992 regression - cron jobs skip execution", () => { schedule: { kind: "cron", expr: "0 8 * * *", tz: "UTC" }, payload: { kind: "systemEvent", text: "test" }, sessionTarget: "main", + wakeMode: "next-heartbeat", createdAtMs: now, updatedAtMs: now, state: { @@ -85,6 +93,7 @@ describe("issue #13992 regression - cron jobs skip execution", () => { schedule: { kind: "cron", expr: "0 8 * * *", tz: "UTC" }, payload: { kind: "systemEvent", text: "test" }, sessionTarget: "main", + wakeMode: "next-heartbeat", createdAtMs: now, updatedAtMs: now, state: { @@ -111,6 +120,7 @@ describe("issue #13992 regression - cron jobs skip execution", () => { schedule: { kind: "cron", expr: "0 8 * * *", tz: "UTC" }, payload: { kind: "systemEvent", text: "test" }, sessionTarget: "main", + wakeMode: "next-heartbeat", createdAtMs: now, updatedAtMs: now, state: { @@ -139,6 +149,7 @@ describe("issue #13992 regression - cron jobs skip execution", () => { schedule: { kind: "cron", expr: "0 8 * * *", tz: "UTC" }, payload: { kind: "systemEvent", text: "due" }, sessionTarget: "main", + wakeMode: "next-heartbeat", createdAtMs: now - 3600_000, updatedAtMs: now - 3600_000, state: { @@ -153,6 +164,7 @@ describe("issue #13992 regression - cron jobs skip execution", () => { schedule: { kind: "cron", expr: "not a valid cron", tz: "UTC" }, payload: { kind: "systemEvent", text: "bad" }, sessionTarget: "main", + wakeMode: "next-heartbeat", createdAtMs: now - 3600_000, updatedAtMs: now - 3600_000, state: { diff --git a/src/cron/service.issue-17852-daily-skip.test.ts b/src/cron/service.issue-17852-daily-skip.test.ts index 46ef0786f9..27f56abdd6 100644 --- a/src/cron/service.issue-17852-daily-skip.test.ts +++ b/src/cron/service.issue-17852-daily-skip.test.ts @@ -25,10 +25,16 @@ describe("issue #17852 - daily cron jobs should not skip days", () => { running: false, timer: null, storeLoadedAtMs: nowMs, + storeFileMtimeMs: null, + op: Promise.resolve(), + warnedDisabled: false, deps: { storePath: "/mock/path", cronEnabled: true, nowMs: () => nowMs, + enqueueSystemEvent: () => {}, + requestHeartbeatNow: () => {}, + runIsolatedAgentJob: async () => ({ status: "ok" }), log: { debug: () => {}, info: () => {}, @@ -47,6 +53,7 @@ describe("issue #17852 - daily cron jobs should not skip days", () => { schedule: { kind: "cron", expr: "0 3 * * *", tz: "UTC" }, payload: { kind: "systemEvent", text: "daily task" }, sessionTarget: "main", + wakeMode: "next-heartbeat", createdAtMs: threeAM - DAY_MS, updatedAtMs: threeAM - DAY_MS, state: {