@@ -31,7 +31,7 @@ describe("LoopsClient", () => {
3131 const mockResponse = { success : true , teamName : "Test Team" } ;
3232 global . fetch = jest . fn ( ) . mockResolvedValue ( {
3333 ok : true ,
34- json : ( ) => Promise . resolve ( mockResponse ) ,
34+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
3535 } ) ;
3636
3737 const result = await client . testApiKey ( ) ;
@@ -48,7 +48,7 @@ describe("LoopsClient", () => {
4848 global . fetch = jest . fn ( ) . mockResolvedValue ( {
4949 ok : false ,
5050 status : 401 ,
51- json : ( ) => Promise . resolve ( mockResponse ) ,
51+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
5252 } ) ;
5353
5454 await expect ( client . testApiKey ( ) ) . rejects . toThrow ( APIError ) ;
@@ -80,7 +80,7 @@ describe("LoopsClient", () => {
8080
8181 global . fetch = jest . fn ( ) . mockResolvedValue ( {
8282 ok : true ,
83- json : ( ) => Promise . resolve ( mockResponse ) ,
83+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
8484 } ) ;
8585
8686 const result = await client . createContact ( { email } ) ;
@@ -106,7 +106,7 @@ describe("LoopsClient", () => {
106106
107107 global . fetch = jest . fn ( ) . mockResolvedValue ( {
108108 ok : true ,
109- json : ( ) => Promise . resolve ( mockResponse ) ,
109+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
110110 } ) ;
111111
112112 const result = await client . createContact ( { email, properties } ) ;
@@ -131,7 +131,7 @@ describe("LoopsClient", () => {
131131 global . fetch = jest . fn ( ) . mockResolvedValue ( {
132132 ok : false ,
133133 status : 400 ,
134- json : ( ) => Promise . resolve ( mockResponse ) ,
134+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
135135 } ) ;
136136
137137 await expect ( client . createContact ( { email } ) ) . rejects . toThrow ( APIError ) ;
@@ -165,7 +165,7 @@ describe("LoopsClient", () => {
165165
166166 global . fetch = jest . fn ( ) . mockResolvedValue ( {
167167 ok : true ,
168- json : ( ) => Promise . resolve ( mockResponse ) ,
168+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
169169 } ) ;
170170
171171 const result = await client . updateContact ( {
@@ -198,7 +198,7 @@ describe("LoopsClient", () => {
198198
199199 global . fetch = jest . fn ( ) . mockResolvedValue ( {
200200 ok : true ,
201- json : ( ) => Promise . resolve ( mockResponse ) ,
201+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
202202 } ) ;
203203
204204 const result = await client . updateContact ( {
@@ -227,7 +227,7 @@ describe("LoopsClient", () => {
227227 global . fetch = jest . fn ( ) . mockResolvedValue ( {
228228 ok : true ,
229229 status : 200 ,
230- json : ( ) => Promise . resolve ( mockResponse ) ,
230+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
231231 } ) ;
232232
233233 const result = await client . updateContact ( { email } ) ;
@@ -255,7 +255,7 @@ describe("LoopsClient", () => {
255255
256256 global . fetch = jest . fn ( ) . mockResolvedValue ( {
257257 ok : true ,
258- json : ( ) => Promise . resolve ( mockResponse ) ,
258+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
259259 } ) ;
260260
261261 const result = await client . createContactProperty ( name , type ) ;
@@ -279,7 +279,7 @@ describe("LoopsClient", () => {
279279 global . fetch = jest . fn ( ) . mockResolvedValue ( {
280280 ok : false ,
281281 status : 400 ,
282- json : ( ) => Promise . resolve ( mockResponse ) ,
282+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
283283 } ) ;
284284
285285 await expect (
@@ -304,7 +304,7 @@ describe("LoopsClient", () => {
304304 global . fetch = jest . fn ( ) . mockResolvedValue ( {
305305 ok : false ,
306306 status : 400 ,
307- json : ( ) => Promise . resolve ( mockResponse ) ,
307+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
308308 } ) ;
309309
310310 await expect ( client . createContactProperty ( name , type ) ) . rejects . toThrow (
@@ -341,7 +341,7 @@ describe("LoopsClient", () => {
341341
342342 global . fetch = jest . fn ( ) . mockResolvedValue ( {
343343 ok : true ,
344- json : ( ) => Promise . resolve ( mockResponse ) ,
344+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
345345 } ) ;
346346
347347 const result = await client . sendEvent ( eventData ) ;
@@ -371,7 +371,7 @@ describe("LoopsClient", () => {
371371
372372 global . fetch = jest . fn ( ) . mockResolvedValue ( {
373373 ok : true ,
374- json : ( ) => Promise . resolve ( mockResponse ) ,
374+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
375375 } ) ;
376376
377377 const result = await client . sendEvent ( eventData ) ;
@@ -412,7 +412,7 @@ describe("LoopsClient", () => {
412412 global . fetch = jest . fn ( ) . mockResolvedValue ( {
413413 ok : false ,
414414 status : 400 ,
415- json : ( ) => Promise . resolve ( mockResponse ) ,
415+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
416416 } ) ;
417417
418418 await expect ( client . sendEvent ( eventData ) ) . rejects . toThrow ( APIError ) ;
@@ -440,7 +440,7 @@ describe("LoopsClient", () => {
440440
441441 global . fetch = jest . fn ( ) . mockResolvedValue ( {
442442 ok : true ,
443- json : ( ) => Promise . resolve ( mockResponse ) ,
443+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
444444 } ) ;
445445
446446 const result = await client . sendEvent ( eventData ) ;
@@ -476,7 +476,7 @@ describe("LoopsClient", () => {
476476
477477 global . fetch = jest . fn ( ) . mockResolvedValue ( {
478478 ok : true ,
479- json : ( ) => Promise . resolve ( mockResponse ) ,
479+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
480480 } ) ;
481481
482482 const result = await client . sendEvent ( eventData ) ;
@@ -506,7 +506,7 @@ describe("LoopsClient", () => {
506506
507507 global . fetch = jest . fn ( ) . mockResolvedValue ( {
508508 ok : true ,
509- json : ( ) => Promise . resolve ( mockResponse ) ,
509+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
510510 } ) ;
511511
512512 const result = await client . sendTransactionalEmail ( emailData ) ;
@@ -534,7 +534,7 @@ describe("LoopsClient", () => {
534534 global . fetch = jest . fn ( ) . mockResolvedValue ( {
535535 ok : false ,
536536 status : 404 ,
537- json : ( ) => Promise . resolve ( mockResponse ) ,
537+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
538538 } ) ;
539539
540540 await expect ( client . sendTransactionalEmail ( emailData ) ) . rejects . toThrow (
@@ -560,6 +560,103 @@ describe("LoopsClient", () => {
560560 } ) ;
561561 } ) ;
562562
563+ describe ( "non-JSON error responses" , ( ) => {
564+ it ( "should handle HTML error response" , async ( ) => {
565+ const htmlBody = "<html><body>502 Bad Gateway</body></html>" ;
566+ global . fetch = jest . fn ( ) . mockResolvedValue ( {
567+ ok : false ,
568+ status : 502 ,
569+ headers : new Headers ( ) ,
570+ text : ( ) => Promise . resolve ( htmlBody ) ,
571+ } ) ;
572+
573+ try {
574+ await client . testApiKey ( ) ;
575+ fail ( "Should have thrown" ) ;
576+ } catch ( error ) {
577+ expect ( error ) . toBeInstanceOf ( APIError ) ;
578+ expect ( ( error as APIError ) . statusCode ) . toBe ( 502 ) ;
579+ expect ( ( error as APIError ) . json ) . toBeNull ( ) ;
580+ expect ( ( error as APIError ) . rawBody ) . toBe ( htmlBody ) ;
581+ }
582+ } ) ;
583+
584+ it ( "should handle plain text error response" , async ( ) => {
585+ global . fetch = jest . fn ( ) . mockResolvedValue ( {
586+ ok : false ,
587+ status : 503 ,
588+ headers : new Headers ( ) ,
589+ text : ( ) => Promise . resolve ( "Service Unavailable" ) ,
590+ } ) ;
591+
592+ try {
593+ await client . testApiKey ( ) ;
594+ fail ( "Should have thrown" ) ;
595+ } catch ( error ) {
596+ expect ( error ) . toBeInstanceOf ( APIError ) ;
597+ expect ( ( error as APIError ) . statusCode ) . toBe ( 503 ) ;
598+ expect ( ( error as APIError ) . rawBody ) . toBe ( "Service Unavailable" ) ;
599+ }
600+ } ) ;
601+
602+ it ( "should handle empty body error response" , async ( ) => {
603+ global . fetch = jest . fn ( ) . mockResolvedValue ( {
604+ ok : false ,
605+ status : 500 ,
606+ headers : new Headers ( ) ,
607+ text : ( ) => Promise . resolve ( "" ) ,
608+ } ) ;
609+
610+ try {
611+ await client . testApiKey ( ) ;
612+ fail ( "Should have thrown" ) ;
613+ } catch ( error ) {
614+ expect ( error ) . toBeInstanceOf ( APIError ) ;
615+ expect ( ( error as APIError ) . json ) . toBeNull ( ) ;
616+ expect ( ( error as APIError ) . rawBody ) . toBe ( "" ) ;
617+ }
618+ } ) ;
619+
620+ it ( "should still parse valid JSON errors normally" , async ( ) => {
621+ const jsonError = { success : false , message : "Invalid API key" } ;
622+ global . fetch = jest . fn ( ) . mockResolvedValue ( {
623+ ok : false ,
624+ status : 401 ,
625+ headers : new Headers ( ) ,
626+ text : ( ) => Promise . resolve ( JSON . stringify ( jsonError ) ) ,
627+ } ) ;
628+
629+ try {
630+ await client . testApiKey ( ) ;
631+ fail ( "Should have thrown" ) ;
632+ } catch ( error ) {
633+ expect ( error ) . toBeInstanceOf ( APIError ) ;
634+ expect ( ( error as APIError ) . json ) . toEqual ( jsonError ) ;
635+ expect ( ( error as APIError ) . rawBody ) . toBeUndefined ( ) ;
636+ }
637+ } ) ;
638+
639+ it ( "should throw APIError when success response is not JSON" , async ( ) => {
640+ const htmlBody = "<html><body>OK</body></html>" ;
641+ global . fetch = jest . fn ( ) . mockResolvedValue ( {
642+ ok : true ,
643+ status : 200 ,
644+ headers : new Headers ( ) ,
645+ text : ( ) => Promise . resolve ( htmlBody ) ,
646+ } ) ;
647+
648+ try {
649+ await client . testApiKey ( ) ;
650+ fail ( "Should have thrown" ) ;
651+ } catch ( error ) {
652+ expect ( error ) . toBeInstanceOf ( APIError ) ;
653+ expect ( ( error as APIError ) . statusCode ) . toBe ( 200 ) ;
654+ expect ( ( error as APIError ) . json ) . toBeNull ( ) ;
655+ expect ( ( error as APIError ) . rawBody ) . toBe ( htmlBody ) ;
656+ }
657+ } ) ;
658+ } ) ;
659+
563660 describe ( "listTransactionalEmails" , ( ) => {
564661 it ( "should list transactional emails successfully" , async ( ) => {
565662 const mockTransactionalEmails = [
@@ -584,7 +681,7 @@ describe("LoopsClient", () => {
584681
585682 global . fetch = jest . fn ( ) . mockResolvedValue ( {
586683 ok : true ,
587- json : ( ) => Promise . resolve ( mockResponse ) ,
684+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
588685 } ) ;
589686
590687 const result = await client . getTransactionalEmails ( ) ;
@@ -620,7 +717,7 @@ describe("LoopsClient", () => {
620717
621718 global . fetch = jest . fn ( ) . mockResolvedValue ( {
622719 ok : true ,
623- json : ( ) => Promise . resolve ( mockResponse ) ,
720+ text : ( ) => Promise . resolve ( JSON . stringify ( mockResponse ) ) ,
624721 } ) ;
625722
626723 const result = await client . getTransactionalEmails ( ) ;
0 commit comments