chore: Fix types in tests 29/N.

This commit is contained in:
cpojer
2026-02-17 14:32:43 +09:00
parent 03e6acd051
commit ecf1c955a1
12 changed files with 67 additions and 35 deletions

View File

@@ -49,7 +49,7 @@ describe("fetchBrowserJson loopback auth", () => {
});
it("adds bearer auth for loopback absolute HTTP URLs", async () => {
const fetchMock = vi.fn(
const fetchMock = vi.fn<(input: RequestInfo | URL, init?: RequestInit) => Promise<Response>>(
async () =>
new Response(JSON.stringify({ ok: true }), {
status: 200,
@@ -61,13 +61,13 @@ describe("fetchBrowserJson loopback auth", () => {
const res = await fetchBrowserJson<{ ok: boolean }>("http://127.0.0.1:18888/");
expect(res.ok).toBe(true);
const init = fetchMock.mock.calls[0]?.[1] as RequestInit;
const init = fetchMock.mock.calls[0]?.[1];
const headers = new Headers(init?.headers);
expect(headers.get("authorization")).toBe("Bearer loopback-token");
});
it("does not inject auth for non-loopback absolute URLs", async () => {
const fetchMock = vi.fn(
const fetchMock = vi.fn<(input: RequestInfo | URL, init?: RequestInit) => Promise<Response>>(
async () =>
new Response(JSON.stringify({ ok: true }), {
status: 200,
@@ -78,13 +78,13 @@ describe("fetchBrowserJson loopback auth", () => {
await fetchBrowserJson<{ ok: boolean }>("http://example.com/");
const init = fetchMock.mock.calls[0]?.[1] as RequestInit;
const init = fetchMock.mock.calls[0]?.[1];
const headers = new Headers(init?.headers);
expect(headers.get("authorization")).toBeNull();
});
it("keeps caller-supplied auth header", async () => {
const fetchMock = vi.fn(
const fetchMock = vi.fn<(input: RequestInfo | URL, init?: RequestInit) => Promise<Response>>(
async () =>
new Response(JSON.stringify({ ok: true }), {
status: 200,
@@ -99,7 +99,7 @@ describe("fetchBrowserJson loopback auth", () => {
},
});
const init = fetchMock.mock.calls[0]?.[1] as RequestInit;
const init = fetchMock.mock.calls[0]?.[1];
const headers = new Headers(init?.headers);
expect(headers.get("authorization")).toBe("Bearer caller-token");
});

View File

@@ -51,7 +51,7 @@ describe("pw-tools-core", () => {
});
const res = await p;
const outPath = vi.mocked(saveAs).mock.calls[0]?.[0];
const outPath = (vi.mocked(saveAs).mock.calls as unknown as Array<[string]>)[0]?.[0];
return { res, outPath };
}

View File

@@ -57,7 +57,7 @@ describe("server-context hot-reload profiles", () => {
const resolved = resolveBrowserConfig(cfg.browser, cfg);
// Verify cache is primed (without desktop)
expect(cfg.browser.profiles.desktop).toBeUndefined();
expect(cfg.browser?.profiles?.desktop).toBeUndefined();
const state = {
server: null,
port: 18791,
@@ -79,7 +79,7 @@ describe("server-context hot-reload profiles", () => {
// 3. Verify without clearConfigCache, loadConfig() still returns stale cached value
const staleCfg = loadConfig();
expect(staleCfg.browser.profiles.desktop).toBeUndefined(); // Cache is stale!
expect(staleCfg.browser?.profiles?.desktop).toBeUndefined(); // Cache is stale!
// 4. Hot-reload should read fresh config for the lookup (createConfigIO().loadConfig()),
// without flushing the global loadConfig cache.
@@ -97,7 +97,7 @@ describe("server-context hot-reload profiles", () => {
// 6. Verify GLOBAL cache was NOT cleared - subsequent simple loadConfig() still sees STALE value
// This confirms the fix: we read fresh config for the specific profile lookup without flushing the global cache
const stillStaleCfg = loadConfig();
expect(stillStaleCfg.browser.profiles.desktop).toBeUndefined();
expect(stillStaleCfg.browser?.profiles?.desktop).toBeUndefined();
});
it("forProfile still throws for profiles that don't exist in fresh config", async () => {

View File

@@ -27,6 +27,8 @@ function makeState(
cdpIsLoopback: profile !== "remote",
remoteCdpTimeoutMs: 1500,
remoteCdpHandshakeTimeoutMs: 3000,
evaluateEnabled: false,
extraArgs: [],
color: "#FF4500",
headless: true,
noSandbox: false,
@@ -62,7 +64,7 @@ describe("browser server-context remote profile tab operations", () => {
listPagesViaPlaywright,
createPageViaPlaywright,
closePageByTargetIdViaPlaywright,
} as Awaited<ReturnType<typeof pwAiModule.getPwAiModule>>);
} as unknown as Awaited<ReturnType<typeof pwAiModule.getPwAiModule>>);
const fetchMock = vi.fn(async () => {
throw new Error("unexpected fetch");
@@ -127,7 +129,7 @@ describe("browser server-context remote profile tab operations", () => {
closePageByTargetIdViaPlaywright: vi.fn(async () => {
throw new Error("unexpected close");
}),
} as Awaited<ReturnType<typeof pwAiModule.getPwAiModule>>);
} as unknown as Awaited<ReturnType<typeof pwAiModule.getPwAiModule>>);
const fetchMock = vi.fn(async () => {
throw new Error("unexpected fetch");
@@ -154,7 +156,7 @@ describe("browser server-context remote profile tab operations", () => {
vi.spyOn(pwAiModule, "getPwAiModule").mockResolvedValue({
listPagesViaPlaywright,
focusPageByTargetIdViaPlaywright,
} as Awaited<ReturnType<typeof pwAiModule.getPwAiModule>>);
} as unknown as Awaited<ReturnType<typeof pwAiModule.getPwAiModule>>);
const fetchMock = vi.fn(async () => {
throw new Error("unexpected fetch");
@@ -180,7 +182,7 @@ describe("browser server-context remote profile tab operations", () => {
listPagesViaPlaywright: vi.fn(async () => {
throw new Error("boom");
}),
} as Awaited<ReturnType<typeof pwAiModule.getPwAiModule>>);
} as unknown as Awaited<ReturnType<typeof pwAiModule.getPwAiModule>>);
const fetchMock = vi.fn(async () => {
throw new Error("unexpected fetch");

View File

@@ -43,7 +43,7 @@ function mockConfig(
home: string,
storePath: string,
agentOverrides?: Partial<NonNullable<NonNullable<OpenClawConfig["agents"]>["defaults"]>>,
telegramOverrides?: Partial<NonNullable<OpenClawConfig["telegram"]>>,
telegramOverrides?: Partial<NonNullable<NonNullable<OpenClawConfig["channels"]>["telegram"]>>,
agentsList?: Array<{ id: string; default?: boolean }>,
) {
configSpy.mockReturnValue({
@@ -57,7 +57,9 @@ function mockConfig(
list: agentsList,
},
session: { store: storePath, mainKey: "main" },
telegram: telegramOverrides ? { ...telegramOverrides } : undefined,
channels: {
telegram: telegramOverrides ? { ...telegramOverrides } : undefined,
},
});
}
@@ -342,7 +344,7 @@ describe("agentCommand", () => {
await agentCommand({ message: "hi", to: "+1999", json: true }, runtime);
const logged = (runtime.log as MockInstance).mock.calls.at(-1)?.[0] as string;
const logged = (runtime.log as unknown as MockInstance).mock.calls.at(-1)?.[0] as string;
const parsed = JSON.parse(logged) as {
payloads: Array<{ text: string; mediaUrl?: string | null }>;
meta: { durationMs: number };
@@ -376,6 +378,7 @@ describe("agentCommand", () => {
const deps = {
sendMessageWhatsApp: vi.fn(),
sendMessageTelegram: vi.fn().mockResolvedValue({ messageId: "t1", chatId: "123" }),
sendMessageSlack: vi.fn(),
sendMessageDiscord: vi.fn(),
sendMessageSignal: vi.fn(),
sendMessageIMessage: vi.fn(),

View File

@@ -29,22 +29,22 @@ vi.mock("../web/session.js", () => ({
webAuthExists,
}));
const handleDiscordAction = vi.fn(async () => ({ details: { ok: true } }));
const handleDiscordAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
vi.mock("../agents/tools/discord-actions.js", () => ({
handleDiscordAction,
}));
const handleSlackAction = vi.fn(async () => ({ details: { ok: true } }));
const handleSlackAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
vi.mock("../agents/tools/slack-actions.js", () => ({
handleSlackAction,
}));
const handleTelegramAction = vi.fn(async () => ({ details: { ok: true } }));
const handleTelegramAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
vi.mock("../agents/tools/telegram-actions.js", () => ({
handleTelegramAction,
}));
const handleWhatsAppAction = vi.fn(async () => ({ details: { ok: true } }));
const handleWhatsAppAction = vi.fn(async (..._args: unknown[]) => ({ details: { ok: true } }));
vi.mock("../agents/tools/whatsapp-actions.js", () => ({
handleWhatsAppAction,
}));

View File

@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
import path from "node:path";
import type { OAuthCredentials } from "@mariozechner/pi-ai";
import { afterEach, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import {
applyAuthProfileConfig,
applyLitellmProviderConfig,
@@ -36,12 +37,12 @@ import {
function createLegacyProviderConfig(params: {
providerId: string;
api: string;
api: "anthropic-messages" | "openai-completions" | "openai-responses";
modelId?: string;
modelName?: string;
baseUrl?: string;
apiKey?: string;
}) {
}): OpenClawConfig {
return {
models: {
providers: {
@@ -63,7 +64,7 @@ function createLegacyProviderConfig(params: {
},
},
},
};
} as OpenClawConfig;
}
const EXPECTED_FALLBACKS = ["anthropic/claude-opus-4-5"] as const;

View File

@@ -115,7 +115,7 @@ describe("resolveChannelCapabilities", () => {
capabilities: { inlineButtons: "dm" },
},
},
};
} as unknown as Partial<OpenClawConfig>;
// Should return undefined (not crash), allowing channel-specific handlers to process it.
expect(

View File

@@ -1,6 +1,10 @@
import { describe, expect, it } from "vitest";
import { migrateLegacyConfig, validateConfigObject } from "./config.js";
function getLegacyRouting(config: unknown) {
return (config as { routing?: Record<string, unknown> } | undefined)?.routing;
}
describe("legacy config detection", () => {
it("rejects routing.allowFrom", async () => {
const res = validateConfigObject({
@@ -27,7 +31,7 @@ describe("legacy config detection", () => {
});
expect(res.changes).toContain("Moved routing.allowFrom → channels.whatsapp.allowFrom.");
expect(res.config?.channels?.whatsapp?.allowFrom).toEqual(["+15555550123"]);
expect(res.config?.routing?.allowFrom).toBeUndefined();
expect(getLegacyRouting(res.config)?.allowFrom).toBeUndefined();
});
it("drops routing.allowFrom when whatsapp missing", async () => {
const res = migrateLegacyConfig({
@@ -35,7 +39,7 @@ describe("legacy config detection", () => {
});
expect(res.changes).toContain("Removed routing.allowFrom (channels.whatsapp not configured).");
expect(res.config?.channels?.whatsapp).toBeUndefined();
expect(res.config?.routing?.allowFrom).toBeUndefined();
expect(getLegacyRouting(res.config)?.allowFrom).toBeUndefined();
});
it("migrates routing.groupChat.requireMention to channels whatsapp/telegram/imessage groups when whatsapp configured", async () => {
const res = migrateLegacyConfig({
@@ -54,7 +58,7 @@ describe("legacy config detection", () => {
expect(res.config?.channels?.whatsapp?.groups?.["*"]?.requireMention).toBe(false);
expect(res.config?.channels?.telegram?.groups?.["*"]?.requireMention).toBe(false);
expect(res.config?.channels?.imessage?.groups?.["*"]?.requireMention).toBe(false);
expect(res.config?.routing?.groupChat?.requireMention).toBeUndefined();
expect(getLegacyRouting(res.config)?.groupChat).toBeUndefined();
});
it("migrates routing.groupChat.requireMention to telegram/imessage when whatsapp missing", async () => {
const res = migrateLegacyConfig({
@@ -72,7 +76,7 @@ describe("legacy config detection", () => {
expect(res.config?.channels?.whatsapp).toBeUndefined();
expect(res.config?.channels?.telegram?.groups?.["*"]?.requireMention).toBe(false);
expect(res.config?.channels?.imessage?.groups?.["*"]?.requireMention).toBe(false);
expect(res.config?.routing?.groupChat?.requireMention).toBeUndefined();
expect(getLegacyRouting(res.config)?.groupChat).toBeUndefined();
});
it("migrates routing.groupChat.mentionPatterns to messages.groupChat.mentionPatterns", async () => {
const res = migrateLegacyConfig({
@@ -82,7 +86,7 @@ describe("legacy config detection", () => {
"Moved routing.groupChat.mentionPatterns → messages.groupChat.mentionPatterns.",
);
expect(res.config?.messages?.groupChat?.mentionPatterns).toEqual(["@openclaw"]);
expect(res.config?.routing?.groupChat?.mentionPatterns).toBeUndefined();
expect(getLegacyRouting(res.config)?.groupChat).toBeUndefined();
});
it("migrates routing agentToAgent/queue/transcribeAudio to tools/messages/media", async () => {
const res = migrateLegacyConfig({
@@ -117,7 +121,7 @@ describe("legacy config detection", () => {
},
],
});
expect(res.config?.routing).toBeUndefined();
expect(getLegacyRouting(res.config)).toBeUndefined();
});
it("migrates audio.transcription with custom script names", async () => {
const res = migrateLegacyConfig({

View File

@@ -65,7 +65,17 @@ describe("applyModelDefaults", () => {
baseUrl: "https://proxy.example/v1",
apiKey: "sk-test",
api: "openai-completions",
models: [{ id: "gpt-5.2", name: "GPT-5.2" }],
models: [
{
id: "gpt-5.2",
name: "GPT-5.2",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 200_000,
maxTokens: 8192,
},
],
},
},
},
@@ -86,8 +96,20 @@ describe("applyModelDefaults", () => {
models: {
providers: {
myproxy: {
baseUrl: "https://proxy.example/v1",
apiKey: "sk-test",
api: "openai-completions",
models: [{ id: "gpt-5.2", name: "GPT-5.2", contextWindow: 32768, maxTokens: 40960 }],
models: [
{
id: "gpt-5.2",
name: "GPT-5.2",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 32768,
maxTokens: 40960,
},
],
},
},
},

View File

@@ -33,7 +33,7 @@ function makeSnapshot<TConfig extends Record<string, unknown>>(
issues: [],
warnings: [],
legacyIssues: [],
} as TestSnapshot<TConfig>;
} as unknown as TestSnapshot<TConfig>;
}
function restoreRedactedValues<TOriginal>(

View File

@@ -151,7 +151,7 @@ describe("resolveCronSession", () => {
updatedAt: Date.now() - 1000,
modelOverride: "some-model",
},
} as ReturnType<typeof loadSessionStore>);
} as unknown as ReturnType<typeof loadSessionStore>);
vi.mocked(evaluateSessionFreshness).mockReturnValue({ fresh: true });
const result = resolveCronSession({