@@ -192,4 +192,53 @@ describe("runHttpRequest", () => {
192192 // Clean up
193193 subscription . unsubscribe ( ) ;
194194 } ) ;
195+
196+ it ( "should throw HTTP error on occurs" , async ( ) => {
197+ // Mock a 404 error response with JSON body
198+ const mockHeaders = new Headers ( ) ;
199+ mockHeaders . append ( "content-type" , "application/json" ) ;
200+
201+ const mockText = '{"message":"User not found"}' ;
202+
203+ const mockResponse = {
204+ ok : false ,
205+ status : 404 ,
206+ headers : mockHeaders ,
207+ // our error-path reads .text() (not streaming)
208+ text : jest . fn ( ) . mockResolvedValue ( mockText ) ,
209+ } as unknown as Response ;
210+
211+ // Override fetch for this test
212+ fetchMock . mockResolvedValue ( mockResponse ) ;
213+
214+ const observable = runHttpRequest ( "https://example.com/api" , { method : "GET" } ) ;
215+
216+ const nextSpy = jest . fn ( ) ;
217+
218+ await new Promise < void > ( ( resolve ) => {
219+ const sub = observable . subscribe ( {
220+ next : nextSpy ,
221+ error : ( err : any ) => {
222+ // error should carry status + parsed payload
223+ expect ( err ) . toBeInstanceOf ( Error ) ;
224+ expect ( err . status ) . toBe ( 404 ) ;
225+ expect ( err . payload ) . toEqual ( { message : "User not found" } ) ;
226+ // readable message is okay too (optional)
227+ expect ( err . message ) . toContain ( "HTTP 404" ) ;
228+ expect ( err . message ) . toContain ( "User not found" ) ;
229+ resolve ( ) ;
230+ sub . unsubscribe ( ) ;
231+ } ,
232+ complete : ( ) => {
233+ fail ( "Should not complete on HTTP error" ) ;
234+ } ,
235+ } ) ;
236+ } ) ;
237+
238+ // Should not have emitted any data events on error short-circuit
239+ expect ( nextSpy ) . not . toHaveBeenCalled ( ) ;
240+
241+ // Ensure we read the error body exactly once
242+ expect ( ( mockResponse as any ) . text ) . toHaveBeenCalledTimes ( 1 ) ;
243+ } ) ;
195244} ) ;
0 commit comments