mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-12 19:30:44 +00:00
test: tighten assertions and harness coverage
This commit is contained in:
@@ -111,6 +111,16 @@ type HttpInstanceLike = {
|
||||
post: (url: string, body?: unknown, options?: Record<string, unknown>) => Promise<unknown>;
|
||||
};
|
||||
|
||||
function requireHttpInstance(value: unknown): HttpInstanceLike {
|
||||
if (isRecord(value) && typeof value.get === "function" && typeof value.post === "function") {
|
||||
return {
|
||||
get: value.get as HttpInstanceLike["get"],
|
||||
post: value.post as HttpInstanceLike["post"],
|
||||
};
|
||||
}
|
||||
throw new Error("expected Feishu HTTP instance");
|
||||
}
|
||||
|
||||
function readCallOptions(
|
||||
mock: { mock: { calls: unknown[][] } },
|
||||
index = -1,
|
||||
@@ -222,25 +232,12 @@ afterAll(() => {
|
||||
});
|
||||
|
||||
describe("createFeishuClient HTTP timeout", () => {
|
||||
const getLastClientHttpInstance = (): HttpInstanceLike | undefined => {
|
||||
const httpInstance = readCallOptions(clientCtorMock).httpInstance;
|
||||
if (
|
||||
isRecord(httpInstance) &&
|
||||
typeof httpInstance.get === "function" &&
|
||||
typeof httpInstance.post === "function"
|
||||
) {
|
||||
return {
|
||||
get: httpInstance.get as HttpInstanceLike["get"],
|
||||
post: httpInstance.post as HttpInstanceLike["post"],
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
const readLastClientHttpInstance = (): HttpInstanceLike =>
|
||||
requireHttpInstance(readCallOptions(clientCtorMock).httpInstance);
|
||||
|
||||
const expectGetCallTimeout = async (timeout: number) => {
|
||||
const httpInstance = getLastClientHttpInstance();
|
||||
expect(httpInstance).toBeDefined();
|
||||
await httpInstance?.get("https://example.com/api");
|
||||
const httpInstance = readLastClientHttpInstance();
|
||||
await httpInstance.get("https://example.com/api");
|
||||
expect(mockBaseHttpInstance.get).toHaveBeenCalledWith(
|
||||
"https://example.com/api",
|
||||
expect.objectContaining({ timeout }),
|
||||
@@ -250,16 +247,18 @@ describe("createFeishuClient HTTP timeout", () => {
|
||||
it("passes a custom httpInstance with default timeout to Lark.Client", () => {
|
||||
createFeishuClient({ appId: "app_1", appSecret: "secret_1", accountId: "timeout-test" }); // pragma: allowlist secret
|
||||
|
||||
expect(readCallOptions(clientCtorMock).httpInstance).toBeDefined();
|
||||
expect(readLastClientHttpInstance()).toMatchObject({
|
||||
get: expect.any(Function),
|
||||
post: expect.any(Function),
|
||||
});
|
||||
});
|
||||
|
||||
it("injects default timeout into HTTP request options", async () => {
|
||||
createFeishuClient({ appId: "app_2", appSecret: "secret_2", accountId: "timeout-inject" }); // pragma: allowlist secret
|
||||
|
||||
const httpInstance = getLastClientHttpInstance();
|
||||
const httpInstance = readLastClientHttpInstance();
|
||||
|
||||
expect(httpInstance).toBeDefined();
|
||||
await httpInstance?.post(
|
||||
await httpInstance.post(
|
||||
"https://example.com/api",
|
||||
{ data: 1 },
|
||||
{ headers: { "X-Custom": "yes" } },
|
||||
@@ -275,10 +274,9 @@ describe("createFeishuClient HTTP timeout", () => {
|
||||
it("allows explicit timeout override per-request", async () => {
|
||||
createFeishuClient({ appId: "app_3", appSecret: "secret_3", accountId: "timeout-override" }); // pragma: allowlist secret
|
||||
|
||||
const httpInstance = getLastClientHttpInstance();
|
||||
const httpInstance = readLastClientHttpInstance();
|
||||
|
||||
expect(httpInstance).toBeDefined();
|
||||
await httpInstance?.get("https://example.com/api", { timeout: 5_000 });
|
||||
await httpInstance.get("https://example.com/api", { timeout: 5_000 });
|
||||
|
||||
expect(mockBaseHttpInstance.get).toHaveBeenCalledWith(
|
||||
"https://example.com/api",
|
||||
@@ -362,9 +360,8 @@ describe("createFeishuClient HTTP timeout", () => {
|
||||
});
|
||||
|
||||
expect(clientCtorMock.mock.calls.length).toBe(2);
|
||||
const httpInstance = getLastClientHttpInstance();
|
||||
expect(httpInstance).toBeDefined();
|
||||
await httpInstance?.get("https://example.com/api");
|
||||
const httpInstance = readLastClientHttpInstance();
|
||||
await httpInstance.get("https://example.com/api");
|
||||
|
||||
expect(mockBaseHttpInstance.get).toHaveBeenCalledWith(
|
||||
"https://example.com/api",
|
||||
|
||||
@@ -61,7 +61,6 @@ describe("createFeishuCommentReplyDispatcher", () => {
|
||||
|
||||
function latestReplyDispatcherOptions() {
|
||||
const options = createReplyDispatcherWithTypingMock.mock.calls.at(-1)?.[0];
|
||||
expect(options).toBeDefined();
|
||||
if (!options) {
|
||||
throw new Error("expected reply dispatcher options");
|
||||
}
|
||||
|
||||
@@ -163,7 +163,10 @@ describe("feishu_doc image fetch hardening", () => {
|
||||
});
|
||||
registerFeishuDocTools(harness.api);
|
||||
const tool = harness.resolveTool("feishu_doc", context);
|
||||
expect(tool).toBeDefined();
|
||||
if (!tool) {
|
||||
throw new Error("expected Feishu doc tool");
|
||||
}
|
||||
expect(tool.execute).toEqual(expect.any(Function));
|
||||
return tool;
|
||||
}
|
||||
|
||||
@@ -206,8 +209,8 @@ describe("feishu_doc image fetch hardening", () => {
|
||||
expect(blockDescendantCreateMock).toHaveBeenCalledTimes(1);
|
||||
const call = blockDescendantCreateMock.mock.calls[0]?.[0];
|
||||
expect(call?.data.children_id).toEqual(["h1", "t1", "h2"]);
|
||||
expect(call?.data.descendants).toBeDefined();
|
||||
expect(call?.data.descendants.length).toBeGreaterThanOrEqual(3);
|
||||
expect(call?.data.descendants).toEqual(expect.arrayContaining(blocks));
|
||||
expect(call?.data.descendants).toHaveLength(3);
|
||||
|
||||
expect(result.details.blocks_added).toBe(3);
|
||||
});
|
||||
|
||||
@@ -566,8 +566,10 @@ describe("sendMediaFeishu msg_type routing", () => {
|
||||
);
|
||||
expectMediaTimeoutClientConfigured();
|
||||
expect(result.buffer).toEqual(Buffer.from("image-data"));
|
||||
expect(capturedPath).toBeDefined();
|
||||
expectPathIsolatedToTmpRoot(capturedPath as string, imageKey);
|
||||
if (!capturedPath) {
|
||||
throw new Error("expected Feishu image temp path");
|
||||
}
|
||||
expectPathIsolatedToTmpRoot(capturedPath, imageKey);
|
||||
});
|
||||
|
||||
it("uses isolated temp paths for message resource downloads", async () => {
|
||||
@@ -589,8 +591,10 @@ describe("sendMediaFeishu msg_type routing", () => {
|
||||
});
|
||||
|
||||
expect(result.buffer).toEqual(Buffer.from("resource-data"));
|
||||
expect(capturedPath).toBeDefined();
|
||||
expectPathIsolatedToTmpRoot(capturedPath as string, fileKey);
|
||||
if (!capturedPath) {
|
||||
throw new Error("expected Feishu resource temp path");
|
||||
}
|
||||
expectPathIsolatedToTmpRoot(capturedPath, fileKey);
|
||||
});
|
||||
|
||||
it("rejects invalid image keys before calling feishu api", async () => {
|
||||
|
||||
@@ -188,7 +188,6 @@ describe("feishuOutbound.sendText local-image auto-convert", () => {
|
||||
throw new Error("feishuOutbound.chunker missing");
|
||||
}
|
||||
|
||||
expect(() => chunker("hello world", 5)).not.toThrow();
|
||||
expect(chunker("hello world", 5)).toEqual(["hello", "world"]);
|
||||
});
|
||||
|
||||
|
||||
@@ -298,7 +298,7 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
|
||||
expect(sendMediaFeishuMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("disables block streaming by default to prevent silent reply drops", async () => {
|
||||
it("disables block streaming by default to prevent silent reply drops", () => {
|
||||
const result = createFeishuReplyDispatcher({
|
||||
cfg: {} as never,
|
||||
agentId: "agent",
|
||||
@@ -334,7 +334,7 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps core block streaming disabled when Feishu blockStreaming is explicitly false", async () => {
|
||||
it("keeps core block streaming disabled when Feishu blockStreaming is explicitly false", () => {
|
||||
resolveFeishuAccountMock.mockReturnValue({
|
||||
accountId: "main",
|
||||
appId: "app_id",
|
||||
@@ -910,7 +910,9 @@ describe("createFeishuReplyDispatcher streaming behavior", () => {
|
||||
expect(reasoningUpdate).not.toMatch(/> _.*_/);
|
||||
|
||||
const combinedUpdate = updateCalls.find((c) => c.includes("Thinking") && c.includes("---"));
|
||||
expect(combinedUpdate).toBeDefined();
|
||||
if (!combinedUpdate) {
|
||||
throw new Error("expected combined reasoning and final-answer streaming update");
|
||||
}
|
||||
|
||||
expect(streamingInstances[0].close).toHaveBeenCalledTimes(1);
|
||||
const closeArg = streamingInstances[0].close.mock.calls[0][0] as string;
|
||||
|
||||
@@ -509,21 +509,36 @@ describe("resolveFeishuCardTemplate", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildStructuredCard", () => {
|
||||
it("uses schema-2.0 width config instead of legacy wide screen mode", () => {
|
||||
const card = buildStructuredCard("hello") as {
|
||||
config: {
|
||||
width_mode?: string;
|
||||
enable_forward?: boolean;
|
||||
wide_screen_mode?: boolean;
|
||||
};
|
||||
function expectSchema2WidthConfig(card: unknown) {
|
||||
const typedCard = card as {
|
||||
config: {
|
||||
width_mode?: string;
|
||||
enable_forward?: boolean;
|
||||
wide_screen_mode?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
expect(card.config.width_mode).toBe("fill");
|
||||
expect(card.config.enable_forward).toBeUndefined();
|
||||
expect(card.config.wide_screen_mode).toBeUndefined();
|
||||
expect(typedCard.config.width_mode).toBe("fill");
|
||||
expect(typedCard.config.enable_forward).toBeUndefined();
|
||||
expect(typedCard.config.wide_screen_mode).toBeUndefined();
|
||||
}
|
||||
|
||||
describe("Feishu card schema config", () => {
|
||||
it.each([
|
||||
{
|
||||
name: "structured card",
|
||||
build: () => buildStructuredCard("hello"),
|
||||
},
|
||||
{
|
||||
name: "markdown card",
|
||||
build: () => buildMarkdownCard("hello"),
|
||||
},
|
||||
])("$name uses schema-2.0 width config instead of legacy wide screen mode", ({ build }) => {
|
||||
expectSchema2WidthConfig(build());
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildStructuredCard", () => {
|
||||
it("falls back to blue when the header template is unsupported", () => {
|
||||
const card = buildStructuredCard("hello", {
|
||||
header: {
|
||||
@@ -542,19 +557,3 @@ describe("buildStructuredCard", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildMarkdownCard", () => {
|
||||
it("uses schema-2.0 width config instead of legacy wide screen mode", () => {
|
||||
const card = buildMarkdownCard("hello") as {
|
||||
config: {
|
||||
width_mode?: string;
|
||||
enable_forward?: boolean;
|
||||
wide_screen_mode?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
expect(card.config.width_mode).toBe("fill");
|
||||
expect(card.config.enable_forward).toBeUndefined();
|
||||
expect(card.config.wide_screen_mode).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -101,21 +101,24 @@ describe("feishu setup wizard", () => {
|
||||
) as never,
|
||||
});
|
||||
|
||||
await expect(
|
||||
runSetupWizardConfigure({
|
||||
configure: feishuConfigure,
|
||||
cfg: {
|
||||
channels: {
|
||||
feishu: {
|
||||
appId: { source: "env", id: "FEISHU_APP_ID", provider: "default" },
|
||||
appSecret: { source: "env", id: "FEISHU_APP_SECRET", provider: "default" },
|
||||
},
|
||||
const result = await runSetupWizardConfigure({
|
||||
configure: feishuConfigure,
|
||||
cfg: {
|
||||
channels: {
|
||||
feishu: {
|
||||
appId: { source: "env", id: "FEISHU_APP_ID", provider: "default" },
|
||||
appSecret: { source: "env", id: "FEISHU_APP_SECRET", provider: "default" },
|
||||
},
|
||||
} as never,
|
||||
prompter,
|
||||
runtime: createNonExitingRuntimeEnv(),
|
||||
}),
|
||||
).resolves.toBeTruthy();
|
||||
},
|
||||
} as never,
|
||||
prompter,
|
||||
runtime: createNonExitingRuntimeEnv(),
|
||||
});
|
||||
|
||||
expect(result.cfg.channels?.feishu).toMatchObject({
|
||||
appId: "cli_from_prompt",
|
||||
appSecret: "secret_from_prompt",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user