import assert from "node:assert/strict"; import test from "node:test"; import { createFeishuChannel } from "../src/channels/feishu/index.js"; test("feishu channel adds and removes thinking reaction around replies", async () => { const operations: string[] = []; let nextReactionId = 0; const channel = createFeishuChannel( { thinkingReaction: { enabled: true, emojiType: "OneSecond" }, transport: { addReaction({ messageId, emojiType }) { nextReactionId += 1; operations.push(`add:${messageId}:${emojiType}`); return { reactionId: `reaction-${nextReactionId}`, emojiType }; }, removeReaction({ messageId, reactionId, emojiType }) { operations.push(`remove:${messageId}:${reactionId}:${emojiType}`); }, send(message) { operations.push(`send:${message.replyToMessageId}:${message.text}`); } } }, { async onMessage() { operations.push("handler:start"); await Promise.resolve(); operations.push("handler:end"); return { text: "reply text" }; } } ); const result = await channel.simulateIncomingText({ text: "hello", senderId: "user-1", conversationId: "dm-1", isDirectMessage: true }); assert.equal(result.handled, true); assert.equal(result.reply?.text, "reply text"); assert.deepEqual(operations, [ `add:${result.message?.messageId}:OneSecond`, "handler:start", "handler:end", `remove:${result.message?.messageId}:reaction-1:OneSecond`, `send:${result.message?.messageId}:reply text` ]); }); test("feishu channel defaults thinking reaction emoji to OneSecond", async () => { const operations: string[] = []; const channel = createFeishuChannel( { transport: { addReaction({ messageId, emojiType }) { operations.push(`add:${messageId}:${emojiType}`); return { reactionId: "reaction-1", emojiType }; }, removeReaction({ messageId, reactionId, emojiType }) { operations.push(`remove:${messageId}:${reactionId}:${emojiType}`); }, send(message) { operations.push(`send:${message.replyToMessageId}:${message.text}`); } } }, { onMessage() { return { text: "reply text" }; } } ); const result = await channel.simulateIncomingText({ text: "hello", senderId: "user-default", conversationId: "dm-default", isDirectMessage: true }); assert.equal(result.handled, true); assert.deepEqual(operations, [ `add:${result.message?.messageId}:OneSecond`, `remove:${result.message?.messageId}:reaction-1:OneSecond`, `send:${result.message?.messageId}:reply text` ]); }); test("feishu channel still replies when thinking reaction fails", async () => { const operations: string[] = []; const channel = createFeishuChannel( { thinkingReaction: { enabled: true, emojiType: "OneSecond" }, transport: { addReaction() { operations.push("add-failed"); throw new Error("reaction unavailable"); }, send(message) { operations.push(`send:${message.replyToMessageId}:${message.text}`); } } }, { onMessage() { operations.push("handler"); return { text: "reply after failure" }; } } ); const result = await channel.simulateIncomingText({ text: "hello", senderId: "user-2", conversationId: "dm-2", isDirectMessage: true }); assert.equal(result.handled, true); assert.deepEqual(operations, [ "add-failed", "handler", `send:${result.message?.messageId}:reply after failure` ]); });