@@ -2081,3 +2081,93 @@ describe('dev ui fallback', () => {
20812081 expect ( setupDevUI ( context as never , { enabled : false } ) . interactive ) . toBe ( false )
20822082 } )
20832083} )
2084+
2085+ /** Long enough for the panel's trailing repaint to land. */
2086+ const TICKER_SETTLE_MS = 400
2087+
2088+ describe ( 'request failures on the panel' , ( ) => {
2089+ const context = {
2090+ listener : { url : 'http://localhost:3000/' , getURLs : ( ) => [ ] , showURLs : ( ) => { } } ,
2091+ close : async ( ) => { } ,
2092+ onReady : ( ) => { } ,
2093+ }
2094+
2095+ async function withPanel ( run : ( ui : ReturnType < typeof setupDevUI > , settle : ( ) => Promise < string > ) => Promise < void > ) : Promise < void > {
2096+ const chunks : string [ ] = [ ]
2097+ const saved = ( [ 'isTTY' , 'columns' , 'rows' ] as const ) . map ( key => [ key , Object . getOwnPropertyDescriptor ( process . stdout , key ) ] as const )
2098+ const stdin = Object . getOwnPropertyDescriptor ( process . stdin , 'isTTY' )
2099+ const setRawMode = Object . getOwnPropertyDescriptor ( process . stdin , 'setRawMode' )
2100+ Object . defineProperty ( process . stdout , 'isTTY' , { value : true , configurable : true } )
2101+ Object . defineProperty ( process . stdout , 'columns' , { value : 100 , configurable : true } )
2102+ Object . defineProperty ( process . stdout , 'rows' , { value : 30 , configurable : true } )
2103+ Object . defineProperty ( process . stdin , 'isTTY' , { value : true , configurable : true } )
2104+ Object . defineProperty ( process . stdin , 'setRawMode' , { value : ( ) => process . stdin , configurable : true } )
2105+ const write = vi . spyOn ( process . stdout , 'write' ) . mockImplementation ( ( chunk : unknown ) => {
2106+ chunks . push ( String ( chunk ) )
2107+ return true
2108+ } )
2109+ const session = beginDevUI ( { ci : false , test : false , version : '4.5.2' } ) !
2110+ const ui = setupDevUI ( context as never , { ci : false , test : false , version : '4.5.2' } )
2111+ try {
2112+ await run ( ui , async ( ) => {
2113+ // The panel repaints on a trailing timer, so nothing is on screen yet.
2114+ await new Promise ( resolve => setTimeout ( resolve , TICKER_SETTLE_MS ) )
2115+ return strip ( chunks . join ( '' ) )
2116+ } )
2117+ }
2118+ finally {
2119+ session . teardown ( )
2120+ write . mockRestore ( )
2121+ for ( const [ key , descriptor ] of saved ) {
2122+ if ( descriptor ) {
2123+ Object . defineProperty ( process . stdout , key , descriptor )
2124+ }
2125+ }
2126+ if ( stdin ) {
2127+ Object . defineProperty ( process . stdin , 'isTTY' , stdin )
2128+ }
2129+ if ( setRawMode ) {
2130+ Object . defineProperty ( process . stdin , 'setRawMode' , setRawMode )
2131+ }
2132+ else {
2133+ Reflect . deleteProperty ( process . stdin , 'setRawMode' )
2134+ }
2135+ }
2136+ }
2137+
2138+ it ( 'should not report the bundler\'s own failed probes as failed requests' , async ( ) => {
2139+ await withPanel ( async ( ui , settle ) => {
2140+ ui . setStatus ( 'building' )
2141+ ui . pushRequests ( [ { method : 'GET' , url : '/__skip_vite' , status : 503 , duration : 1 , internal : true } ] )
2142+ const frames = await settle ( )
2143+
2144+ expect ( frames ) . not . toContain ( 'failed request' )
2145+ expect ( frames ) . not . toContain ( 'a request failed' )
2146+ } )
2147+ } )
2148+
2149+ it ( 'should report a failed app request' , async ( ) => {
2150+ await withPanel ( async ( ui , settle ) => {
2151+ ui . setStatus ( 'ready' )
2152+ ui . pushRequests ( [ { method : 'GET' , url : '/' , status : 500 , duration : 1 } ] )
2153+ const frames = await settle ( )
2154+
2155+ expect ( frames ) . toContain ( '1 failed request' )
2156+ expect ( frames ) . toContain ( 'a request failed' )
2157+ } )
2158+ } )
2159+
2160+ it ( 'should not let an internal request clear a failure the app reported' , async ( ) => {
2161+ await withPanel ( async ( ui , settle ) => {
2162+ ui . setStatus ( 'ready' )
2163+ ui . pushRequests ( [ { method : 'GET' , url : '/' , status : 500 , duration : 1 } ] )
2164+ await settle ( )
2165+ ui . pushRequests ( [ { method : 'GET' , url : '/__skip_vite' , status : 200 , duration : 1 , internal : true } ] )
2166+ const frames = await settle ( )
2167+
2168+ const last = frames . slice ( frames . lastIndexOf ( 'Nuxt 4.5.2' ) )
2169+ expect ( last ) . toContain ( 'ERROR' )
2170+ expect ( last ) . toContain ( 'a request failed' )
2171+ } )
2172+ } )
2173+ } )
0 commit comments