@@ -23,35 +23,26 @@ import {isRunningInThread, isRunningInChildProcess} from './utils.cjs';
2323const currentlyUnhandled = setUpCurrentlyUnhandled ( ) ;
2424let runner ;
2525
26+ let forcingExit = false ;
27+
28+ const forceExit = ( ) => {
29+ forcingExit = true ;
30+ process . exit ( 1 ) ;
31+ } ;
32+
2633// Override process.exit with an undetectable replacement
2734// to report when it is called from a test (which it should never be).
28- const { apply} = Reflect ;
29- const realExit = process . exit ;
30-
31- async function exit ( code , forceSync = false ) {
32- const flushing = channel . flush ( ) ;
33- if ( ! forceSync ) {
34- await flushing ;
35+ const handleProcessExit = ( target , thisArg , args ) => {
36+ if ( ! forcingExit ) {
37+ const error = new Error ( 'Unexpected process.exit()' ) ;
38+ Error . captureStackTrace ( error , handleProcessExit ) ;
39+ channel . send ( { type : 'process-exit' , stack : error . stack } ) ;
3540 }
3641
37- apply ( realExit , process , [ code ] ) ;
38- }
39-
40- const handleProcessExit = ( fn , receiver , args ) => {
41- const error = new Error ( 'Unexpected process.exit()' ) ;
42- Error . captureStackTrace ( error , handleProcessExit ) ;
43- channel . send ( { type : 'process-exit' , stack : error . stack } ) ;
44-
45- // Make sure to extract the code only from `args` rather than e.g. `Array.prototype`.
46- // This level of paranoia is usually unwarranted, but we're dealing with test code
47- // that has already colored outside the lines.
48- const code = args . length > 0 ? args [ 0 ] : undefined ;
49-
50- // Force a synchronous exit as guaranteed by the real process.exit().
51- exit ( code , true ) ;
42+ target . apply ( thisArg , args ) ;
5243} ;
5344
54- process . exit = new Proxy ( realExit , {
45+ process . exit = new Proxy ( process . exit , {
5546 apply : handleProcessExit ,
5647} ) ;
5748
@@ -101,7 +92,7 @@ const run = async options => {
10192
10293 runner . on ( 'error' , error => {
10394 channel . send ( { type : 'internal-error' , err : serializeError ( error ) } ) ;
104- exit ( 1 ) ;
95+ forceExit ( ) ;
10596 } ) ;
10697
10798 runner . on ( 'finish' , async ( ) => {
@@ -112,30 +103,35 @@ const run = async options => {
112103 }
113104 } catch ( error ) {
114105 channel . send ( { type : 'internal-error' , err : serializeError ( error ) } ) ;
115- exit ( 1 ) ;
106+ forceExit ( ) ;
116107 return ;
117108 }
118109
119110 try {
120111 await Promise . all ( sharedWorkerTeardowns . map ( fn => fn ( ) ) ) ;
121112 } catch ( error ) {
122113 channel . send ( { type : 'uncaught-exception' , err : serializeError ( error ) } ) ;
123- exit ( 1 ) ;
114+ forceExit ( ) ;
124115 return ;
125116 }
126117
127118 nowAndTimers . setImmediate ( ( ) => {
128- for ( const rejection of currentlyUnhandled ( ) ) {
119+ const unhandled = currentlyUnhandled ( ) ;
120+ if ( unhandled . length === 0 ) {
121+ return ;
122+ }
123+
124+ for ( const rejection of unhandled ) {
129125 channel . send ( { type : 'unhandled-rejection' , err : serializeError ( rejection . reason , { testFile : options . file } ) } ) ;
130126 }
131127
132- exit ( 0 ) ;
128+ forceExit ( ) ;
133129 } ) ;
134130 } ) ;
135131
136132 process . on ( 'uncaughtException' , error => {
137133 channel . send ( { type : 'uncaught-exception' , err : serializeError ( error , { testFile : options . file } ) } ) ;
138- exit ( 1 ) ;
134+ forceExit ( ) ;
139135 } ) ;
140136
141137 // Store value to prevent required modules from modifying it.
@@ -248,11 +244,11 @@ const run = async options => {
248244 channel . unref ( ) ;
249245 } else {
250246 channel . send ( { type : 'missing-ava-import' } ) ;
251- exit ( 1 ) ;
247+ forceExit ( ) ;
252248 }
253249 } catch ( error ) {
254250 channel . send ( { type : 'uncaught-exception' , err : serializeError ( error , { testFile : options . file } ) } ) ;
255- exit ( 1 ) ;
251+ forceExit ( ) ;
256252 }
257253} ;
258254
0 commit comments