@@ -181,6 +181,45 @@ Deno.test("handles 400 response with non-JSON text", async () => {
181181 ) ;
182182} ) ;
183183
184+ Deno . test ( "handles 403 with empty body without deserialization error" , async ( ) => {
185+ const mocks = new MockRegistry ( ) ;
186+ mocks . onPost ( "/api/resource" ) . reply ( 403 ) ;
187+
188+ const client = new FetchClient ( ) ;
189+ mocks . install ( client ) ;
190+
191+ // Should throw FetchClientError with status-based message, not a deserialization error
192+ const error = await assertRejects ( async ( ) => {
193+ await client . postJSON ( "https://example.com/api/resource" , { } ) ;
194+ } , FetchClientError ) ;
195+
196+ assert ( error instanceof FetchClientError ) ;
197+ assertEquals ( error . status , 403 ) ;
198+ assert ( error . response . problem ) ;
199+ assertEquals ( error . response . problem . status , 403 ) ;
200+ assertStringIncludes ( error . message , "Forbidden" ) ;
201+ // Should NOT contain deserialization error
202+ assertFalse ( error . message . includes ( "Unable to deserialize" ) ) ;
203+ } ) ;
204+
205+ Deno . test ( "handles empty body error response with expectedStatusCodes" , async ( ) => {
206+ const mocks = new MockRegistry ( ) ;
207+ mocks . onGet ( "/api/resource" ) . reply ( 403 ) ;
208+
209+ const client = new FetchClient ( ) ;
210+ mocks . install ( client ) ;
211+
212+ const res = await client . getJSON ( "https://example.com/api/resource" , {
213+ expectedStatusCodes : [ 403 ] ,
214+ } ) ;
215+
216+ assertFalse ( res . ok ) ;
217+ assertEquals ( res . status , 403 ) ;
218+ assert ( res . problem ) ;
219+ // Problem title should not mention deserialization failure
220+ assertFalse ( res . problem . title ?. includes ( "Unable to deserialize" ) ?? false ) ;
221+ } ) ;
222+
184223Deno . test ( "network error throws TypeError" , async ( ) => {
185224 const mocks = new MockRegistry ( ) ;
186225 mocks . onGet ( "/api/flaky" ) . networkError ( "Connection refused" ) ;
0 commit comments