test: tighten assertions and harness coverage

This commit is contained in:
Peter Steinberger
2026-05-08 05:27:57 +01:00
parent f62618f805
commit 9ef37d1907
822 changed files with 8918 additions and 6533 deletions

View File

@@ -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",

View File

@@ -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");
}

View File

@@ -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);
});

View File

@@ -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 () => {

View File

@@ -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"]);
});

View File

@@ -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;

View File

@@ -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();
});
});

View File

@@ -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",
});
});
});