@@ -1894,7 +1894,9 @@ abc123def456789012345678901234567890123456789012345678901234abcd
18941894 expect ( info . error ) . toBeDefined ( )
18951895 }
18961896 } finally {
1897- await new Promise < void > ( resolve => { testServer . close ( ( ) => resolve ( ) ) } )
1897+ await new Promise < void > ( resolve => {
1898+ testServer . close ( ( ) => resolve ( ) )
1899+ } )
18981900 }
18991901 } )
19001902
@@ -1994,8 +1996,8 @@ abc123def456789012345678901234567890123456789012345678901234abcd
19941996
19951997 // At least one hook call should contain the size limit error
19961998 expect ( responseInfos . length ) . toBeGreaterThanOrEqual ( 1 )
1997- const sizeError = responseInfos . find (
1998- info => info . error ?. message ?. includes ( 'exceeds maximum size limit' ) ,
1999+ const sizeError = responseInfos . find ( info =>
2000+ info . error ?. message ?. includes ( 'exceeds maximum size limit' ) ,
19992001 )
20002002 expect ( sizeError ) . toBeDefined ( )
20012003 } )
@@ -2010,7 +2012,9 @@ abc123def456789012345678901234567890123456789012345678901234abcd
20102012
20112013 it ( 'should have headers on rawResponse' , async ( ) => {
20122014 const response = await httpRequest ( `${ httpBaseUrl } /json` )
2013- expect ( response . rawResponse ! . headers [ 'content-type' ] ) . toContain ( 'application/json' )
2015+ expect ( response . rawResponse ! . headers [ 'content-type' ] ) . toContain (
2016+ 'application/json' ,
2017+ )
20142018 } )
20152019
20162020 it ( 'should be available on non-2xx responses' , async ( ) => {
@@ -2022,52 +2026,68 @@ abc123def456789012345678901234567890123456789012345678901234abcd
20222026
20232027 describe ( 'enrichErrorMessage' , ( ) => {
20242028 it ( 'should enrich ECONNREFUSED' , ( ) => {
2025- const err = Object . assign ( new Error ( 'connect failed' ) , { code : 'ECONNREFUSED' } ) as NodeJS . ErrnoException
2029+ const err = Object . assign ( new Error ( 'connect failed' ) , {
2030+ code : 'ECONNREFUSED' ,
2031+ } ) as NodeJS . ErrnoException
20262032 const msg = enrichErrorMessage ( 'http://localhost:1' , 'GET' , err )
20272033 expect ( msg ) . toContain ( 'Connection refused' )
20282034 expect ( msg ) . toContain ( 'GET request failed' )
20292035 } )
20302036
20312037 it ( 'should enrich ENOTFOUND' , ( ) => {
2032- const err = Object . assign ( new Error ( 'not found' ) , { code : 'ENOTFOUND' } ) as NodeJS . ErrnoException
2038+ const err = Object . assign ( new Error ( 'not found' ) , {
2039+ code : 'ENOTFOUND' ,
2040+ } ) as NodeJS . ErrnoException
20332041 const msg = enrichErrorMessage ( 'http://no-such-host.invalid' , 'POST' , err )
20342042 expect ( msg ) . toContain ( 'DNS lookup failed' )
20352043 expect ( msg ) . toContain ( 'POST request failed' )
20362044 } )
20372045
20382046 it ( 'should enrich ETIMEDOUT' , ( ) => {
2039- const err = Object . assign ( new Error ( 'timed out' ) , { code : 'ETIMEDOUT' } ) as NodeJS . ErrnoException
2047+ const err = Object . assign ( new Error ( 'timed out' ) , {
2048+ code : 'ETIMEDOUT' ,
2049+ } ) as NodeJS . ErrnoException
20402050 const msg = enrichErrorMessage ( 'http://example.com' , 'GET' , err )
20412051 expect ( msg ) . toContain ( 'Connection timed out' )
20422052 } )
20432053
20442054 it ( 'should enrich ECONNRESET' , ( ) => {
2045- const err = Object . assign ( new Error ( 'reset' ) , { code : 'ECONNRESET' } ) as NodeJS . ErrnoException
2055+ const err = Object . assign ( new Error ( 'reset' ) , {
2056+ code : 'ECONNRESET' ,
2057+ } ) as NodeJS . ErrnoException
20462058 const msg = enrichErrorMessage ( 'http://example.com' , 'GET' , err )
20472059 expect ( msg ) . toContain ( 'Connection reset' )
20482060 } )
20492061
20502062 it ( 'should enrich EPIPE' , ( ) => {
2051- const err = Object . assign ( new Error ( 'broken pipe' ) , { code : 'EPIPE' } ) as NodeJS . ErrnoException
2063+ const err = Object . assign ( new Error ( 'broken pipe' ) , {
2064+ code : 'EPIPE' ,
2065+ } ) as NodeJS . ErrnoException
20522066 const msg = enrichErrorMessage ( 'http://example.com' , 'PUT' , err )
20532067 expect ( msg ) . toContain ( 'Broken pipe' )
20542068 expect ( msg ) . toContain ( 'PUT request failed' )
20552069 } )
20562070
20572071 it ( 'should enrich CERT_HAS_EXPIRED' , ( ) => {
2058- const err = Object . assign ( new Error ( 'cert expired' ) , { code : 'CERT_HAS_EXPIRED' } ) as NodeJS . ErrnoException
2072+ const err = Object . assign ( new Error ( 'cert expired' ) , {
2073+ code : 'CERT_HAS_EXPIRED' ,
2074+ } ) as NodeJS . ErrnoException
20592075 const msg = enrichErrorMessage ( 'https://expired.example.com' , 'GET' , err )
20602076 expect ( msg ) . toContain ( 'SSL/TLS certificate error' )
20612077 } )
20622078
20632079 it ( 'should enrich UNABLE_TO_VERIFY_LEAF_SIGNATURE' , ( ) => {
2064- const err = Object . assign ( new Error ( 'leaf sig' ) , { code : 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' } ) as NodeJS . ErrnoException
2080+ const err = Object . assign ( new Error ( 'leaf sig' ) , {
2081+ code : 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' ,
2082+ } ) as NodeJS . ErrnoException
20652083 const msg = enrichErrorMessage ( 'https://badcert.example.com' , 'GET' , err )
20662084 expect ( msg ) . toContain ( 'SSL/TLS certificate error' )
20672085 } )
20682086
20692087 it ( 'should include error code for unknown codes' , ( ) => {
2070- const err = Object . assign ( new Error ( 'something' ) , { code : 'ESOMETHING' } ) as NodeJS . ErrnoException
2088+ const err = Object . assign ( new Error ( 'something' ) , {
2089+ code : 'ESOMETHING' ,
2090+ } ) as NodeJS . ErrnoException
20712091 const msg = enrichErrorMessage ( 'http://example.com' , 'DELETE' , err )
20722092 expect ( msg ) . toContain ( 'Error code: ESOMETHING' )
20732093 expect ( msg ) . toContain ( 'DELETE request failed' )
@@ -2079,5 +2099,151 @@ abc123def456789012345678901234567890123456789012345678901234abcd
20792099 expect ( msg ) . toContain ( 'GET request failed' )
20802100 expect ( msg ) . not . toContain ( 'Error code:' )
20812101 } )
2102+
2103+ it ( 'should include url in the message' , ( ) => {
2104+ const err = Object . assign ( new Error ( 'fail' ) , { code : 'ECONNREFUSED' } ) as NodeJS . ErrnoException
2105+ const msg = enrichErrorMessage ( 'http://my-server:8080/api' , 'GET' , err )
2106+ expect ( msg ) . toContain ( 'http://my-server:8080/api' )
2107+ } )
2108+ } )
2109+
2110+ describe ( 'hooks — edge cases' , ( ) => {
2111+ it ( 'should work with only onRequest (no onResponse)' , async ( ) => {
2112+ const infos : HttpHookRequestInfo [ ] = [ ]
2113+ await httpRequest ( `${ httpBaseUrl } /json` , {
2114+ hooks : { onRequest : info => infos . push ( info ) } ,
2115+ } )
2116+ expect ( infos ) . toHaveLength ( 1 )
2117+ } )
2118+
2119+ it ( 'should work with only onResponse (no onRequest)' , async ( ) => {
2120+ const infos : HttpHookResponseInfo [ ] = [ ]
2121+ await httpRequest ( `${ httpBaseUrl } /json` , {
2122+ hooks : { onResponse : info => infos . push ( info ) } ,
2123+ } )
2124+ expect ( infos ) . toHaveLength ( 1 )
2125+ expect ( infos [ 0 ] ! . status ) . toBe ( 200 )
2126+ } )
2127+
2128+ it ( 'should work with empty hooks object' , async ( ) => {
2129+ const response = await httpRequest ( `${ httpBaseUrl } /json` , { hooks : { } } )
2130+ expect ( response . ok ) . toBe ( true )
2131+ } )
2132+
2133+ it ( 'should pass hooks through httpJson' , async ( ) => {
2134+ const infos : HttpHookResponseInfo [ ] = [ ]
2135+ await httpJson ( `${ httpBaseUrl } /json` , {
2136+ hooks : { onResponse : info => infos . push ( info ) } ,
2137+ } )
2138+ expect ( infos ) . toHaveLength ( 1 )
2139+ expect ( infos [ 0 ] ! . status ) . toBe ( 200 )
2140+ } )
2141+
2142+ it ( 'should pass hooks through httpText' , async ( ) => {
2143+ const infos : HttpHookResponseInfo [ ] = [ ]
2144+ await httpText ( `${ httpBaseUrl } /text` , {
2145+ hooks : { onResponse : info => infos . push ( info ) } ,
2146+ } )
2147+ expect ( infos ) . toHaveLength ( 1 )
2148+ expect ( infos [ 0 ] ! . status ) . toBe ( 200 )
2149+ } )
2150+
2151+ it ( 'should include response headers in onResponse' , async ( ) => {
2152+ const infos : HttpHookResponseInfo [ ] = [ ]
2153+ await httpRequest ( `${ httpBaseUrl } /json` , {
2154+ hooks : { onResponse : info => infos . push ( info ) } ,
2155+ } )
2156+ expect ( infos [ 0 ] ! . headers ) . toBeDefined ( )
2157+ const ct = infos [ 0 ] ! . headers ?. [ 'content-type' ]
2158+ expect ( ct ) . toContain ( 'application/json' )
2159+ } )
2160+
2161+ it ( 'should report non-zero duration in onResponse' , async ( ) => {
2162+ const infos : HttpHookResponseInfo [ ] = [ ]
2163+ await httpRequest ( `${ httpBaseUrl } /slow` , {
2164+ hooks : { onResponse : info => infos . push ( info ) } ,
2165+ } )
2166+ expect ( infos [ 0 ] ! . duration ) . toBeGreaterThanOrEqual ( 0 )
2167+ } )
2168+ } )
2169+
2170+ describe ( 'maxResponseSize — edge cases' , ( ) => {
2171+ it ( 'should allow response exactly at maxResponseSize' , async ( ) => {
2172+ // /json body is small (<1000 bytes); set limit to its exact size
2173+ const probe = await httpRequest ( `${ httpBaseUrl } /json` )
2174+ const exactSize = probe . body . length
2175+
2176+ const response = await httpRequest ( `${ httpBaseUrl } /json` , {
2177+ maxResponseSize : exactSize ,
2178+ } )
2179+ expect ( response . ok ) . toBe ( true )
2180+ expect ( response . body . length ) . toBe ( exactSize )
2181+ } )
2182+
2183+ it ( 'should reject when maxResponseSize is 0' , async ( ) => {
2184+ // 0 is falsy so should be treated as "no limit"
2185+ const response = await httpRequest ( `${ httpBaseUrl } /json` , {
2186+ maxResponseSize : 0 ,
2187+ } )
2188+ expect ( response . ok ) . toBe ( true )
2189+ } )
2190+
2191+ it ( 'should enforce maxResponseSize on redirected response' , async ( ) => {
2192+ // /redirect -> /text (19 bytes "Plain text response")
2193+ await expect (
2194+ httpRequest ( `${ httpBaseUrl } /redirect` , {
2195+ maxResponseSize : 5 ,
2196+ } ) ,
2197+ ) . rejects . toThrow ( / e x c e e d s m a x i m u m s i z e l i m i t / )
2198+ } )
2199+ } )
2200+
2201+ describe ( 'rawResponse — edge cases' , ( ) => {
2202+ it ( 'should have rawResponse after redirect' , async ( ) => {
2203+ const response = await httpRequest ( `${ httpBaseUrl } /redirect` )
2204+ expect ( response . rawResponse ) . toBeDefined ( )
2205+ // rawResponse should be from the final response, not the redirect
2206+ expect ( response . rawResponse ! . statusCode ) . toBe ( 200 )
2207+ } )
2208+
2209+ it ( 'should have rawResponse on server error' , async ( ) => {
2210+ const response = await httpRequest ( `${ httpBaseUrl } /server-error` )
2211+ expect ( response . rawResponse ) . toBeDefined ( )
2212+ expect ( response . rawResponse ! . statusCode ) . toBe ( 500 )
2213+ } )
2214+ } )
2215+
2216+ describe ( 'enriched error messages — integration' , ( ) => {
2217+ it ( 'should include method and url in timeout errors' , async ( ) => {
2218+ try {
2219+ await httpRequest ( `${ httpBaseUrl } /timeout` , { timeout : 50 } )
2220+ expect . unreachable ( 'should have thrown' )
2221+ } catch ( e ) {
2222+ const msg = ( e as Error ) . message
2223+ expect ( msg ) . toContain ( 'GET' )
2224+ expect ( msg ) . toContain ( 'timed out' )
2225+ expect ( msg ) . toContain ( `${ httpBaseUrl } /timeout` )
2226+ }
2227+ } )
2228+
2229+ it ( 'should include method and url in connection errors' , async ( ) => {
2230+ try {
2231+ await httpRequest ( 'http://localhost:1/no-server' , { timeout : 100 } )
2232+ expect . unreachable ( 'should have thrown' )
2233+ } catch ( e ) {
2234+ const msg = ( e as Error ) . message
2235+ expect ( msg ) . toContain ( 'request failed' )
2236+ expect ( msg ) . toContain ( 'localhost:1' )
2237+ }
2238+ } )
2239+
2240+ it ( 'should preserve cause chain on network errors' , async ( ) => {
2241+ try {
2242+ await httpRequest ( 'http://localhost:1/no-server' , { timeout : 100 } )
2243+ expect . unreachable ( 'should have thrown' )
2244+ } catch ( e ) {
2245+ expect ( ( e as Error ) . cause ) . toBeDefined ( )
2246+ }
2247+ } )
20822248 } )
20832249} )
0 commit comments