@@ -436,3 +436,82 @@ describe('devframeTerminalHost interactive PTY sessions', () => {
436436 expect ( ( ) => session . resize ( 100 , 30 ) ) . not . toThrow ( )
437437 } )
438438} )
439+
440+ describe ( 'devframeTerminalHost PTY status lifecycle' , ( ) => {
441+ itPty ( 'marks status stopped and emits an update on a clean exit' , async ( ) => {
442+ const { host } = createTerminalHost ( )
443+ const updates : string [ ] = [ ]
444+ host . events . on ( 'terminal:session:updated' , s => updates . push ( s . status ) )
445+
446+ const session = await host . startPtySession ( {
447+ command : NODE ,
448+ args : [ '-e' , 'process.exit(0)' ] ,
449+ } , { id : 'pty-status' , title : 'PTY status' } )
450+
451+ await waitUntil ( ( ) => {
452+ expect ( session . status ) . toBe ( 'stopped' )
453+ } )
454+ expect ( updates ) . toContain ( 'stopped' )
455+ } )
456+
457+ itPty ( 'marks status error on a non-zero exit' , async ( ) => {
458+ const { host } = createTerminalHost ( )
459+
460+ const session = await host . startPtySession ( {
461+ command : NODE ,
462+ args : [ '-e' , 'process.exit(3)' ] ,
463+ } , { id : 'pty-status-error' , title : 'PTY status error' } )
464+
465+ await waitUntil ( ( ) => {
466+ expect ( session . status ) . toBe ( 'error' )
467+ } )
468+ } )
469+
470+ itPty ( 'marks status stopped on terminate() rather than error' , async ( ) => {
471+ const { host, sinks } = createTerminalHost ( )
472+
473+ const session = await host . startPtySession ( {
474+ command : NODE ,
475+ args : [ '-e' , 'setInterval(() => {}, 4000)' ] ,
476+ } , { id : 'pty-status-terminate' , title : 'PTY status terminate' } )
477+
478+ expect ( session . status ) . toBe ( 'running' )
479+ await session . terminate ( )
480+
481+ await waitUntil ( ( ) => {
482+ expect ( sinks . get ( 'pty-status-terminate' ) ?. closed ) . toBe ( true )
483+ } )
484+ expect ( session . status ) . toBe ( 'stopped' )
485+ } )
486+
487+ itPty ( 'returns to running after restart() without an error flash' , async ( ) => {
488+ const { host } = createTerminalHost ( )
489+
490+ const session = await host . startPtySession ( {
491+ command : NODE ,
492+ args : [ '-e' , 'setInterval(() => {}, 4000)' ] ,
493+ } , { id : 'pty-status-restart' , title : 'PTY status restart' } )
494+
495+ await session . restart ( )
496+ expect ( session . status ) . toBe ( 'running' )
497+
498+ await session . terminate ( )
499+ } )
500+
501+ itPty ( 'keeps status stopped when restart() is called after the process exited' , async ( ) => {
502+ const { host } = createTerminalHost ( )
503+
504+ const session = await host . startPtySession ( {
505+ command : NODE ,
506+ args : [ '-e' , 'process.exit(0)' ] ,
507+ } , { id : 'pty-status-restart-exited' , title : 'PTY status restart exited' } )
508+
509+ await waitUntil ( ( ) => {
510+ expect ( session . status ) . toBe ( 'stopped' )
511+ } )
512+ // The stream is closed for good, so `restart()` is a no-op — the session
513+ // stays reported as stopped rather than flipping back to running.
514+ await session . restart ( )
515+ expect ( session . status ) . toBe ( 'stopped' )
516+ } )
517+ } )
0 commit comments