@@ -23,35 +23,26 @@ import {isRunningInThread, isRunningInChildProcess} from './utils.cjs';
23
23
const currentlyUnhandled = setUpCurrentlyUnhandled ( ) ;
24
24
let runner ;
25
25
26
+ let forcingExit = false ;
27
+
28
+ const forceExit = ( ) => {
29
+ forcingExit = true ;
30
+ process . exit ( 1 ) ;
31
+ } ;
32
+
26
33
// Override process.exit with an undetectable replacement
27
34
// 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 } ) ;
35
40
}
36
41
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 ) ;
52
43
} ;
53
44
54
- process . exit = new Proxy ( realExit , {
45
+ process . exit = new Proxy ( process . exit , {
55
46
apply : handleProcessExit ,
56
47
} ) ;
57
48
@@ -101,7 +92,7 @@ const run = async options => {
101
92
102
93
runner . on ( 'error' , error => {
103
94
channel . send ( { type : 'internal-error' , err : serializeError ( error ) } ) ;
104
- exit ( 1 ) ;
95
+ forceExit ( ) ;
105
96
} ) ;
106
97
107
98
runner . on ( 'finish' , async ( ) => {
@@ -112,30 +103,35 @@ const run = async options => {
112
103
}
113
104
} catch ( error ) {
114
105
channel . send ( { type : 'internal-error' , err : serializeError ( error ) } ) ;
115
- exit ( 1 ) ;
106
+ forceExit ( ) ;
116
107
return ;
117
108
}
118
109
119
110
try {
120
111
await Promise . all ( sharedWorkerTeardowns . map ( fn => fn ( ) ) ) ;
121
112
} catch ( error ) {
122
113
channel . send ( { type : 'uncaught-exception' , err : serializeError ( error ) } ) ;
123
- exit ( 1 ) ;
114
+ forceExit ( ) ;
124
115
return ;
125
116
}
126
117
127
118
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 ) {
129
125
channel . send ( { type : 'unhandled-rejection' , err : serializeError ( rejection . reason , { testFile : options . file } ) } ) ;
130
126
}
131
127
132
- exit ( 0 ) ;
128
+ forceExit ( ) ;
133
129
} ) ;
134
130
} ) ;
135
131
136
132
process . on ( 'uncaughtException' , error => {
137
133
channel . send ( { type : 'uncaught-exception' , err : serializeError ( error , { testFile : options . file } ) } ) ;
138
- exit ( 1 ) ;
134
+ forceExit ( ) ;
139
135
} ) ;
140
136
141
137
// Store value to prevent required modules from modifying it.
@@ -248,11 +244,11 @@ const run = async options => {
248
244
channel . unref ( ) ;
249
245
} else {
250
246
channel . send ( { type : 'missing-ava-import' } ) ;
251
- exit ( 1 ) ;
247
+ forceExit ( ) ;
252
248
}
253
249
} catch ( error ) {
254
250
channel . send ( { type : 'uncaught-exception' , err : serializeError ( error , { testFile : options . file } ) } ) ;
255
- exit ( 1 ) ;
251
+ forceExit ( ) ;
256
252
}
257
253
} ;
258
254
0 commit comments