@@ -22,9 +22,9 @@ export default class httpClient {
2222
2323 let proxyUrl = null ;
2424 try {
25- // Handle URL with or without protocol
26- const urlStr = SMARTUI_API_PROXY ?. startsWith ( 'http' ) ?
27- SMARTUI_API_PROXY : `http://${ SMARTUI_API_PROXY } ` ;
25+ // Handle URL with or without protocol
26+ const urlStr = SMARTUI_API_PROXY ?. startsWith ( 'http' ) ?
27+ SMARTUI_API_PROXY : `http://${ SMARTUI_API_PROXY } ` ;
2828 proxyUrl = SMARTUI_API_PROXY ? new URL ( urlStr ) : null ;
2929 } catch ( error ) {
3030 console . error ( 'Invalid proxy URL:' , error ) ;
@@ -36,7 +36,7 @@ export default class httpClient {
3636 port : proxyUrl . port ? Number ( proxyUrl . port ) : 80
3737 } : false
3838 } ;
39-
39+
4040 if ( SMARTUI_API_SKIP_CERTIFICATES ) {
4141 axiosConfig . httpsAgent = new https . Agent ( {
4242 rejectUnauthorized : false
@@ -45,29 +45,63 @@ export default class httpClient {
4545
4646 this . axiosInstance = axios . create ( axiosConfig ) ;
4747
48-
48+
4949 this . axiosInstance . interceptors . request . use ( ( config ) => {
5050 config . headers [ 'projectToken' ] = this . projectToken ;
5151 config . headers [ 'projectName' ] = this . projectName ;
5252 config . headers [ 'username' ] = this . username ;
5353 config . headers [ 'accessKey' ] = this . accessKey ;
5454 return config ;
5555 } ) ;
56+
57+ // Add a request interceptor for retry logic
58+ this . axiosInstance . interceptors . response . use (
59+ ( response ) => response ,
60+ async ( error ) => {
61+ const { config } = error ;
62+ if ( config && config . url === '/screenshot' && config . method === 'post' ) {
63+ // Set default retry count and delay if not already defined
64+ if ( ! config . retryCount ) {
65+ config . retryCount = 0 ;
66+ config . retry = 2 ;
67+ config . retryDelay = 5000 ;
68+ }
69+
70+ // Check if we should retry the request
71+ if ( config . retryCount < config . retry ) {
72+ config . retryCount += 1 ;
73+ await new Promise ( resolve => setTimeout ( resolve , config . retryDelay ) ) ;
74+ config . timeout = 30000 ;
75+ return this . axiosInstance ( config ) ;
76+ }
77+
78+ // If we've reached max retries, reject with the error
79+ return Promise . reject ( error ) ;
80+ }
81+ }
82+ ) ;
5683 }
5784
85+
86+
5887 async request ( config : AxiosRequestConfig , log : Logger ) : Promise < Record < string , any > > {
5988 log . debug ( `http request: ${ config . method } ${ config . url } ` ) ;
60- if ( config && config . data && ! config . data . name ) {
89+ if ( config && config . data && ! config . data . name ) {
6190 log . debug ( config . data ) ;
6291 }
6392 return this . axiosInstance . request ( config )
6493 . then ( resp => {
65- log . debug ( `http response: ${ JSON . stringify ( {
66- status : resp . status ,
67- headers : resp . headers ,
68- body : resp . data
69- } ) } `)
70- return resp . data ;
94+ if ( resp ) {
95+ log . debug ( `http response: ${ JSON . stringify ( {
96+ status : resp . status ,
97+ headers : resp . headers ,
98+ body : resp . data
99+ } ) } `)
100+ return resp . data ;
101+ } else {
102+ log . debug ( `empty response: ${ JSON . stringify ( resp ) } ` )
103+ return { } ;
104+ }
71105 } )
72106 . catch ( error => {
73107 if ( error . response ) {
@@ -107,7 +141,7 @@ export default class httpClient {
107141 throw new Error ( 'Authentication failed, project token not received' ) ;
108142 }
109143 }
110-
144+
111145 createBuild ( git : Git , config : any , log : Logger , buildName : string , isStartExec : boolean ) {
112146 return this . request ( {
113147 url : '/build' ,
@@ -128,7 +162,7 @@ export default class httpClient {
128162 params : { buildId, baseline }
129163 } , log ) ;
130164 }
131-
165+
132166 ping ( buildId : string , log : Logger ) {
133167 return this . request ( {
134168 url : '/build/ping' ,
@@ -138,10 +172,10 @@ export default class httpClient {
138172 }
139173 } , log ) ;
140174 }
141-
175+
142176
143177 finalizeBuild ( buildId : string , totalSnapshots : number , log : Logger ) {
144- let params : Record < string , string | number > = { buildId} ;
178+ let params : Record < string , string | number > = { buildId } ;
145179 if ( totalSnapshots > - 1 ) params . totalSnapshots = totalSnapshots ;
146180
147181 return this . request ( {
@@ -156,7 +190,7 @@ export default class httpClient {
156190 url : `/builds/${ ctx . build . id } /snapshot` ,
157191 method : 'POST' ,
158192 headers : { 'Content-Type' : 'application/json' } ,
159- data : {
193+ data : {
160194 snapshot,
161195 test : {
162196 type : ctx . testType ,
@@ -171,7 +205,7 @@ export default class httpClient {
171205 url : `/build/${ ctx . build . id } /snapshot` ,
172206 method : 'POST' ,
173207 headers : { 'Content-Type' : 'application/json' } ,
174- data : {
208+ data : {
175209 name : snapshot . name ,
176210 url : snapshot . url ,
177211 snapshotUuid : snapshotUuid ,
@@ -185,13 +219,13 @@ export default class httpClient {
185219 }
186220
187221 uploadScreenshot (
188- { id : buildId , name : buildName , baseline } : Build ,
189- ssPath : string , ssName : string , browserName : string , viewport : string , log : Logger
222+ { id : buildId , name : buildName , baseline } : Build ,
223+ ssPath : string , ssName : string , browserName : string , viewport : string , log : Logger
190224 ) {
191225 browserName = browserName === constants . SAFARI ? constants . WEBKIT : browserName ;
192226 const file = fs . readFileSync ( ssPath ) ;
193227 const form = new FormData ( ) ;
194- form . append ( 'screenshot' , file , { filename : `${ ssName } .png` , contentType : 'image/png' } ) ;
228+ form . append ( 'screenshot' , file , { filename : `${ ssName } .png` , contentType : 'image/png' } ) ;
195229 form . append ( 'browser' , browserName ) ;
196230 form . append ( 'viewport' , viewport ) ;
197231 form . append ( 'buildId' , buildId ) ;
@@ -204,19 +238,20 @@ export default class httpClient {
204238 method : 'POST' ,
205239 headers : form . getHeaders ( ) ,
206240 data : form ,
241+ timeout : 30000
207242 } )
208- . then ( ( ) => {
209- log . debug ( `${ ssName } for ${ browserName } ${ viewport } uploaded successfully` ) ;
210- } )
211- . catch ( error => {
212- log . error ( `Unable to upload screenshot ${ JSON . stringify ( error ) } ` )
213- if ( error && error . response && error . response . data && error . response . data . error ) {
214- throw new Error ( error . response . data . error . message ) ;
215- }
216- if ( error ) {
217- throw new Error ( JSON . stringify ( error ) ) ;
218- }
219- } )
243+ . then ( ( ) => {
244+ log . debug ( `${ ssName } for ${ browserName } ${ viewport } uploaded successfully` ) ;
245+ } )
246+ . catch ( error => {
247+ log . error ( `Unable to upload screenshot ${ JSON . stringify ( error ) } ` )
248+ if ( error && error . response && error . response . data && error . response . data . error ) {
249+ throw new Error ( error . response . data . error . message ) ;
250+ }
251+ if ( error ) {
252+ throw new Error ( JSON . stringify ( error ) ) ;
253+ }
254+ } )
220255 }
221256
222257 checkUpdate ( log : Logger ) {
@@ -232,15 +267,15 @@ export default class httpClient {
232267 }
233268
234269 getFigmaFilesAndImages ( figmaFileToken : string , figmaToken : String | undefined , queryParams : string , authToken : string , depth : number , markBaseline : boolean , buildName : string , log : Logger ) {
235- const requestBody = {
236- figma_file_token : figmaFileToken ,
237- figma_token : figmaToken ,
238- query_params : queryParams ,
239- auth : authToken ,
240- depth : depth ,
241- mark_base_line : markBaseline ,
242- build_name : buildName
243- } ;
270+ const requestBody = {
271+ figma_file_token : figmaFileToken ,
272+ figma_token : figmaToken ,
273+ query_params : queryParams ,
274+ auth : authToken ,
275+ depth : depth ,
276+ mark_base_line : markBaseline ,
277+ build_name : buildName
278+ } ;
244279
245280 return this . request ( {
246281 url : "/uploadfigma" ,
@@ -297,34 +332,34 @@ export default class httpClient {
297332 return this . request ( {
298333 url : uploadURL ,
299334 method : 'PUT' ,
300- headers :{
335+ headers : {
301336 'Content-Type' : 'application/json' ,
302337 } ,
303338 data : snapshot ,
304339 maxBodyLength : Infinity , // prevent axios from limiting the body size
305340 maxContentLength : Infinity , // prevent axios from limiting the content size
306341 } , ctx . log )
307342 }
308-
343+
309344 processWebFigma ( requestBody : any , log : Logger ) {
310- return this . request ( {
311- url : "figma-web/upload" ,
312- method : "POST" ,
313- headers : {
314- "Content-Type" : "application/json" ,
315- } ,
316- data : JSON . stringify ( requestBody )
317- } , log ) ;
318- }
345+ return this . request ( {
346+ url : "figma-web/upload" ,
347+ method : "POST" ,
348+ headers : {
349+ "Content-Type" : "application/json" ,
350+ } ,
351+ data : JSON . stringify ( requestBody )
352+ } , log ) ;
353+ }
319354
320355 fetchWebFigma ( buildId : any , log : Logger ) {
321- return this . request ( {
322- url : "figma-web/fetch" ,
323- method : "GET" ,
324- headers : {
325- "Content-Type" : "application/json" ,
326- } ,
327- params : { buildId }
328- } , log ) ;
329- }
356+ return this . request ( {
357+ url : "figma-web/fetch" ,
358+ method : "GET" ,
359+ headers : {
360+ "Content-Type" : "application/json" ,
361+ } ,
362+ params : { buildId }
363+ } , log ) ;
364+ }
330365}
0 commit comments