@@ -2,11 +2,18 @@ import type { OpenClawConfig } from "openclaw/plugin-sdk/feishu";
22import { describe , expect , it , vi } from "vitest" ;
33
44const probeFeishuMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
5+ const listReactionsFeishuMock = vi . hoisted ( ( ) => vi . fn ( ) ) ;
56
67vi . mock ( "./probe.js" , ( ) => ( {
78 probeFeishu : probeFeishuMock ,
89} ) ) ;
910
11+ vi . mock ( "./reactions.js" , ( ) => ( {
12+ addReactionFeishu : vi . fn ( ) ,
13+ listReactionsFeishu : listReactionsFeishuMock ,
14+ removeReactionFeishu : vi . fn ( ) ,
15+ } ) ) ;
16+
1017import { feishuPlugin } from "./channel.js" ;
1118
1219describe ( "feishuPlugin.status.probeAccount" , ( ) => {
@@ -46,3 +53,114 @@ describe("feishuPlugin.status.probeAccount", () => {
4653 expect ( result ) . toMatchObject ( { ok : true , appId : "cli_main" } ) ;
4754 } ) ;
4855} ) ;
56+
57+ describe ( "feishuPlugin actions" , ( ) => {
58+ const cfg = {
59+ channels : {
60+ feishu : {
61+ enabled : true ,
62+ appId : "cli_main" ,
63+ appSecret : "secret_main" ,
64+ actions : {
65+ reactions : true ,
66+ } ,
67+ } ,
68+ } ,
69+ } as OpenClawConfig ;
70+
71+ it ( "does not advertise reactions when disabled via actions config" , ( ) => {
72+ const disabledCfg = {
73+ channels : {
74+ feishu : {
75+ enabled : true ,
76+ appId : "cli_main" ,
77+ appSecret : "secret_main" ,
78+ actions : {
79+ reactions : false ,
80+ } ,
81+ } ,
82+ } ,
83+ } as OpenClawConfig ;
84+
85+ expect ( feishuPlugin . actions ?. listActions ?.( { cfg : disabledCfg } ) ) . toEqual ( [ ] ) ;
86+ } ) ;
87+
88+ it ( "advertises reactions when any enabled configured account allows them" , ( ) => {
89+ const cfg = {
90+ channels : {
91+ feishu : {
92+ enabled : true ,
93+ defaultAccount : "main" ,
94+ actions : {
95+ reactions : false ,
96+ } ,
97+ accounts : {
98+ main : {
99+ appId : "cli_main" ,
100+ appSecret : "secret_main" ,
101+ enabled : true ,
102+ actions : {
103+ reactions : false ,
104+ } ,
105+ } ,
106+ secondary : {
107+ appId : "cli_secondary" ,
108+ appSecret : "secret_secondary" ,
109+ enabled : true ,
110+ actions : {
111+ reactions : true ,
112+ } ,
113+ } ,
114+ } ,
115+ } ,
116+ } ,
117+ } as OpenClawConfig ;
118+
119+ expect ( feishuPlugin . actions ?. listActions ?.( { cfg } ) ) . toEqual ( [ "react" , "reactions" ] ) ;
120+ } ) ;
121+
122+ it ( "requires clearAll=true before removing all bot reactions" , async ( ) => {
123+ await expect (
124+ feishuPlugin . actions ?. handleAction ?.( {
125+ action : "react" ,
126+ params : { messageId : "om_msg1" } ,
127+ cfg,
128+ accountId : undefined ,
129+ } as never ) ,
130+ ) . rejects . toThrow (
131+ "Emoji is required to add a Feishu reaction. Set clearAll=true to remove all bot reactions." ,
132+ ) ;
133+ } ) ;
134+
135+ it ( "throws for unsupported Feishu send actions without card payload" , async ( ) => {
136+ await expect (
137+ feishuPlugin . actions ?. handleAction ?.( {
138+ action : "send" ,
139+ params : { to : "chat:oc_group_1" , message : "hello" } ,
140+ cfg,
141+ accountId : undefined ,
142+ } as never ) ,
143+ ) . rejects . toThrow ( 'Unsupported Feishu action: "send"' ) ;
144+ } ) ;
145+
146+ it ( "allows explicit clearAll=true when removing all bot reactions" , async ( ) => {
147+ listReactionsFeishuMock . mockResolvedValueOnce ( [
148+ { reactionId : "r1" , operatorType : "app" } ,
149+ { reactionId : "r2" , operatorType : "app" } ,
150+ ] ) ;
151+
152+ const result = await feishuPlugin . actions ?. handleAction ?.( {
153+ action : "react" ,
154+ params : { messageId : "om_msg1" , clearAll : true } ,
155+ cfg,
156+ accountId : undefined ,
157+ } as never ) ;
158+
159+ expect ( listReactionsFeishuMock ) . toHaveBeenCalledWith ( {
160+ cfg,
161+ messageId : "om_msg1" ,
162+ accountId : undefined ,
163+ } ) ;
164+ expect ( result ?. details ) . toMatchObject ( { ok : true , removed : 2 } ) ;
165+ } ) ;
166+ } ) ;
0 commit comments