@@ -38,8 +38,9 @@ function openPort(
3838 } as unknown as SerialPort ;
3939}
4040
41- // A closed port whose open() always rejects. Defaults to a non-NetworkError
42- // (the reopen bails fast); pass a NetworkError to exercise the retry window.
41+ // A closed port whose open() always rejects. Defaults to a non-NetworkError;
42+ // the reopen falls through to the next candidate either way, so pass a
43+ // NetworkError only when a test cares about the error kind.
4344function deadPort (
4445 error : unknown = new DOMException ( "blocked" , "SecurityError" )
4546) : SerialPort {
@@ -216,21 +217,28 @@ describe("attachSerialLogStream reopen", () => {
216217 }
217218 } ) ;
218219
219- it ( "fails fast on a non-recoverable open error (no waiting out the window)" , async ( ) => {
220- const errSpy = vi . spyOn ( console , "error" ) . mockImplementation ( ( ) => { } ) ;
221- const restore = withGetPorts ( async ( ) => [ ] ) ;
220+ it ( "falls through a non-NetworkError fresh handle to the cached port" , async ( ) => {
221+ // A re-enumerated handle that fails non-NetworkError (e.g. SecurityError on
222+ // a phantom UART bridge) must not abandon the cached fallback the loop
223+ // exists to provide. Resolves on the first round, so no fake timers.
224+ const cached = {
225+ readable : null ,
226+ getInfo : ( ) => ( { usbVendorId : 0x303a , usbProductId : 0x1001 } ) ,
227+ open : vi . fn ( ) . mockResolvedValue ( undefined ) ,
228+ setSignals : vi . fn ( ) . mockResolvedValue ( undefined ) ,
229+ } as unknown as SerialPort ;
230+ const restore = withGetPorts ( async ( ) => [
231+ deadPort ( new DOMException ( "blocked" , "SecurityError" ) ) ,
232+ ] ) ;
222233 const dialog = stubDialog ( ) ;
223234 try {
224- // SecurityError won't fix itself by waiting — bail without fake timers.
225- await attachSerialLogStream ( deadPort ( ) , dialog as never , defaultLocalize , 115200 ) ;
226- expect ( dialog . setSerialOpenFailed ) . toHaveBeenCalledTimes ( 1 ) ;
227- expect ( dialog . setSerialOpenFailed . mock . calls [ 0 ] [ 0 ] as string ) . toContain (
228- "USB 303a:1001"
229- ) ;
230- expect ( toastError ) . toHaveBeenCalledTimes ( 1 ) ;
231- expect ( errSpy ) . toHaveBeenCalled ( ) ;
235+ await attachSerialLogStream ( cached , dialog as never , defaultLocalize , 115200 ) ;
236+ expect ( cached . open ) . toHaveBeenCalledWith ( { baudRate : 115200 } ) ;
237+ expect ( dialog . setSerialStream ) . toHaveBeenCalledTimes ( 1 ) ;
238+ expect ( dialog . setSerialStream . mock . calls [ 0 ] [ 0 ] ) . toBe ( cached ) ;
239+ expect ( dialog . setSerialOpenFailed ) . not . toHaveBeenCalled ( ) ;
240+ expect ( toastError ) . not . toHaveBeenCalled ( ) ;
232241 } finally {
233- errSpy . mockRestore ( ) ;
234242 restore ( ) ;
235243 }
236244 } ) ;
0 commit comments