chore: Fix types in tests 42/N.

This commit is contained in:
cpojer
2026-02-17 15:48:29 +09:00
parent 6264c5e842
commit 7d2ef131c1
24 changed files with 133 additions and 39 deletions

View File

@@ -370,6 +370,7 @@ describe("resolveGroupRequireMention", () => {
GroupSpace: "145",
};
const groupResolution: GroupKeyResolution = {
key: "discord:group:123",
channel: "discord",
id: "123",
chatType: "group",
@@ -394,6 +395,7 @@ describe("resolveGroupRequireMention", () => {
GroupSubject: "#general",
};
const groupResolution: GroupKeyResolution = {
key: "slack:group:C123",
channel: "slack",
id: "C123",
chatType: "group",

View File

@@ -79,7 +79,11 @@ describe("buildInboundMediaNote", () => {
const note = buildInboundMediaNote({
MediaPaths: ["/tmp/a.png", "/tmp/b.png"],
MediaUrls: ["https://example.com/a.png", "https://example.com/b.png"],
MediaUnderstandingDecisions: [createSuccessfulImageMediaDecision()],
MediaUnderstandingDecisions: [
createSuccessfulImageMediaDecision() as unknown as NonNullable<
Parameters<typeof buildInboundMediaNote>[0]["MediaUnderstandingDecisions"]
>[number],
],
});
expect(note).toBe("[media attached: /tmp/b.png | https://example.com/b.png]");
});

View File

@@ -3,6 +3,7 @@ import fs from "node:fs/promises";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { loadSessionStore } from "../config/sessions.js";
import type { ModelDefinitionConfig } from "../config/types.models.js";
import { drainSystemEvents } from "../infra/system-events.js";
import {
assertModelSelection,
@@ -13,6 +14,18 @@ import {
} from "./reply.directive.directive-behavior.e2e-harness.js";
import { getReplyFromConfig } from "./reply.js";
function makeModelDefinition(id: string, name: string): ModelDefinitionConfig {
return {
id,
name,
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128_000,
maxTokens: 8_192,
};
}
describe("directive behavior", () => {
installDirectiveBehaviorE2EHooks();
@@ -42,13 +55,13 @@ describe("directive behavior", () => {
baseUrl: "https://api.moonshot.ai/v1",
apiKey: "sk-test",
api: "openai-completions",
models: [{ id: "kimi-k2-0905-preview", name: "Kimi K2" }],
models: [makeModelDefinition("kimi-k2-0905-preview", "Kimi K2")],
},
lmstudio: {
baseUrl: "http://127.0.0.1:1234/v1",
apiKey: "lmstudio",
api: "openai-responses",
models: [{ id: "kimi-k2-0905-preview", name: "Kimi K2 (Local)" }],
models: [makeModelDefinition("kimi-k2-0905-preview", "Kimi K2 (Local)")],
},
},
},

View File

@@ -1,6 +1,7 @@
import "./reply.directive.directive-behavior.e2e-mocks.js";
import path from "node:path";
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { loadSessionStore } from "../config/sessions.js";
import {
installDirectiveBehaviorE2EHooks,
@@ -27,7 +28,7 @@ describe("directive behavior", () => {
},
channels: { whatsapp: { allowFrom: ["*"] } },
session: { store: storePath },
};
} as unknown as OpenClawConfig;
}
async function runQueueDirective(params: { home: string; storePath: string; body: string }) {
@@ -94,7 +95,7 @@ describe("directive behavior", () => {
CommandAuthorized: true,
},
{},
makeRestrictedElevatedDisabledConfig(home),
makeRestrictedElevatedDisabledConfig(home) as unknown as OpenClawConfig,
);
const text = extractReplyText(res);

View File

@@ -1,5 +1,6 @@
import "./reply.directive.directive-behavior.e2e-mocks.js";
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { loadSessionStore } from "../config/sessions.js";
import {
AUTHORIZED_WHATSAPP_COMMAND,
@@ -65,7 +66,7 @@ describe("directive behavior", () => {
CommandAuthorized: true,
},
{},
makeRestrictedElevatedDisabledConfig(home),
makeRestrictedElevatedDisabledConfig(home) as unknown as OpenClawConfig,
);
const text = replyText(res);

View File

@@ -1,4 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { createTempHomeHarness, makeReplyConfig } from "./reply.test-harness.js";
const runEmbeddedPiAgentMock = vi.fn();
@@ -63,7 +64,7 @@ describe("getReplyFromConfig typing (heartbeat)", () => {
await getReplyFromConfig(
{ Body: "hi", From: "+1000", To: "+2000", Provider: "whatsapp" },
{ onReplyStart, isHeartbeat: false },
makeReplyConfig(home),
makeReplyConfig(home) as unknown as OpenClawConfig,
);
expect(onReplyStart).toHaveBeenCalled();
@@ -81,7 +82,7 @@ describe("getReplyFromConfig typing (heartbeat)", () => {
await getReplyFromConfig(
{ Body: "hi", From: "+1000", To: "+2000", Provider: "whatsapp" },
{ onReplyStart, isHeartbeat: true },
makeReplyConfig(home),
makeReplyConfig(home) as unknown as OpenClawConfig,
);
expect(onReplyStart).not.toHaveBeenCalled();

View File

@@ -2,6 +2,7 @@ import path from "node:path";
import { describe, expect, it, vi } from "vitest";
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
import { runEmbeddedPiAgent } from "../agents/pi-embedded.js";
import type { OpenClawConfig } from "../config/config.js";
import { getReplyFromConfig } from "./reply.js";
vi.mock("../agents/pi-embedded.js", () => ({
@@ -48,7 +49,7 @@ function makeCfg(home: string) {
},
channels: { whatsapp: { allowFrom: ["*"] } },
session: { store: path.join(home, "sessions.json") },
};
} as unknown as OpenClawConfig;
}
describe("getReplyFromConfig media note plumbing", () => {

View File

@@ -1,4 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { createTempHomeHarness, makeReplyConfig } from "./reply.test-harness.js";
const agentMocks = vi.hoisted(() => ({
@@ -70,7 +71,11 @@ describe("RawBody directive parsing", () => {
CommandAuthorized: true,
};
const res = await getReplyFromConfig(groupMessageCtx, {}, makeReplyConfig(home));
const res = await getReplyFromConfig(
groupMessageCtx,
{},
makeReplyConfig(home) as OpenClawConfig,
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toBe("ok");

View File

@@ -16,6 +16,14 @@ beforeAll(async () => {
installTriggerHandlingE2eTestHooks();
function requireSessionStorePath(cfg: { session?: { store?: string } }): string {
const storePath = cfg.session?.store;
if (!storePath) {
throw new Error("expected session store path");
}
return storePath;
}
describe("trigger handling", () => {
it("allows approved sender to toggle elevated mode", async () => {
await withTempHome(async (home) => {
@@ -46,7 +54,7 @@ describe("trigger handling", () => {
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("tools.elevated.enabled");
const storeRaw = await fs.readFile(cfg.session!.store, "utf-8");
const storeRaw = await fs.readFile(requireSessionStorePath(cfg), "utf-8");
const store = JSON.parse(storeRaw) as Record<string, { elevatedLevel?: string }>;
expect(store[MAIN_SESSION_KEY]?.elevatedLevel).toBeUndefined();
});

View File

@@ -16,6 +16,14 @@ beforeAll(async () => {
installTriggerHandlingE2eTestHooks();
function requireSessionStorePath(cfg: { session?: { store?: string } }): string {
const storePath = cfg.session?.store;
if (!storePath) {
throw new Error("expected session store path");
}
return storePath;
}
describe("trigger handling", () => {
it("allows elevated off in groups without mention", async () => {
await withTempHome(async (home) => {
@@ -38,7 +46,7 @@ describe("trigger handling", () => {
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Elevated mode disabled.");
const store = loadSessionStore(cfg.session!.store);
const store = loadSessionStore(requireSessionStorePath(cfg));
expect(store["agent:main:whatsapp:group:123@g.us"]?.elevatedLevel).toBe("off");
});
});
@@ -64,7 +72,7 @@ describe("trigger handling", () => {
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Elevated mode set to ask");
const storeRaw = await fs.readFile(cfg.session!.store, "utf-8");
const storeRaw = await fs.readFile(requireSessionStorePath(cfg), "utf-8");
const store = JSON.parse(storeRaw) as Record<string, { elevatedLevel?: string }>;
expect(store["agent:main:whatsapp:group:123@g.us"]?.elevatedLevel).toBe("on");
});

View File

@@ -1,6 +1,7 @@
import fs from "node:fs/promises";
import { join } from "node:path";
import { beforeAll, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import {
getRunEmbeddedPiAgentMock,
installTriggerHandlingE2eTestHooks,
@@ -17,6 +18,14 @@ beforeAll(async () => {
installTriggerHandlingE2eTestHooks();
function requireSessionStorePath(cfg: { session?: { store?: string } }): string {
const storePath = cfg.session?.store;
if (!storePath) {
throw new Error("expected session store path");
}
return storePath;
}
describe("trigger handling", () => {
it("ignores inline elevated directive for unapproved sender", async () => {
await withTempHome(async (home) => {
@@ -56,7 +65,7 @@ describe("trigger handling", () => {
},
tools: { elevated: { allowFrom: { discord: ["steipete"] } } },
session: { store: join(home, "sessions.json") },
};
} as OpenClawConfig;
const res = await getReplyFromConfig(
{
@@ -75,7 +84,7 @@ describe("trigger handling", () => {
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Elevated mode set to ask");
const storeRaw = await fs.readFile(cfg.session.store, "utf-8");
const storeRaw = await fs.readFile(requireSessionStorePath(cfg), "utf-8");
const store = JSON.parse(storeRaw) as Record<string, { elevatedLevel?: string }>;
expect(store[MAIN_SESSION_KEY]?.elevatedLevel).toBe("on");
});
@@ -95,7 +104,7 @@ describe("trigger handling", () => {
},
},
session: { store: join(home, "sessions.json") },
};
} as OpenClawConfig;
const res = await getReplyFromConfig(
{

View File

@@ -34,9 +34,17 @@ function mockEmbeddedOkPayload() {
return runEmbeddedPiAgentMock;
}
function requireSessionStorePath(cfg: { session?: { store?: string } }): string {
const storePath = cfg.session?.store;
if (!storePath) {
throw new Error("expected session store path");
}
return storePath;
}
async function writeStoredModelOverride(cfg: ReturnType<typeof makeCfg>): Promise<void> {
await fs.writeFile(
cfg.session!.store,
requireSessionStorePath(cfg),
JSON.stringify({
[MAIN_SESSION_KEY]: {
sessionId: "main",
@@ -154,7 +162,7 @@ describe("trigger handling", () => {
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Group activation set to always");
const store = JSON.parse(await fs.readFile(cfg.session!.store, "utf-8")) as Record<
const store = JSON.parse(await fs.readFile(requireSessionStorePath(cfg), "utf-8")) as Record<
string,
{ groupActivation?: string }
>;

View File

@@ -40,6 +40,14 @@ function makeUnauthorizedWhatsAppCfg(home: string) {
};
}
function requireSessionStorePath(cfg: { session?: { store?: string } }): string {
const storePath = cfg.session?.store;
if (!storePath) {
throw new Error("expected session store path");
}
return storePath;
}
async function runInlineUnauthorizedCommand(params: {
home: string;
command: "/status" | "/help";
@@ -143,7 +151,7 @@ describe("trigger handling", () => {
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Send policy set to off");
const storeRaw = await fs.readFile(cfg.session!.store, "utf-8");
const storeRaw = await fs.readFile(requireSessionStorePath(cfg), "utf-8");
const store = JSON.parse(storeRaw) as Record<string, { sendPolicy?: string }>;
expect(store[MAIN_SESSION_KEY]?.sendPolicy).toBe("deny");
});

View File

@@ -18,6 +18,14 @@ beforeAll(async () => {
installTriggerHandlingE2eTestHooks();
function requireSessionStorePath(cfg: { session?: { store?: string } }): string {
const storePath = cfg.session?.store;
if (!storePath) {
throw new Error("expected session store path");
}
return storePath;
}
describe("trigger handling", () => {
it("reports active auth profile and key snippet in status", async () => {
await withTempHome(async (home) => {
@@ -50,7 +58,7 @@ describe("trigger handling", () => {
Provider: "whatsapp",
} as Parameters<typeof resolveSessionKey>[1]);
await fs.writeFile(
cfg.session!.store,
requireSessionStorePath(cfg),
JSON.stringify(
{
[sessionKey]: {

View File

@@ -1,5 +1,6 @@
import { beforeAll, describe, expect, it } from "vitest";
import { normalizeTestText } from "../../test/helpers/normalize-text.js";
import type { OpenClawConfig } from "../config/config.js";
import {
getRunEmbeddedPiAgentMock,
installTriggerHandlingE2eTestHooks,
@@ -47,7 +48,7 @@ describe("trigger handling", () => {
},
},
},
};
} as unknown as OpenClawConfig;
const res = await getReplyFromConfig(modelStatusCtx, {}, cfg);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
@@ -78,7 +79,7 @@ describe("trigger handling", () => {
it("restarts when enabled", async () => {
await withTempHome(async (home) => {
const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock();
const cfg = { ...makeCfg(home), commands: { restart: true } };
const cfg = { ...makeCfg(home), commands: { restart: true } } as OpenClawConfig;
const res = await getReplyFromConfig(
{
Body: "/restart",

View File

@@ -16,6 +16,14 @@ installTriggerHandlingE2eTestHooks();
const DEFAULT_SESSION_KEY = "telegram:slash:111";
function requireSessionStorePath(cfg: { session?: { store?: string } }): string {
const storePath = cfg.session?.store;
if (!storePath) {
throw new Error("expected session store path");
}
return storePath;
}
function makeTelegramModelCommand(body: string, sessionKey = DEFAULT_SESSION_KEY) {
return {
Body: body,
@@ -78,7 +86,7 @@ describe("trigger handling", () => {
expect(normalized).toContain("Model set to openrouter/anthropic/claude-opus-4-5");
const store = loadSessionStore(cfg.session!.store);
const store = loadSessionStore(requireSessionStorePath(cfg));
expect(store[sessionKey]?.providerOverride).toBe("openrouter");
expect(store[sessionKey]?.modelOverride).toBe("anthropic/claude-opus-4-5");
});
@@ -92,7 +100,7 @@ describe("trigger handling", () => {
expect(normalized).toContain("Browse: /models or /models <provider>");
expect(normalized).toContain("Switch: /model <provider/model>");
const store = loadSessionStore(cfg.session!.store);
const store = loadSessionStore(requireSessionStorePath(cfg));
expect(store[sessionKey]?.providerOverride).toBeUndefined();
expect(store[sessionKey]?.modelOverride).toBeUndefined();
});
@@ -107,7 +115,7 @@ describe("trigger handling", () => {
expect(normalized).toContain("Model reset to default (anthropic/claude-opus-4-5)");
const store = loadSessionStore(cfg.session!.store);
const store = loadSessionStore(requireSessionStorePath(cfg));
expect(store[sessionKey]?.providerOverride).toBeUndefined();
expect(store[sessionKey]?.modelOverride).toBeUndefined();
});
@@ -119,7 +127,7 @@ describe("trigger handling", () => {
expect(normalized).toContain("Model set to openai/gpt-5.2");
const store = loadSessionStore(cfg.session!.store);
const store = loadSessionStore(requireSessionStorePath(cfg));
expect(store[sessionKey]?.providerOverride).toBe("openai");
expect(store[sessionKey]?.modelOverride).toBe("gpt-5.2");
});

View File

@@ -642,10 +642,11 @@ describe("runReplyAgent claude-cli routing", () => {
}
it("uses claude-cli runner for claude-cli provider", async () => {
const randomSpy = vi.spyOn(crypto, "randomUUID").mockReturnValue("run-1");
const runId = "00000000-0000-0000-0000-000000000001";
const randomSpy = vi.spyOn(crypto, "randomUUID").mockReturnValue(runId);
const lifecyclePhases: string[] = [];
const unsubscribe = onAgentEvent((evt) => {
if (evt.runId !== "run-1") {
if (evt.runId !== runId) {
return;
}
if (evt.stream !== "lifecycle") {

View File

@@ -91,8 +91,8 @@ describe("/model chat UX", () => {
describe("handleDirectiveOnly model persist behavior (fixes #1435)", () => {
const allowedModelKeys = new Set(["anthropic/claude-opus-4-5", "openai/gpt-4o"]);
const allowedModelCatalog = [
{ provider: "anthropic", id: "claude-opus-4-5" },
{ provider: "openai", id: "gpt-4o" },
{ provider: "anthropic", id: "claude-opus-4-5", name: "Claude Opus 4.5" },
{ provider: "openai", id: "gpt-4o", name: "GPT-4o" },
];
const sessionKey = "agent:main:dm:1";
const storePath = "/tmp/sessions.json";

View File

@@ -66,12 +66,12 @@ describe("handleInlineActions", () => {
elevatedEnabled: false,
elevatedAllowed: false,
elevatedFailures: [],
defaultActivation: () => ({ enabled: true, message: "" }),
defaultActivation: () => "always",
resolvedThinkLevel: undefined,
resolvedVerboseLevel: undefined,
resolvedReasoningLevel: "off",
resolvedElevatedLevel: "off",
resolveDefaultThinkingLevel: () => "off",
resolveDefaultThinkingLevel: async () => "off",
provider: "openai",
model: "gpt-4o-mini",
contextTokens: 0,

View File

@@ -1,4 +1,5 @@
import { describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../../config/config.js";
import { resolveMemoryFlushPromptForRun } from "./memory-flush.js";
describe("resolveMemoryFlushPromptForRun", () => {
@@ -9,7 +10,7 @@ describe("resolveMemoryFlushPromptForRun", () => {
timeFormat: "12",
},
},
};
} as OpenClawConfig;
it("replaces YYYY-MM-DD using user timezone and appends current time", () => {
const prompt = resolveMemoryFlushPromptForRun({

View File

@@ -612,7 +612,7 @@ let previousRuntimeError: typeof defaultRuntime.error;
beforeAll(() => {
previousRuntimeError = defaultRuntime.error;
defaultRuntime.error = undefined;
defaultRuntime.error = (() => {}) as typeof defaultRuntime.error;
});
afterAll(() => {
@@ -1160,7 +1160,8 @@ describe("createReplyDispatcher", () => {
});
it("fires onIdle when the queue drains", async () => {
const deliver = vi.fn(async () => await new Promise((resolve) => setTimeout(resolve, 5)));
const deliver: Parameters<typeof createReplyDispatcher>[0]["deliver"] = async () =>
await new Promise((resolve) => setTimeout(resolve, 5));
const onIdle = vi.fn();
const dispatcher = createReplyDispatcher({ deliver, onIdle });

View File

@@ -369,9 +369,9 @@ describe("createTypingSignaler", () => {
});
await signaler.signalTextDelta("hello");
typing.startTypingLoop.mockClear();
typing.startTypingOnText.mockClear();
typing.refreshTypingTtl.mockClear();
(typing.startTypingLoop as ReturnType<typeof vi.fn>).mockClear();
(typing.startTypingOnText as ReturnType<typeof vi.fn>).mockClear();
(typing.refreshTypingTtl as ReturnType<typeof vi.fn>).mockClear();
await signaler.signalToolStart();
expect(typing.refreshTypingTtl).toHaveBeenCalled();

View File

@@ -64,6 +64,9 @@ const { routeReply } = await import("./route-reply.js");
const createRegistry = (channels: PluginRegistry["channels"]): PluginRegistry => ({
plugins: [],
tools: [],
hooks: [],
typedHooks: [],
commands: [],
channels,
providers: [],
gatewayHandlers: {},

View File

@@ -132,7 +132,9 @@ describe("buildStatusMessage", () => {
sessionKey: "agent:main:main",
queue: { mode: "none" },
mediaDecisions: [
createSuccessfulImageMediaDecision(),
createSuccessfulImageMediaDecision() as unknown as NonNullable<
Parameters<typeof buildStatusMessage>[0]["mediaDecisions"]
>[number],
{
capability: "audio",
outcome: "skipped",