diff --git a/extensions/feishu/src/bot.card-action.test.ts b/extensions/feishu/src/bot.card-action.test.ts index 83bd583fb8f..9c9ba50e0ed 100644 --- a/extensions/feishu/src/bot.card-action.test.ts +++ b/extensions/feishu/src/bot.card-action.test.ts @@ -8,6 +8,10 @@ import { type FeishuCardActionEvent, } from "./card-action.js"; import { createFeishuCardInteractionEnvelope } from "./card-interaction.js"; +import { + expectFirstSentCardUsesFillWidthOnly, + expectSentCardHasP2pAction, +} from "./card-test-helpers.js"; import { FEISHU_APPROVAL_CANCEL_ACTION, FEISHU_APPROVAL_CONFIRM_ACTION, @@ -239,21 +243,7 @@ describe("Feishu Card Action Handler", () => { }), }), ); - const firstSendArg = (sendCardFeishuMock.mock.calls as unknown[][]).at(0)?.[0] as - | { - card?: { - config?: { - width_mode?: string; - wide_screen_mode?: boolean; - enable_forward?: boolean; - }; - }; - } - | undefined; - const sentCard = firstSendArg?.card; - expect(sentCard).toBeDefined(); - expect(sentCard?.config?.wide_screen_mode).toBeUndefined(); - expect(sentCard?.config?.enable_forward).toBeUndefined(); + expectFirstSentCardUsesFillWidthOnly(sendCardFeishuMock); expect(handleFeishuMessage).not.toHaveBeenCalled(); }); @@ -423,28 +413,7 @@ describe("Feishu Card Action Handler", () => { await handleFeishuCardAction({ cfg, event, runtime, accountId: "main" }); - expect(sendCardFeishuMock).toHaveBeenCalledWith( - expect.objectContaining({ - card: expect.objectContaining({ - body: expect.objectContaining({ - elements: expect.arrayContaining([ - expect.objectContaining({ - tag: "action", - actions: expect.arrayContaining([ - expect.objectContaining({ - value: expect.objectContaining({ - c: expect.objectContaining({ - t: "p2p", - }), - }), - }), - ]), - }), - ]), - }), - }), - }), - ); + expectSentCardHasP2pAction(sendCardFeishuMock); expect(createFeishuClientMock).toHaveBeenCalledTimes(1); }); diff --git a/extensions/feishu/src/card-test-helpers.ts b/extensions/feishu/src/card-test-helpers.ts new file mode 100644 index 00000000000..d07c6477899 --- /dev/null +++ b/extensions/feishu/src/card-test-helpers.ts @@ -0,0 +1,47 @@ +import { expect } from "vitest"; + +export function expectFirstSentCardUsesFillWidthOnly(sendCardMock: { + mock: { calls: unknown[][] }; +}) { + const firstSendArg = sendCardMock.mock.calls.at(0)?.[0] as + | { + card?: { + config?: { + width_mode?: string; + wide_screen_mode?: boolean; + enable_forward?: boolean; + }; + }; + } + | undefined; + const sentCard = firstSendArg?.card; + expect(sentCard).toBeDefined(); + expect(sentCard?.config?.width_mode).toBe("fill"); + expect(sentCard?.config?.wide_screen_mode).toBeUndefined(); + expect(sentCard?.config?.enable_forward).toBeUndefined(); +} + +export function expectSentCardHasP2pAction(sendCardMock: unknown) { + expect(sendCardMock).toHaveBeenCalledWith( + expect.objectContaining({ + card: expect.objectContaining({ + body: expect.objectContaining({ + elements: expect.arrayContaining([ + expect.objectContaining({ + tag: "action", + actions: expect.arrayContaining([ + expect.objectContaining({ + value: expect.objectContaining({ + c: expect.objectContaining({ + t: "p2p", + }), + }), + }), + ]), + }), + ]), + }), + }), + }), + ); +} diff --git a/extensions/feishu/src/card-ux-launcher.test.ts b/extensions/feishu/src/card-ux-launcher.test.ts index a8513a58f78..1cbacaffb78 100644 --- a/extensions/feishu/src/card-ux-launcher.test.ts +++ b/extensions/feishu/src/card-ux-launcher.test.ts @@ -1,6 +1,10 @@ import { describe, expect, it, vi, beforeEach } from "vitest"; import { createRuntimeEnv } from "../../../test/helpers/plugins/runtime-env.js"; import type { ClawdbotConfig, RuntimeEnv } from "../runtime-api.js"; +import { + expectFirstSentCardUsesFillWidthOnly, + expectSentCardHasP2pAction, +} from "./card-test-helpers.js"; import { createQuickActionLauncherCard, isFeishuQuickActionMenuEventKey, @@ -71,44 +75,10 @@ describe("feishu quick-action launcher", () => { expect.objectContaining({ to: "user:u123", accountId: "main", - card: expect.objectContaining({ - config: expect.objectContaining({ - width_mode: "fill", - }), - body: expect.objectContaining({ - elements: expect.arrayContaining([ - expect.objectContaining({ - tag: "action", - actions: expect.arrayContaining([ - expect.objectContaining({ - value: expect.objectContaining({ - c: expect.objectContaining({ - t: "p2p", - }), - }), - }), - ]), - }), - ]), - }), - }), }), ); - const firstSendArg = (sendCardFeishuMock.mock.calls as unknown[][]).at(0)?.[0] as - | { - card?: { - config?: { - width_mode?: string; - wide_screen_mode?: boolean; - enable_forward?: boolean; - }; - }; - } - | undefined; - const sentCard = firstSendArg?.card; - expect(sentCard).toBeDefined(); - expect(sentCard?.config?.wide_screen_mode).toBeUndefined(); - expect(sentCard?.config?.enable_forward).toBeUndefined(); + expectSentCardHasP2pAction(sendCardFeishuMock); + expectFirstSentCardUsesFillWidthOnly(sendCardFeishuMock); }); it("falls back to legacy menu handling when launcher send fails", async () => { diff --git a/extensions/feishu/src/monitor.bot-menu.test.ts b/extensions/feishu/src/monitor.bot-menu.test.ts index e68e8fe0b7f..770fe26a3cb 100644 --- a/extensions/feishu/src/monitor.bot-menu.test.ts +++ b/extensions/feishu/src/monitor.bot-menu.test.ts @@ -1,5 +1,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { ClawdbotConfig, RuntimeEnv } from "../runtime-api.js"; +import { expectFirstSentCardUsesFillWidthOnly } from "./card-test-helpers.js"; import { monitorSingleAccount } from "./monitor.account.js"; import { setFeishuRuntime } from "./runtime.js"; import type { ResolvedFeishuAccount } from "./types.js"; @@ -215,21 +216,7 @@ describe("Feishu bot menu handler", () => { }), ); }); - const firstSendArg = (sendCardFeishuMock.mock.calls as unknown[][]).at(0)?.[0] as - | { - card?: { - config?: { - width_mode?: string; - wide_screen_mode?: boolean; - enable_forward?: boolean; - }; - }; - } - | undefined; - const sentCard = firstSendArg?.card; - expect(sentCard).toBeDefined(); - expect(sentCard?.config?.wide_screen_mode).toBeUndefined(); - expect(sentCard?.config?.enable_forward).toBeUndefined(); + expectFirstSentCardUsesFillWidthOnly(sendCardFeishuMock); }); it("reopens replay for explicit retryable fallback failures", async () => {