mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 16:44:45 +00:00
test: clear broad mock helper lint
This commit is contained in:
@@ -206,7 +206,7 @@ function requireRecord(value: unknown, label: string): Record<string, unknown> {
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function requireFirstCallArg<T>(mock: unknown, label: string): T {
|
||||
function requireFirstCallArg<T>(mock: unknown, label: string, _type?: (value: T) => T): T {
|
||||
const call = (mock as MockCallReader).mock.calls.at(0);
|
||||
if (!call) {
|
||||
throw new Error(`expected ${label} to be called`);
|
||||
@@ -238,7 +238,7 @@ function expectRequestInputTextContains(
|
||||
expect(
|
||||
input.some((entry) => {
|
||||
const item = requireRecord(entry, "turn/start input entry");
|
||||
return item.type === "text" && String(item.text ?? "").includes(expected);
|
||||
return item.type === "text" && typeof item.text === "string" && item.text.includes(expected);
|
||||
}),
|
||||
).toBe(true);
|
||||
}
|
||||
@@ -297,7 +297,8 @@ describe("runCodexAppServerAttempt context-engine lifecycle", () => {
|
||||
expect(assembleParams.availableTools).toEqual(new Set());
|
||||
|
||||
const threadStartParams = requireRequestParams(harness, "thread/start");
|
||||
expect(String(threadStartParams.developerInstructions ?? "")).toContain(
|
||||
const developerInstructions = threadStartParams.developerInstructions;
|
||||
expect(typeof developerInstructions === "string" ? developerInstructions : "").toContain(
|
||||
"context-engine system",
|
||||
);
|
||||
expectRequestInputTextContains(harness, "OpenClaw assembled context for this turn:");
|
||||
|
||||
@@ -105,7 +105,9 @@ function createConfigWithDiscordAccount(overrides: Record<string, unknown> = {})
|
||||
type MockCallReader = { mock: { calls: unknown[][] } };
|
||||
|
||||
function mockMessages(mock: unknown): string[] {
|
||||
return (mock as MockCallReader).mock.calls.map((call) => String(call[0] ?? ""));
|
||||
return (mock as MockCallReader).mock.calls.map((call) =>
|
||||
typeof call[0] === "string" ? call[0] : "",
|
||||
);
|
||||
}
|
||||
|
||||
function expectMockLogContains(mock: unknown, expected: string): void {
|
||||
|
||||
@@ -215,7 +215,12 @@ function setupRuntimeMediaMocks(params: { loadFileName: string; loadBytes: strin
|
||||
return { loadOutboundMediaFromUrl, fetchRemoteMedia };
|
||||
}
|
||||
|
||||
function requireMockArg<T>(mock: ReturnType<typeof vi.fn>, callIndex = 0, argIndex = 0): T {
|
||||
function requireMockArg<T>(
|
||||
mock: ReturnType<typeof vi.fn>,
|
||||
callIndex = 0,
|
||||
argIndex = 0,
|
||||
_type?: (value: T) => T,
|
||||
): T {
|
||||
const call = mock.mock.calls[callIndex];
|
||||
if (!call) {
|
||||
throw new Error(`expected mock call ${callIndex}`);
|
||||
@@ -223,7 +228,11 @@ function requireMockArg<T>(mock: ReturnType<typeof vi.fn>, callIndex = 0, argInd
|
||||
return call[argIndex] as T;
|
||||
}
|
||||
|
||||
function requireMockArgs<T extends unknown[]>(mock: ReturnType<typeof vi.fn>, callIndex = 0): T {
|
||||
function requireMockArgs<T extends unknown[]>(
|
||||
mock: ReturnType<typeof vi.fn>,
|
||||
callIndex = 0,
|
||||
_type?: (value: T) => T,
|
||||
): T {
|
||||
const call = mock.mock.calls[callIndex];
|
||||
if (!call) {
|
||||
throw new Error(`expected mock call ${callIndex}`);
|
||||
|
||||
@@ -129,7 +129,7 @@ describe("irc inbound behavior", () => {
|
||||
expect.stringContaining("Your IRC id: alice!ident@example.com"),
|
||||
undefined,
|
||||
);
|
||||
const replyMessages = sendReply.mock.calls.map((call) => String(call[1]));
|
||||
const replyMessages = (sendReply.mock.calls as unknown[][]).map((call) => String(call[1]));
|
||||
expect(replyMessages.some((message) => message.includes("CODE"))).toBe(true);
|
||||
});
|
||||
|
||||
@@ -185,7 +185,9 @@ describe("irc inbound behavior", () => {
|
||||
sendReply: vi.fn(async () => {}),
|
||||
});
|
||||
|
||||
const assembledRequest = coreRuntime.channel.turn.runAssembled.mock.calls[0]?.[0];
|
||||
const assembledRequest = (
|
||||
coreRuntime.channel.turn.runAssembled as unknown as { mock: { calls: unknown[][] } }
|
||||
).mock.calls[0]?.[0] as { replyPipeline?: unknown } | undefined;
|
||||
expect(assembledRequest?.replyPipeline).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -609,7 +609,7 @@ describe("handleLineWebhookEvents", () => {
|
||||
});
|
||||
|
||||
expect(processMessage).not.toHaveBeenCalled();
|
||||
const pairingRequest = upsertPairingRequestMock.mock.calls[0]?.[0] as
|
||||
const pairingRequest = (upsertPairingRequestMock.mock.calls as unknown[][])[0]?.[0] as
|
||||
| { accountId?: string; channel?: string; id?: string }
|
||||
| undefined;
|
||||
expect(pairingRequest?.channel).toBe("line");
|
||||
@@ -656,7 +656,7 @@ describe("handleLineWebhookEvents", () => {
|
||||
|
||||
expect(readAllowFromStoreMock).toHaveBeenCalledWith("line", undefined, "work");
|
||||
expect(processMessage).not.toHaveBeenCalled();
|
||||
const pairingRequest = upsertPairingRequestMock.mock.calls[0]?.[0] as
|
||||
const pairingRequest = (upsertPairingRequestMock.mock.calls as unknown[][])[0]?.[0] as
|
||||
| { accountId?: string; channel?: string; id?: string }
|
||||
| undefined;
|
||||
expect(pairingRequest?.channel).toBe("line");
|
||||
|
||||
@@ -466,7 +466,9 @@ describe("linePlugin gateway.startAccount", () => {
|
||||
await vi.waitFor(() => {
|
||||
expect(monitorLineProvider).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
const startupParams = monitorLineProvider.mock.calls[0]?.[0];
|
||||
const startupParams = (monitorLineProvider.mock.calls as unknown[][])[0]?.[0] as
|
||||
| { accountId?: string; channelAccessToken?: string; channelSecret?: string }
|
||||
| undefined;
|
||||
expect(startupParams?.channelAccessToken).toBe("token");
|
||||
expect(startupParams?.channelSecret).toBe("secret");
|
||||
expect(startupParams?.accountId).toBe("default");
|
||||
|
||||
@@ -77,7 +77,7 @@ function requireCandidateKeyByPath(
|
||||
}
|
||||
|
||||
function mockStringMessages(mock: { mock: { calls: unknown[][] } }): string[] {
|
||||
return mock.mock.calls.map((call) => String(call[0] ?? ""));
|
||||
return mock.mock.calls.map((call) => (typeof call[0] === "string" ? call[0] : ""));
|
||||
}
|
||||
|
||||
function expectIncludesSubstring(values: readonly string[], expected: string): void {
|
||||
|
||||
@@ -149,7 +149,7 @@ function createCronHarness(
|
||||
}
|
||||
|
||||
function mockStringMessages(mock: { mock: { calls: unknown[][] } }): string[] {
|
||||
return mock.mock.calls.map((call) => String(call[0] ?? ""));
|
||||
return mock.mock.calls.map((call) => (typeof call[0] === "string" ? call[0] : ""));
|
||||
}
|
||||
|
||||
function expectLogContains(mock: { mock: { calls: unknown[][] } }, expected: string): void {
|
||||
|
||||
@@ -279,7 +279,9 @@ describe("nextcloud-talk inbound behavior", () => {
|
||||
runtime: createRuntimeEnv(),
|
||||
});
|
||||
|
||||
const assembledRequest = coreRuntime.channel.turn.runAssembled.mock.calls[0]?.[0];
|
||||
const assembledRequest = (
|
||||
coreRuntime.channel.turn.runAssembled as unknown as { mock: { calls: unknown[][] } }
|
||||
).mock.calls[0]?.[0] as { replyPipeline?: unknown } | undefined;
|
||||
expect(assembledRequest?.replyPipeline).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -221,7 +221,7 @@ describe("nextcloud-talk send cfg threading", () => {
|
||||
expect(mediaSendCall?.[0]).toBe(
|
||||
"https://nextcloud.example.com/ocs/v2.php/apps/spreed/api/v1/bot/abc123/message",
|
||||
);
|
||||
expect((mediaSendCall?.[1] as RequestInit | undefined)?.body).toBe(
|
||||
expect(mediaSendCall?.[1]?.body).toBe(
|
||||
JSON.stringify({
|
||||
message: "image\n\nAttachment: https://example.com/image.png",
|
||||
}),
|
||||
|
||||
@@ -141,7 +141,7 @@ function expectSaveMediaBufferCall(mock: unknown, contentType: string, maxBytes:
|
||||
}
|
||||
|
||||
function expectVerboseLogContains(expected: string): void {
|
||||
const messages = vi.mocked(logVerbose).mock.calls.map((call) => String(call[0] ?? ""));
|
||||
const messages = vi.mocked(logVerbose).mock.calls.map((call) => call[0]);
|
||||
expect(messages.some((message) => message.includes(expected))).toBe(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ function expectIncludesSubstring(values: readonly string[], expected: string): v
|
||||
}
|
||||
|
||||
function mockStringMessages(mock: { mock: { calls: unknown[][] } }): string[] {
|
||||
return mock.mock.calls.map((call) => String(call[0] ?? ""));
|
||||
return mock.mock.calls.map((call) => (typeof call[0] === "string" ? call[0] : ""));
|
||||
}
|
||||
|
||||
const clientModule = await import("./client.js");
|
||||
|
||||
@@ -136,7 +136,9 @@ function requireMockCall(mock: unknown, index: number, label: string): unknown[]
|
||||
}
|
||||
|
||||
function mockMessages(mock: unknown): string[] {
|
||||
return (mock as MockCallReader).mock.calls.map((call) => String(call[0] ?? ""));
|
||||
return (mock as MockCallReader).mock.calls.map((call) =>
|
||||
typeof call[0] === "string" ? call[0] : "",
|
||||
);
|
||||
}
|
||||
|
||||
function expectMockMessageContains(mock: unknown, expected: string): void {
|
||||
|
||||
@@ -83,10 +83,10 @@ function captureDiagnosticEvents(): {
|
||||
return { events, unsubscribe };
|
||||
}
|
||||
|
||||
function mockCallArg<T>(mock: { mock: { calls: unknown[][] } }, index = 0): T {
|
||||
function mockCallArg(mock: { mock: { calls: unknown[][] } }, index = 0): unknown {
|
||||
const call = mock.mock.calls[index];
|
||||
expect(call).toBeDefined();
|
||||
return call[0] as T;
|
||||
return call[0];
|
||||
}
|
||||
|
||||
describe("AgentHarness V2 compatibility adapter", () => {
|
||||
@@ -287,11 +287,11 @@ describe("AgentHarness V2 compatibility adapter", () => {
|
||||
await expect(runAgentHarnessV2LifecycleAttempt(harness, params)).rejects.toThrow(
|
||||
"codex app-server send failed",
|
||||
);
|
||||
const cleanupInput = mockCallArg<{
|
||||
const cleanupInput = mockCallArg(cleanup) as {
|
||||
error?: unknown;
|
||||
prepared?: { lifecycleState?: string };
|
||||
session?: { lifecycleState?: string };
|
||||
}>(cleanup);
|
||||
};
|
||||
expect(cleanupInput.error).toBe(sendError);
|
||||
expect(cleanupInput.prepared?.lifecycleState).toBe("prepared");
|
||||
expect(cleanupInput.session?.lifecycleState).toBe("started");
|
||||
@@ -322,11 +322,11 @@ describe("AgentHarness V2 compatibility adapter", () => {
|
||||
await expect(runAgentHarnessV2LifecycleAttempt(harness, params)).rejects.toThrow(
|
||||
"codex app-server start failed",
|
||||
);
|
||||
const cleanupInput = mockCallArg<{
|
||||
const cleanupInput = mockCallArg(cleanup) as {
|
||||
error?: unknown;
|
||||
prepared?: { lifecycleState?: string };
|
||||
session?: unknown;
|
||||
}>(cleanup);
|
||||
};
|
||||
expect(cleanupInput.error).toBe(startError);
|
||||
expect(cleanupInput.prepared?.lifecycleState).toBe("prepared");
|
||||
expect(cleanupInput.session).toBeUndefined();
|
||||
@@ -358,12 +358,12 @@ describe("AgentHarness V2 compatibility adapter", () => {
|
||||
await expect(runAgentHarnessV2LifecycleAttempt(harness, params)).rejects.toThrow(
|
||||
"outcome classification failed",
|
||||
);
|
||||
const cleanupInput = mockCallArg<{
|
||||
const cleanupInput = mockCallArg(cleanup) as {
|
||||
error?: unknown;
|
||||
result?: unknown;
|
||||
prepared?: { lifecycleState?: string };
|
||||
session?: { lifecycleState?: string };
|
||||
}>(cleanup);
|
||||
};
|
||||
expect(cleanupInput.error).toBe(outcomeError);
|
||||
expect(cleanupInput.result).toBe(rawResult);
|
||||
expect(cleanupInput.prepared?.lifecycleState).toBe("prepared");
|
||||
|
||||
@@ -153,10 +153,10 @@ function resultDetails(result: { details?: unknown }): Record<string, unknown> {
|
||||
return result.details as Record<string, unknown>;
|
||||
}
|
||||
|
||||
function firstMockCallArg<T>(mock: { mock: { calls: unknown[][] } }): T {
|
||||
function firstMockCallArg(mock: { mock: { calls: unknown[][] } }): unknown {
|
||||
const firstCall = mock.mock.calls[0];
|
||||
expect(firstCall).toBeDefined();
|
||||
return firstCall[0] as T;
|
||||
return firstCall[0];
|
||||
}
|
||||
|
||||
function resetVideoGenerateMocks() {
|
||||
@@ -570,21 +570,22 @@ describe("createVideoGenerateTool", () => {
|
||||
}
|
||||
await scheduledWork();
|
||||
expect(saveSpy).not.toHaveBeenCalled();
|
||||
const progress = firstMockCallArg<{ runId: string; progressSummary: string }>(
|
||||
taskExecutorMocks.recordTaskRunProgressByRunId,
|
||||
);
|
||||
const progress = firstMockCallArg(taskExecutorMocks.recordTaskRunProgressByRunId) as {
|
||||
runId: string;
|
||||
progressSummary: string;
|
||||
};
|
||||
expect(progress.runId).toMatch(/^tool:video_generate:/);
|
||||
expect(progress.progressSummary).toBe("Generating video");
|
||||
const completion = firstMockCallArg<{ runId: string }>(
|
||||
taskExecutorMocks.completeTaskRunByRunId,
|
||||
);
|
||||
const completion = firstMockCallArg(taskExecutorMocks.completeTaskRunByRunId) as {
|
||||
runId: string;
|
||||
};
|
||||
expect(completion.runId).toMatch(/^tool:video_generate:/);
|
||||
const wake = firstMockCallArg<{
|
||||
const wake = firstMockCallArg(wakeSpy) as {
|
||||
handle: { taskId?: string };
|
||||
status: string;
|
||||
mediaUrls: string[];
|
||||
result: string;
|
||||
}>(wakeSpy);
|
||||
};
|
||||
expect(wake.handle.taskId).toBe("task-123");
|
||||
expect(wake.status).toBe("ok");
|
||||
expect(wake.mediaUrls).toEqual(["https://example.com/generated-lobster.mp4"]);
|
||||
@@ -959,9 +960,10 @@ describe("createVideoGenerateTool", () => {
|
||||
providerOptions: { seed: 42, draft: true },
|
||||
});
|
||||
|
||||
const input = firstMockCallArg<{ autoProviderFallback?: boolean; providerOptions?: unknown }>(
|
||||
generateSpy,
|
||||
);
|
||||
const input = firstMockCallArg(generateSpy) as {
|
||||
autoProviderFallback?: boolean;
|
||||
providerOptions?: unknown;
|
||||
};
|
||||
expect(input.autoProviderFallback).toBe(false);
|
||||
expect(input.providerOptions).toEqual({ seed: 42, draft: true });
|
||||
});
|
||||
@@ -1083,7 +1085,9 @@ describe("createVideoGenerateTool", () => {
|
||||
aspectRatio: "adaptive",
|
||||
});
|
||||
|
||||
expect(firstMockCallArg<{ aspectRatio?: string }>(generateSpy).aspectRatio).toBe("adaptive");
|
||||
expect((firstMockCallArg(generateSpy) as { aspectRatio?: string }).aspectRatio).toBe(
|
||||
"adaptive",
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts provider-specific aspectRatio and resolution values and forwards them to the runtime", async () => {
|
||||
@@ -1097,7 +1101,7 @@ describe("createVideoGenerateTool", () => {
|
||||
resolution: "draft-large",
|
||||
});
|
||||
|
||||
const input = firstMockCallArg<{ aspectRatio?: string; resolution?: string }>(generateSpy);
|
||||
const input = firstMockCallArg(generateSpy) as { aspectRatio?: string; resolution?: string };
|
||||
expect(input.aspectRatio).toBe("17:9");
|
||||
expect(input.resolution).toBe("draft-large");
|
||||
});
|
||||
|
||||
@@ -239,12 +239,12 @@ function createAdvancedFinalizeArgs(params: AdvancedFinalizeArgs = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function requireMockArg<T>(mock: ReturnType<typeof vi.fn>, callIndex = 0, argIndex = 0): T {
|
||||
function requireMockArg(mock: ReturnType<typeof vi.fn>, callIndex = 0, argIndex = 0): unknown {
|
||||
const call = mock.mock.calls[callIndex];
|
||||
if (!call) {
|
||||
throw new Error(`expected mock call ${callIndex}`);
|
||||
}
|
||||
return call[argIndex] as T;
|
||||
return call[argIndex];
|
||||
}
|
||||
|
||||
function expectNoteContains(
|
||||
@@ -253,7 +253,7 @@ function expectNoteContains(
|
||||
title: string,
|
||||
): void {
|
||||
const calls = vi.mocked(prompter.note).mock.calls;
|
||||
expect(calls.some((call) => String(call[0]).includes(expected) && call[1] === title)).toBe(true);
|
||||
expect(calls.some((call) => call[0].includes(expected) && call[1] === title)).toBe(true);
|
||||
}
|
||||
|
||||
function expectNoteTitleNotCalled(
|
||||
@@ -364,7 +364,10 @@ describe("finalizeSetupWizard", () => {
|
||||
}
|
||||
}
|
||||
|
||||
const probeParams = requireMockArg<{ url?: string; password?: string }>(probeGatewayReachable);
|
||||
const probeParams = requireMockArg(probeGatewayReachable) as {
|
||||
url?: string;
|
||||
password?: string;
|
||||
};
|
||||
expect(probeParams.url).toBe("ws://127.0.0.1:18789");
|
||||
expect(probeParams.password).toBe("resolved-gateway-password"); // pragma: allowlist secret
|
||||
expect(launchTuiCli).toHaveBeenCalledWith({
|
||||
@@ -668,18 +671,18 @@ describe("finalizeSetupWizard", () => {
|
||||
runtime: createRuntime(),
|
||||
});
|
||||
|
||||
const healthArgs = requireMockArg<{
|
||||
const healthArgs = requireMockArg(healthCommand) as {
|
||||
json?: boolean;
|
||||
timeoutMs?: number;
|
||||
token?: string;
|
||||
config?: OpenClawConfig;
|
||||
}>(healthCommand);
|
||||
};
|
||||
expect(healthArgs.json).toBe(false);
|
||||
expect(healthArgs.timeoutMs).toBe(10_000);
|
||||
expect(healthArgs.token).toBe("session-token");
|
||||
expect(healthArgs.config?.gateway?.auth?.mode).toBe("token");
|
||||
expect(healthArgs.config?.gateway?.auth?.token).toBe("session-token");
|
||||
expect(requireMockArg<unknown>(healthCommand, 0, 1)).toBeTypeOf("object");
|
||||
expect(requireMockArg(healthCommand, 0, 1)).toBeTypeOf("object");
|
||||
});
|
||||
|
||||
it("uses the resolved setup password for health checks", async () => {
|
||||
@@ -722,27 +725,27 @@ describe("finalizeSetupWizard", () => {
|
||||
runtime: createRuntime(),
|
||||
});
|
||||
|
||||
const waitArgs = requireMockArg<{
|
||||
const waitArgs = requireMockArg(waitForGatewayReachable) as {
|
||||
url?: string;
|
||||
token?: string;
|
||||
password?: string;
|
||||
}>(waitForGatewayReachable);
|
||||
};
|
||||
expect(waitArgs.url).toBe("ws://127.0.0.1:18789");
|
||||
expect(waitArgs.token).toBeUndefined();
|
||||
expect(waitArgs.password).toBe("session-password");
|
||||
const healthArgs = requireMockArg<{
|
||||
const healthArgs = requireMockArg(healthCommand) as {
|
||||
json?: boolean;
|
||||
timeoutMs?: number;
|
||||
token?: string;
|
||||
password?: string;
|
||||
config?: OpenClawConfig;
|
||||
}>(healthCommand);
|
||||
};
|
||||
expect(healthArgs.json).toBe(false);
|
||||
expect(healthArgs.timeoutMs).toBe(10_000);
|
||||
expect(healthArgs.token).toBeUndefined();
|
||||
expect(healthArgs.password).toBe("session-password");
|
||||
expect(healthArgs.config?.gateway?.auth?.mode).toBe("password");
|
||||
expect(requireMockArg<unknown>(healthCommand, 0, 1)).toBeTypeOf("object");
|
||||
expect(requireMockArg(healthCommand, 0, 1)).toBeTypeOf("object");
|
||||
});
|
||||
|
||||
it("shows actionable gateway guidance instead of a hard error in no-daemon onboarding", async () => {
|
||||
|
||||
Reference in New Issue
Block a user