chore: Fix types in tests 38/N.

This commit is contained in:
cpojer
2026-02-17 15:47:23 +09:00
parent 238718c1d8
commit 084e39b519
19 changed files with 85 additions and 40 deletions

View File

@@ -7,10 +7,15 @@ function createLimiterSpy(): AuthRateLimiter & {
recordFailure: ReturnType<typeof vi.fn>;
reset: ReturnType<typeof vi.fn>;
} {
const check = vi.fn<AuthRateLimiter["check"]>(
(_ip, _scope) => ({ allowed: true, remaining: 10, retryAfterMs: 0 }) as const,
);
const recordFailure = vi.fn<AuthRateLimiter["recordFailure"]>((_ip, _scope) => {});
const reset = vi.fn<AuthRateLimiter["reset"]>((_ip, _scope) => {});
return {
check: vi.fn(() => ({ allowed: true, remaining: 10, retryAfterMs: 0 })),
recordFailure: vi.fn(),
reset: vi.fn(),
check,
recordFailure,
reset,
size: () => 0,
prune: () => {},
dispose: () => {},

View File

@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { SessionScope } from "../config/sessions/types.js";
const agentCommand = vi.fn();
@@ -14,7 +15,12 @@ const { resolveStorePath } = await import("../config/sessions/paths.js");
const { loadSessionStore, saveSessionStore } = await import("../config/sessions/store.js");
describe("runBootOnce", () => {
const resolveMainStore = (cfg: { session?: { store?: string } } = {}) => {
const resolveMainStore = (
cfg: {
session?: { store?: string; scope?: SessionScope; mainKey?: string };
agents?: { list?: Array<{ id?: string; default?: boolean }> };
} = {},
) => {
const sessionKey = resolveMainSessionKey(cfg);
const agentId = resolveAgentIdFromSessionKey(sessionKey);
const storePath = resolveStorePath(cfg.session?.store, { agentId });

View File

@@ -7,6 +7,7 @@ import { parseModelRef } from "../agents/model-selection.js";
import { loadConfig } from "../config/config.js";
import { isTruthyEnvValue } from "../infra/env.js";
import { getFreePortBlockWithPermissionFallback } from "../test-utils/ports.js";
import { GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
import { GatewayClient } from "./client.js";
import { renderCatNoncePngBase64 } from "./live-image-probe.js";
import { startGatewayServer } from "./server.js";
@@ -144,7 +145,7 @@ async function connectClient(params: { url: string; token: string }) {
const client = new GatewayClient({
url: params.url,
token: params.token,
clientName: "vitest-live-cli-backend",
clientName: GATEWAY_CLIENT_NAMES.TEST,
clientVersion: "dev",
mode: "test",
onHelloOk: () => stop(undefined, client),

View File

@@ -36,11 +36,10 @@ describe("GatewayClient", () => {
wsMockState.last = null;
const client = new GatewayClient({ url: "ws://127.0.0.1:1" });
client.start();
const last = wsMockState.last as { url: unknown; opts: unknown } | null;
expect(wsMockState.last?.url).toBe("ws://127.0.0.1:1");
expect(wsMockState.last?.opts).toEqual(
expect.objectContaining({ maxPayload: 25 * 1024 * 1024 }),
);
expect(last?.url).toBe("ws://127.0.0.1:1");
expect(last?.opts).toEqual(expect.objectContaining({ maxPayload: 25 * 1024 * 1024 }));
});
});
@@ -153,7 +152,8 @@ describe("late-arriving invoke results", () => {
context,
});
const [ok, payload, error] = respond.mock.lastCall ?? [];
const [ok, rawPayload, error] = respond.mock.lastCall ?? [];
const payload = rawPayload as { ok?: boolean; ignored?: boolean } | undefined;
// Late-arriving results return success instead of error to reduce log noise.
expect(ok).toBe(true);

View File

@@ -22,7 +22,7 @@ import { getApiKeyForModel } from "../agents/model-auth.js";
import { ensureOpenClawModelsJson } from "../agents/models-config.js";
import { discoverAuthStorage, discoverModels } from "../agents/pi-model-discovery.js";
import { loadConfig } from "../config/config.js";
import type { OpenClawConfig, ModelProviderConfig } from "../config/types.js";
import type { ModelsConfig, OpenClawConfig, ModelProviderConfig } from "../config/types.js";
import { isTruthyEnvValue } from "../infra/env.js";
import { DEFAULT_AGENT_ID } from "../routing/session-key.js";
import { GATEWAY_CLIENT_MODES, GATEWAY_CLIENT_NAMES } from "../utils/message-channel.js";
@@ -401,6 +401,7 @@ function buildLiveGatewayConfig(params: {
...providerOverrides,
};
const providers = Object.keys(nextProviders).length > 0 ? nextProviders : baseProviders;
const baseModels = params.cfg.models;
return {
...params.cfg,
agents: {
@@ -418,7 +419,9 @@ function buildLiveGatewayConfig(params: {
},
},
models:
Object.keys(providers).length > 0 ? { ...params.cfg.models, providers } : params.cfg.models,
Object.keys(providers).length > 0
? ({ ...baseModels, providers } as ModelsConfig)
: baseModels,
};
}
@@ -1149,10 +1152,10 @@ describeLive("gateway live (dev agent, profile keys)", () => {
await fs.writeFile(toolProbePath, `nonceA=${nonceA}\nnonceB=${nonceB}\n`);
const port = await getFreeGatewayPort();
const server = await startGatewayServer({
configPath: cfg.__meta?.path,
port,
token,
const server = await startGatewayServer(port, {
bind: "loopback",
auth: { mode: "token", token },
controlUiEnabled: false,
});
const client = await connectClient({

View File

@@ -109,7 +109,7 @@ describe("hooks mapping", () => {
],
});
expect(result?.ok).toBe(true);
if (result?.ok && result.action.kind === "agent") {
if (result?.ok && result.action && result.action.kind === "agent") {
expect(result.action.model).toBe("openai/gpt-4.1-mini");
}
});

View File

@@ -126,7 +126,8 @@ function createErrnoError(code: string) {
}
function mockWorkspaceStateRead(params: { onboardingCompletedAt?: string; errorCode?: string }) {
mocks.fsReadFile.mockImplementation(async (filePath: string | URL | number) => {
mocks.fsReadFile.mockImplementation(async (...args: unknown[]) => {
const filePath = args[0];
if (String(filePath).endsWith("workspace-state.json")) {
if (params.errorCode) {
throw createErrnoError(params.errorCode);

View File

@@ -107,6 +107,9 @@ describe("chat abort transcript persistence", () => {
params: { sessionKey: "main", runId },
respond,
context: context as never,
req: {} as never,
client: null,
isWebchatConnect: () => false,
});
const [ok1, payload1] = respond.mock.calls.at(-1) ?? [];
@@ -121,6 +124,9 @@ describe("chat abort transcript persistence", () => {
params: { sessionKey: "main", runId },
respond,
context: context as never,
req: {} as never,
client: null,
isWebchatConnect: () => false,
});
const lines = await readTranscriptLines(transcriptPath);
@@ -178,6 +184,9 @@ describe("chat abort transcript persistence", () => {
params: { sessionKey: "main" },
respond,
context: context as never,
req: {} as never,
client: null,
isWebchatConnect: () => false,
});
const [ok, payload] = respond.mock.calls.at(-1) ?? [];
@@ -235,7 +244,9 @@ describe("chat abort transcript persistence", () => {
},
respond,
context: context as never,
client: undefined,
req: {} as never,
client: null,
isWebchatConnect: () => false,
});
const [ok, payload] = respond.mock.calls.at(-1) ?? [];

View File

@@ -26,7 +26,7 @@ describe("gateway chat.inject transcript writes", () => {
);
vi.doMock("../session-utils.js", async (importOriginal) => {
const original = await importOriginal();
const original = await importOriginal<typeof import("../session-utils.js")>();
return {
...original,
loadSessionEntry: () => ({
@@ -50,7 +50,10 @@ describe("gateway chat.inject transcript writes", () => {
await chatHandlers["chat.inject"]({
params: { sessionKey: "k1", message: "hello" },
respond,
context,
req: {} as never,
client: null as never,
isWebchatConnect: () => false,
context: context as unknown as GatewayRequestContext,
});
expect(respond).toHaveBeenCalled();

View File

@@ -28,6 +28,10 @@ describe("skills.update", () => {
skillKey: "brave-search",
apiKey: "abc\r\ndef",
},
req: {} as never,
client: null as never,
isWebchatConnect: () => false,
context: {} as never,
respond: (success, _result, err) => {
ok = success;
error = err;

View File

@@ -106,7 +106,9 @@ describe("sessions.usage", () => {
expect(respond).toHaveBeenCalledTimes(1);
expect(respond.mock.calls[0]?.[0]).toBe(true);
const result = respond.mock.calls[0]?.[1] as unknown as { sessions: Array<unknown> };
const result = respond.mock.calls[0]?.[1] as unknown as {
sessions: Array<{ key: string; agentId: string }>;
};
expect(result.sessions).toHaveLength(2);
// Sorted by most recent first (mtime=200 -> opus first).

View File

@@ -1,4 +1,5 @@
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../config/config.js";
vi.mock("../../infra/session-cost-usage.js", async () => {
const actual = await vi.importActual<typeof import("../../infra/session-cost-usage.js")>(
@@ -63,7 +64,7 @@ describe("gateway usage helpers", () => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-02-05T00:00:00.000Z"));
const config = {} as unknown as ReturnType<import("../../config/config.js").loadConfig>;
const config = {} as OpenClawConfig;
const a = await __test.loadCostUsageSummaryCached({
startMs: 1,
endMs: 2,

View File

@@ -15,6 +15,7 @@ const createRegistry = (diagnostics: PluginDiagnostic[]): PluginRegistry => ({
hooks: [],
typedHooks: [],
channels: [],
commands: [],
providers: [],
gatewayHandlers: {},
httpHandlers: [],

View File

@@ -306,9 +306,14 @@ describe("gateway server agent", () => {
const ack = await ackP;
const final = await finalP;
expect(ack.payload.runId).toBeDefined();
expect(final.payload.runId).toBe(ack.payload.runId);
expect(final.payload.status).toBe("ok");
const ackPayload = ack.payload;
const finalPayload = final.payload;
if (!ackPayload || !finalPayload) {
throw new Error("missing websocket payload");
}
expect(ackPayload.runId).toBeDefined();
expect(finalPayload.runId).toBe(ackPayload.runId);
expect(finalPayload.status).toBe("ok");
});
test("agent dedupes by idempotencyKey after completion", async () => {

View File

@@ -63,6 +63,7 @@ async function withCanvasGatewayHarness(params: {
const canvasWss = new WebSocketServer({ noServer: true });
const canvasHost: CanvasHostHandler = {
rootDir: "test",
basePath: "/canvas",
close: async () => {},
handleUpgrade: (req, socket, head) => {
const url = new URL(req.url ?? "/", "http://localhost");

View File

@@ -270,7 +270,7 @@ describe("gateway server chat", () => {
test("smoke: supports abort and idempotent completion", async () => {
const tempDirs: string[] = [];
const { server, ws } = await startServerWithClient();
const spy = vi.mocked(getReplyFromConfig);
const spy = vi.mocked(getReplyFromConfig) as unknown as ReturnType<typeof vi.fn>;
let aborted = false;
try {

View File

@@ -44,10 +44,10 @@ describe("gateway config.apply", () => {
},
}),
);
const res = await onceMessage<{ ok: boolean; error?: { message?: string } }>(
ws,
(o) => o.type === "res" && o.id === id,
);
const res = await onceMessage<{ ok: boolean; error?: { message?: string } }>(ws, (o) => {
const msg = o as { type?: string; id?: string };
return msg.type === "res" && msg.id === id;
});
expect(res.ok).toBe(false);
expect(res.error?.message ?? "").toMatch(/invalid|SyntaxError/i);
} finally {
@@ -69,10 +69,10 @@ describe("gateway config.apply", () => {
},
}),
);
const res = await onceMessage<{ ok: boolean; error?: { message?: string } }>(
ws,
(o) => o.type === "res" && o.id === id,
);
const res = await onceMessage<{ ok: boolean; error?: { message?: string } }>(ws, (o) => {
const msg = o as { type?: string; id?: string };
return msg.type === "res" && msg.id === id;
});
expect(res.ok).toBe(false);
expect(res.error?.message ?? "").toContain("raw");
} finally {

View File

@@ -561,7 +561,7 @@ describe("gateway server cron", () => {
await yieldToEventLoop();
expect(fetchMock).toHaveBeenCalledTimes(2);
cronIsolatedRun.mockResolvedValueOnce({ status: "ok" });
cronIsolatedRun.mockResolvedValueOnce({ status: "ok", summary: "" });
const noSummaryRes = await rpcReq(ws, "cron.add", {
name: "webhook no summary",
enabled: true,

View File

@@ -268,10 +268,11 @@ describe("node.invoke approval bypass", () => {
});
expect(invoke.ok).toBe(true);
expect(lastInvokeParams).toBeTruthy();
expect(lastInvokeParams?.approved).toBe(true);
expect(lastInvokeParams?.approvalDecision).toBe("allow-once");
expect(lastInvokeParams?.injected).toBeUndefined();
const invokeParams = lastInvokeParams as Record<string, unknown> | null;
expect(invokeParams).toBeTruthy();
expect(invokeParams?.["approved"]).toBe(true);
expect(invokeParams?.["approvalDecision"]).toBe("allow-once");
expect(invokeParams?.["injected"]).toBeUndefined();
ws.close();
ws2.close();