@@ -12,20 +12,38 @@ const httpsProxyAgentCtorMock = vi.hoisted(() =>
1212 } ) ,
1313) ;
1414
15+ const mockBaseHttpInstance = vi . hoisted ( ( ) => ( {
16+ request : vi . fn ( ) . mockResolvedValue ( { } ) ,
17+ get : vi . fn ( ) . mockResolvedValue ( { } ) ,
18+ post : vi . fn ( ) . mockResolvedValue ( { } ) ,
19+ put : vi . fn ( ) . mockResolvedValue ( { } ) ,
20+ patch : vi . fn ( ) . mockResolvedValue ( { } ) ,
21+ delete : vi . fn ( ) . mockResolvedValue ( { } ) ,
22+ head : vi . fn ( ) . mockResolvedValue ( { } ) ,
23+ options : vi . fn ( ) . mockResolvedValue ( { } ) ,
24+ } ) ) ;
25+
1526vi . mock ( "@larksuiteoapi/node-sdk" , ( ) => ( {
1627 AppType : { SelfBuild : "self" } ,
1728 Domain : { Feishu : "https://open.feishu.cn" , Lark : "https://open.larksuite.com" } ,
1829 LoggerLevel : { info : "info" } ,
1930 Client : vi . fn ( ) ,
2031 WSClient : wsClientCtorMock ,
2132 EventDispatcher : vi . fn ( ) ,
33+ defaultHttpInstance : mockBaseHttpInstance ,
2234} ) ) ;
2335
2436vi . mock ( "https-proxy-agent" , ( ) => ( {
2537 HttpsProxyAgent : httpsProxyAgentCtorMock ,
2638} ) ) ;
2739
28- import { createFeishuWSClient } from "./client.js" ;
40+ import { Client as LarkClient } from "@larksuiteoapi/node-sdk" ;
41+ import {
42+ createFeishuClient ,
43+ createFeishuWSClient ,
44+ clearClientCache ,
45+ FEISHU_HTTP_TIMEOUT_MS ,
46+ } from "./client.js" ;
2947
3048const proxyEnvKeys = [ "https_proxy" , "HTTPS_PROXY" , "http_proxy" , "HTTP_PROXY" ] as const ;
3149type ProxyEnvKey = ( typeof proxyEnvKeys ) [ number ] ;
@@ -68,6 +86,59 @@ afterEach(() => {
6886 }
6987} ) ;
7088
89+ describe ( "createFeishuClient HTTP timeout" , ( ) => {
90+ beforeEach ( ( ) => {
91+ clearClientCache ( ) ;
92+ } ) ;
93+
94+ it ( "passes a custom httpInstance with default timeout to Lark.Client" , ( ) => {
95+ createFeishuClient ( { appId : "app_1" , appSecret : "secret_1" , accountId : "timeout-test" } ) ;
96+
97+ const calls = ( LarkClient as unknown as ReturnType < typeof vi . fn > ) . mock . calls ;
98+ const lastCall = calls [ calls . length - 1 ] [ 0 ] as { httpInstance ?: unknown } ;
99+ expect ( lastCall . httpInstance ) . toBeDefined ( ) ;
100+ } ) ;
101+
102+ it ( "injects default timeout into HTTP request options" , async ( ) => {
103+ createFeishuClient ( { appId : "app_2" , appSecret : "secret_2" , accountId : "timeout-inject" } ) ;
104+
105+ const calls = ( LarkClient as unknown as ReturnType < typeof vi . fn > ) . mock . calls ;
106+ const lastCall = calls [ calls . length - 1 ] [ 0 ] as {
107+ httpInstance : { post : ( ...args : unknown [ ] ) => Promise < unknown > } ;
108+ } ;
109+ const httpInstance = lastCall . httpInstance ;
110+
111+ await httpInstance . post (
112+ "https://example.com/api" ,
113+ { data : 1 } ,
114+ { headers : { "X-Custom" : "yes" } } ,
115+ ) ;
116+
117+ expect ( mockBaseHttpInstance . post ) . toHaveBeenCalledWith (
118+ "https://example.com/api" ,
119+ { data : 1 } ,
120+ expect . objectContaining ( { timeout : FEISHU_HTTP_TIMEOUT_MS , headers : { "X-Custom" : "yes" } } ) ,
121+ ) ;
122+ } ) ;
123+
124+ it ( "allows explicit timeout override per-request" , async ( ) => {
125+ createFeishuClient ( { appId : "app_3" , appSecret : "secret_3" , accountId : "timeout-override" } ) ;
126+
127+ const calls = ( LarkClient as unknown as ReturnType < typeof vi . fn > ) . mock . calls ;
128+ const lastCall = calls [ calls . length - 1 ] [ 0 ] as {
129+ httpInstance : { get : ( ...args : unknown [ ] ) => Promise < unknown > } ;
130+ } ;
131+ const httpInstance = lastCall . httpInstance ;
132+
133+ await httpInstance . get ( "https://example.com/api" , { timeout : 5_000 } ) ;
134+
135+ expect ( mockBaseHttpInstance . get ) . toHaveBeenCalledWith (
136+ "https://example.com/api" ,
137+ expect . objectContaining ( { timeout : 5_000 } ) ,
138+ ) ;
139+ } ) ;
140+ } ) ;
141+
71142describe ( "createFeishuWSClient proxy handling" , ( ) => {
72143 it ( "does not set a ws proxy agent when proxy env is absent" , ( ) => {
73144 createFeishuWSClient ( baseAccount ) ;
0 commit comments