1- import { beforeEach , describe , expect , it , vi } from "vitest" ;
1+ import { afterEach , beforeEach , describe , expect , it , vi } from "vitest" ;
22
33const mocks = vi . hoisted ( ( ) => ( {
44 dashboardStart : vi . fn ( ) ,
@@ -45,7 +45,14 @@ vi.mock("../src/history/event-store.js", () => ({
4545} ) ) ;
4646
4747describe ( "runtime bootstrap" , ( ) => {
48+ let sigintListeners : NodeJS . SignalsListener [ ] ;
49+ let sigtermListeners : NodeJS . SignalsListener [ ] ;
50+ let stdinEndListeners : Array < ( ...args : unknown [ ] ) => void > ;
51+
4852 beforeEach ( ( ) => {
53+ sigintListeners = process . listeners ( "SIGINT" ) as NodeJS . SignalsListener [ ] ;
54+ sigtermListeners = process . listeners ( "SIGTERM" ) as NodeJS . SignalsListener [ ] ;
55+ stdinEndListeners = process . stdin . listeners ( "end" ) as Array < ( ...args : unknown [ ] ) => void > ;
4956 vi . resetModules ( ) ;
5057 vi . clearAllMocks ( ) ;
5158 mocks . serverRun . mockResolvedValue ( undefined ) ;
@@ -57,13 +64,29 @@ describe("runtime bootstrap", () => {
5764 delete process . env . PROMPT_REFINER_BACKGROUND ;
5865 } ) ;
5966
67+ afterEach ( ( ) => {
68+ process . removeAllListeners ( "SIGINT" ) ;
69+ process . removeAllListeners ( "SIGTERM" ) ;
70+ process . stdin . removeAllListeners ( "end" ) ;
71+ for ( const listener of sigintListeners ) process . on ( "SIGINT" , listener ) ;
72+ for ( const listener of sigtermListeners ) process . on ( "SIGTERM" , listener ) ;
73+ for ( const listener of stdinEndListeners ) process . stdin . on ( "end" , listener ) ;
74+ vi . restoreAllMocks ( ) ;
75+ } ) ;
76+
6077 it ( "starts a lightweight MCP server without competing background services" , async ( ) => {
6178 await import ( "../src/index.js" ) ;
6279
6380 expect ( mocks . dashboardStart ) . not . toHaveBeenCalled ( ) ;
6481 expect ( mocks . serverConstructor ) . toHaveBeenCalledWith ( process . cwd ( ) ) ;
6582 expect ( mocks . watcherConstructor ) . not . toHaveBeenCalled ( ) ;
6683 expect ( mocks . serverRun ) . toHaveBeenCalledWith ( { background : false } ) ;
84+
85+ const stdinHandler = process . stdin . listeners ( "end" ) . at ( - 1 ) as ( ) => void ;
86+ stdinHandler ( ) ;
87+ stdinHandler ( ) ;
88+ await vi . waitFor ( ( ) => expect ( mocks . serverStop ) . toHaveBeenCalledOnce ( ) ) ;
89+ expect ( mocks . flush ) . toHaveBeenCalledOnce ( ) ;
6790 } ) ;
6891
6992 it ( "starts background ownership explicitly and exits on fatal server failure" , async ( ) => {
@@ -79,7 +102,33 @@ describe("runtime bootstrap", () => {
79102
80103 expect ( mocks . dashboardStart ) . toHaveBeenCalledWith ( 4321 , process . cwd ( ) ) ;
81104 expect ( mocks . watcherStart ) . toHaveBeenCalledOnce ( ) ;
105+ const changeHandler = mocks . watcherOn . mock . calls . find ( call => call [ 0 ] === "change" ) ?. [ 1 ] ;
106+ changeHandler ( { event : "change" , path : `${ process . cwd ( ) } \\src\\a.ts` } ) ;
107+ expect ( mocks . loggerInfo ) . toHaveBeenCalledWith ( expect . stringContaining ( "[FS] change" ) ) ;
108+ expect ( mocks . dashboardLog ) . toHaveBeenCalledWith ( expect . stringContaining ( "[FS] change" ) ) ;
82109 expect ( consoleError ) . toHaveBeenCalledWith ( "[FATAL ERROR]" , error ) ;
83110 expect ( mocks . serverStop ) . toHaveBeenCalledOnce ( ) ;
84111 } ) ;
112+
113+ it ( "ignores stdin end while background ownership is active" , async ( ) => {
114+ process . env . PROMPT_REFINER_BACKGROUND = "true" ;
115+ await import ( "../src/index.js" ) ;
116+
117+ const stdinHandler = process . stdin . listeners ( "end" ) . at ( - 1 ) as ( ) => void ;
118+ stdinHandler ( ) ;
119+
120+ await new Promise ( resolve => setTimeout ( resolve , 0 ) ) ;
121+ expect ( mocks . serverStop ) . not . toHaveBeenCalled ( ) ;
122+ } ) ;
123+
124+ it ( "shuts down on process signals" , async ( ) => {
125+ const exit = vi . spyOn ( process , "exit" ) . mockImplementation ( ( ( ) => undefined ) as never ) ;
126+
127+ await import ( "../src/index.js" ) ;
128+ const signalHandler = process . listeners ( "SIGTERM" ) . at ( - 1 ) as ( ) => void ;
129+ signalHandler ( ) ;
130+
131+ await vi . waitFor ( ( ) => expect ( exit ) . toHaveBeenCalledWith ( 0 ) ) ;
132+ expect ( mocks . serverStop ) . toHaveBeenCalledOnce ( ) ;
133+ } ) ;
85134} ) ;
0 commit comments