@@ -265,15 +265,24 @@ describe('fetchWithRetry', () => {
265265 expect ( result . ok ) . toBe ( true ) ;
266266 expect ( fetch ) . toHaveBeenCalledTimes ( 2 ) ;
267267 expect ( core . warning ) . toHaveBeenCalledWith ( expect . stringContaining ( 'Rate limited' ) ) ;
268- } ) ;
268+ } , 15000 ) ;
269269
270270 test ( 'should throw error after max retries' , async ( ) => {
271- fetch . mockResolvedValue ( { ok : false , status : 500 , statusText : 'Server Error' } ) ;
271+ const mockErrorResponse = {
272+ ok : false ,
273+ status : 500 ,
274+ statusText : 'Server Error' ,
275+ text : jest . fn ( ) . mockResolvedValue ( '' )
276+ } ;
277+
278+ fetch
279+ . mockResolvedValueOnce ( mockErrorResponse )
280+ . mockResolvedValueOnce ( mockErrorResponse ) ;
272281
273282 await expect ( fetchWithRetry ( 'http://test.com' , { } , 2 ) )
274283 . rejects . toThrow ( 'HTTP 500: Server Error' ) ;
275284 expect ( fetch ) . toHaveBeenCalledTimes ( 2 ) ;
276- } ) ;
285+ } , 15000 ) ;
277286} ) ;
278287
279288describe ( 'getFeatureFlag' , ( ) => {
@@ -296,7 +305,7 @@ describe('getFeatureFlag', () => {
296305
297306 const result = await getFeatureFlag ( 'test-api-key' , 'test-project' , 'test-flag' ) ;
298307 expect ( result ) . toEqual ( mockFlag ) ;
299- } ) ;
308+ } , 10000 ) ;
300309
301310 test ( 'should return null for 404 (flag not found)' , async ( ) => {
302311 fetch . mockResolvedValueOnce ( {
@@ -311,14 +320,21 @@ describe('getFeatureFlag', () => {
311320
312321 test ( 'should throw error for other HTTP errors' , async ( ) => {
313322 // Mock multiple calls since fetchWithRetry will retry
323+ const mockErrorResponse = {
324+ ok : false ,
325+ status : 401 ,
326+ statusText : 'Unauthorized' ,
327+ text : jest . fn ( ) . mockResolvedValue ( '' )
328+ } ;
329+
314330 fetch
315- . mockResolvedValueOnce ( { ok : false , status : 401 , statusText : 'Unauthorized' } )
316- . mockResolvedValueOnce ( { ok : false , status : 401 , statusText : 'Unauthorized' } )
317- . mockResolvedValueOnce ( { ok : false , status : 401 , statusText : 'Unauthorized' } ) ;
331+ . mockResolvedValueOnce ( mockErrorResponse )
332+ . mockResolvedValueOnce ( mockErrorResponse )
333+ . mockResolvedValueOnce ( mockErrorResponse ) ;
318334
319335 await expect ( getFeatureFlag ( 'invalid-api-key' , 'test-project' , 'test-flag' ) )
320336 . rejects . toThrow ( 'HTTP 401: Unauthorized. Please check your API key is valid and has the required permissions.' ) ;
321- } , 10000 ) ;
337+ } , 20000 ) ;
322338} ) ;
323339
324340describe ( 'setCustomProperty' , ( ) => {
@@ -347,16 +363,66 @@ describe('setCustomProperty', () => {
347363 expect ( result ) . toEqual ( mockResponse ) ;
348364 } , 10000 ) ;
349365
366+ test ( 'should use correct JSON patch format with "value" field' , async ( ) => {
367+ const mockResponse = {
368+ key : 'test-flag' ,
369+ customProperties : {
370+ 'flag.expiry.date' : {
371+ name : 'flag.expiry.date' ,
372+ value : [ '03/15/2024' ]
373+ }
374+ }
375+ } ;
376+
377+ fetch . mockResolvedValueOnce ( {
378+ ok : true ,
379+ json : async ( ) => mockResponse
380+ } ) ;
381+
382+ await setCustomProperty ( 'test-api-key' , 'test-project' , 'test-flag' , 'flag.expiry.date' , '03/15/2024' ) ;
383+
384+ // Verify the request was made with correct format
385+ expect ( fetch ) . toHaveBeenCalledWith (
386+ 'https://app.launchdarkly.com/api/v2/flags/test-project/test-flag' ,
387+ expect . objectContaining ( {
388+ method : 'PATCH' ,
389+ headers : expect . objectContaining ( {
390+ 'Authorization' : 'test-api-key' ,
391+ 'Content-Type' : 'application/json'
392+ } ) ,
393+ body : JSON . stringify ( {
394+ patch : [
395+ {
396+ op : 'add' ,
397+ path : '/customProperties/flag.expiry.date' ,
398+ value : {
399+ name : 'flag.expiry.date' ,
400+ value : [ '03/15/2024' ] // Should be "value" not "values"
401+ }
402+ }
403+ ]
404+ } )
405+ } )
406+ ) ;
407+ } ) ;
408+
350409 test ( 'should throw error for 401 (unauthorized)' , async ( ) => {
351410 // Mock multiple calls since fetchWithRetry will retry
411+ const mockErrorResponse = {
412+ ok : false ,
413+ status : 401 ,
414+ statusText : 'Unauthorized' ,
415+ text : jest . fn ( ) . mockResolvedValue ( '' )
416+ } ;
417+
352418 fetch
353- . mockResolvedValueOnce ( { ok : false , status : 401 , statusText : 'Unauthorized' } )
354- . mockResolvedValueOnce ( { ok : false , status : 401 , statusText : 'Unauthorized' } )
355- . mockResolvedValueOnce ( { ok : false , status : 401 , statusText : 'Unauthorized' } ) ;
419+ . mockResolvedValueOnce ( mockErrorResponse )
420+ . mockResolvedValueOnce ( mockErrorResponse )
421+ . mockResolvedValueOnce ( mockErrorResponse ) ;
356422
357423 await expect ( setCustomProperty ( 'invalid-api-key' , 'test-project' , 'test-flag' , 'flag.expiry.date' , '03/15/2024' ) )
358424 . rejects . toThrow ( 'HTTP 401: Unauthorized. Please check your API key is valid and has the required permissions. Please check your API key has WRITE permissions.' ) ;
359- } , 10000 ) ;
425+ } , 20000 ) ;
360426
361427 test ( 'should throw error for 404 (flag not found)' , async ( ) => {
362428 fetch . mockResolvedValueOnce ( {
0 commit comments