refactor(feishu-tests): share card action event builders

This commit is contained in:
Peter Steinberger
2026-03-17 06:40:59 +00:00
parent 769332c1a7
commit 214c7a481c

View File

@@ -35,6 +35,54 @@ describe("Feishu Card Action Handler", () => {
const cfg = {} as any; // Minimal mock
const runtime = { log: vi.fn(), error: vi.fn() } as any;
function createCardActionEvent(params: {
token: string;
actionValue: unknown;
chatId?: string;
openId?: string;
userId?: string;
unionId?: string;
}): FeishuCardActionEvent {
const openId = params.openId ?? "u123";
const userId = params.userId ?? "uid1";
return {
operator: { open_id: openId, user_id: userId, union_id: params.unionId ?? "un1" },
token: params.token,
action: {
value: params.actionValue,
tag: "button",
},
context: { open_id: openId, user_id: userId, chat_id: params.chatId ?? "chat1" },
};
}
function createStructuredQuickActionEvent(params: {
token: string;
action: string;
command?: string;
chatId?: string;
chatType?: "group" | "p2p";
operatorOpenId?: string;
actionOpenId?: string;
}): FeishuCardActionEvent {
return createCardActionEvent({
token: params.token,
chatId: params.chatId,
openId: params.operatorOpenId,
actionValue: createFeishuCardInteractionEnvelope({
k: "quick",
a: params.action,
...(params.command ? { q: params.command } : {}),
c: {
u: params.actionOpenId ?? params.operatorOpenId ?? "u123",
h: params.chatId ?? "chat1",
t: params.chatType ?? "group",
e: Date.now() + 60_000,
},
}),
});
}
beforeEach(() => {
vi.clearAllMocks();
resetProcessedFeishuCardActionTokensForTests();
@@ -85,20 +133,11 @@ describe("Feishu Card Action Handler", () => {
});
it("routes quick command actions with operator and conversation context", async () => {
const event: FeishuCardActionEvent = {
operator: { open_id: "u123", user_id: "uid1", union_id: "un1" },
const event = createStructuredQuickActionEvent({
token: "tok3",
action: {
value: createFeishuCardInteractionEnvelope({
k: "quick",
a: "feishu.quick_actions.help",
q: "/help",
c: { u: "u123", h: "chat1", t: "group", e: Date.now() + 60_000 },
}),
tag: "button",
},
context: { open_id: "u123", user_id: "uid1", chat_id: "chat1" },
};
action: "feishu.quick_actions.help",
command: "/help",
});
await handleFeishuCardAction({ cfg, event, runtime });
@@ -182,20 +221,11 @@ describe("Feishu Card Action Handler", () => {
});
it("runs approval confirmation through the normal message path", async () => {
const event: FeishuCardActionEvent = {
operator: { open_id: "u123", user_id: "uid1", union_id: "un1" },
const event = createStructuredQuickActionEvent({
token: "tok5",
action: {
value: createFeishuCardInteractionEnvelope({
k: "quick",
a: FEISHU_APPROVAL_CONFIRM_ACTION,
q: "/new",
c: { u: "u123", h: "chat1", t: "group", e: Date.now() + 60_000 },
}),
tag: "button",
},
context: { open_id: "u123", user_id: "uid1", chat_id: "chat1" },
};
action: FEISHU_APPROVAL_CONFIRM_ACTION,
command: "/new",
});
await handleFeishuCardAction({ cfg, event, runtime });
@@ -211,20 +241,15 @@ describe("Feishu Card Action Handler", () => {
});
it("safely rejects stale structured actions", async () => {
const event: FeishuCardActionEvent = {
operator: { open_id: "u123", user_id: "uid1", union_id: "un1" },
const event = createCardActionEvent({
token: "tok6",
action: {
value: createFeishuCardInteractionEnvelope({
k: "quick",
a: "feishu.quick_actions.help",
q: "/help",
c: { u: "u123", h: "chat1", t: "group", e: Date.now() - 1 },
}),
tag: "button",
},
context: { open_id: "u123", user_id: "uid1", chat_id: "chat1" },
};
actionValue: createFeishuCardInteractionEnvelope({
k: "quick",
a: "feishu.quick_actions.help",
q: "/help",
c: { u: "u123", h: "chat1", t: "group", e: Date.now() - 1 },
}),
});
await handleFeishuCardAction({ cfg, event, runtime });
@@ -238,20 +263,13 @@ describe("Feishu Card Action Handler", () => {
});
it("safely rejects wrong-user structured actions", async () => {
const event: FeishuCardActionEvent = {
operator: { open_id: "u999", user_id: "uid1", union_id: "un1" },
const event = createStructuredQuickActionEvent({
token: "tok7",
action: {
value: createFeishuCardInteractionEnvelope({
k: "quick",
a: "feishu.quick_actions.help",
q: "/help",
c: { u: "u123", h: "chat1", t: "group", e: Date.now() + 60_000 },
}),
tag: "button",
},
context: { open_id: "u999", user_id: "uid1", chat_id: "chat1" },
};
action: "feishu.quick_actions.help",
command: "/help",
operatorOpenId: "u999",
actionOpenId: "u123",
});
await handleFeishuCardAction({ cfg, event, runtime });
@@ -289,20 +307,13 @@ describe("Feishu Card Action Handler", () => {
});
it("preserves p2p callbacks for DM quick actions", async () => {
const event: FeishuCardActionEvent = {
operator: { open_id: "u123", user_id: "uid1", union_id: "un1" },
const event = createStructuredQuickActionEvent({
token: "tok9",
action: {
value: createFeishuCardInteractionEnvelope({
k: "quick",
a: "feishu.quick_actions.help",
q: "/help",
c: { u: "u123", h: "p2p-chat-1", t: "p2p", e: Date.now() + 60_000 },
}),
tag: "button",
},
context: { open_id: "u123", user_id: "uid1", chat_id: "p2p-chat-1" },
};
action: "feishu.quick_actions.help",
command: "/help",
chatId: "p2p-chat-1",
chatType: "p2p",
});
await handleFeishuCardAction({ cfg, event, runtime });
@@ -319,20 +330,11 @@ describe("Feishu Card Action Handler", () => {
});
it("drops duplicate structured callback tokens", async () => {
const event: FeishuCardActionEvent = {
operator: { open_id: "u123", user_id: "uid1", union_id: "un1" },
const event = createStructuredQuickActionEvent({
token: "tok10",
action: {
value: createFeishuCardInteractionEnvelope({
k: "quick",
a: "feishu.quick_actions.help",
q: "/help",
c: { u: "u123", h: "chat1", t: "group", e: Date.now() + 60_000 },
}),
tag: "button",
},
context: { open_id: "u123", user_id: "uid1", chat_id: "chat1" },
};
action: "feishu.quick_actions.help",
command: "/help",
});
await handleFeishuCardAction({ cfg, event, runtime });
await handleFeishuCardAction({ cfg, event, runtime });
@@ -341,20 +343,11 @@ describe("Feishu Card Action Handler", () => {
});
it("releases a claimed token when dispatch fails so retries can succeed", async () => {
const event: FeishuCardActionEvent = {
operator: { open_id: "u123", user_id: "uid1", union_id: "un1" },
const event = createStructuredQuickActionEvent({
token: "tok11",
action: {
value: createFeishuCardInteractionEnvelope({
k: "quick",
a: "feishu.quick_actions.help",
q: "/help",
c: { u: "u123", h: "chat1", t: "group", e: Date.now() + 60_000 },
}),
tag: "button",
},
context: { open_id: "u123", user_id: "uid1", chat_id: "chat1" },
};
action: "feishu.quick_actions.help",
command: "/help",
});
vi.mocked(handleFeishuMessage)
.mockRejectedValueOnce(new Error("transient"))
.mockResolvedValueOnce(undefined as never);