@@ -3,7 +3,7 @@ import { TerminalService } from '@/main/terminal'
33
44/** Stub sessions by terminal id, populated by the mock below. */
55const { stubSessions } = vi . hoisted ( ( ) => ( {
6- stubSessions : new Map < string , { setBusy ( busy : boolean ) : void } > ( ) ,
6+ stubSessions : new Map < string , { setBusy ( busy : boolean ) : void ; exit ( ) : void } > ( ) ,
77} ) )
88
99/**
@@ -19,12 +19,26 @@ vi.mock('@/main/terminal/session', async () => {
1919 return {
2020 ...actual ,
2121 TerminalSession : {
22- create : ( { terminalId, cwd, cols, rows } : Record < string , never > & { terminalId : string } ) => {
22+ create : ( {
23+ terminalId,
24+ cwd,
25+ cols,
26+ rows,
27+ callbacks,
28+ } : Record < string , never > & {
29+ terminalId : string
30+ callbacks : { onExit ( terminalId : string ) : void }
31+ } ) => {
2332 const state = { cwd, disposed : false , busy : false }
2433 const stub = {
2534 setBusy : ( busy : boolean ) => {
2635 state . busy = busy
2736 } ,
37+ /** Stands in for the user running `exit` or pressing Ctrl-D. */
38+ exit : ( ) => {
39+ state . disposed = true
40+ callbacks . onExit ( terminalId )
41+ } ,
2842 terminalId,
2943 cols,
3044 rows,
@@ -237,3 +251,33 @@ describe('closing', () => {
237251 expect ( terminal . getTabs ( ) . tabs ) . toHaveLength ( 1 )
238252 } )
239253} )
254+
255+ describe ( 'a shell that ends by itself' , ( ) => {
256+ it ( 'replaces the only terminal instead of leaving a dead tab' , ( ) => {
257+ const terminal = service ( )
258+ const { activeTerminalId } = terminal . start ( { cols : 80 , rows : 24 } )
259+ const original = activeTerminalId as string
260+
261+ stubSessions . get ( original ) ?. exit ( )
262+
263+ // The panel's whole content is the terminal, so an exited last shell used
264+ // to sit there unusable — nothing to type into and no way to get it back.
265+ const after = terminal . getTabs ( )
266+ expect ( after . tabs ) . toHaveLength ( 1 )
267+ expect ( after . activeTerminalId ) . not . toBe ( original )
268+ expect ( after . tabs [ 0 ] ?. terminalId ) . toBe ( after . activeTerminalId )
269+ } )
270+
271+ it ( 'removes one of several and activates a neighbour' , ( ) => {
272+ const terminal = service ( )
273+ terminal . start ( { cols : 80 , rows : 24 } )
274+ const second = terminal . openTerminal ( ) . activeTerminalId as string
275+
276+ stubSessions . get ( second ) ?. exit ( )
277+
278+ const after = terminal . getTabs ( )
279+ expect ( after . tabs . map ( ( tab ) => tab . terminalId ) ) . not . toContain ( second )
280+ expect ( after . tabs ) . toHaveLength ( 1 )
281+ expect ( after . activeTerminalId ) . toBe ( after . tabs [ 0 ] ?. terminalId )
282+ } )
283+ } )
0 commit comments