@@ -21,7 +21,7 @@ import net from 'net';
21
21
type TestChildParams = {
22
22
command : string [ ] ,
23
23
cwd ?: string ,
24
- env ?: { [ key : string ] : string | number | boolean | undefined } ,
24
+ env ?: NodeJS . ProcessEnv ,
25
25
shell ?: boolean ,
26
26
onOutput ?: ( ) => void ;
27
27
} ;
@@ -42,9 +42,13 @@ export class TestChildProcess {
42
42
env : {
43
43
...process . env ,
44
44
...params . env ,
45
- } as any ,
45
+ } ,
46
46
cwd : params . cwd ,
47
47
shell : params . shell ,
48
+ // On non-windows platforms, `detached: true` makes child process a leader of a new
49
+ // process group, making it possible to kill child process tree with `.kill(-pid)` command.
50
+ // @see https://nodejs.org/api/child_process.html#child_process_options_detached
51
+ detached : process . platform !== 'win32' ,
48
52
} ) ;
49
53
if ( process . env . PWTEST_DEBUG )
50
54
process . stdout . write ( `\n\nLaunching ${ params . command . join ( ' ' ) } \n` ) ;
@@ -63,32 +67,34 @@ export class TestChildProcess {
63
67
this . process . stderr . on ( 'data' , appendChunk ) ;
64
68
this . process . stdout . on ( 'data' , appendChunk ) ;
65
69
66
- const onExit = ( ) => {
67
- if ( ! this . process . pid || this . process . killed )
68
- return ;
69
- try {
70
- if ( process . platform === 'win32' )
71
- execSync ( `taskkill /pid ${ this . process . pid } /T /F /FI "MEMUSAGE gt 0"` ) ;
72
- else
73
- process . kill ( - this . process . pid , 'SIGKILL' ) ;
74
- } catch ( e ) {
75
- // the process might have already stopped
76
- }
77
- } ;
78
- process . on ( 'exit' , onExit ) ;
70
+ const killProcessGroup = this . _killProcessGroup . bind ( this ) ;
71
+ process . on ( 'exit' , killProcessGroup ) ;
79
72
this . exited = new Promise ( f => {
80
73
this . process . on ( 'exit' , ( exitCode , signal ) => f ( { exitCode, signal } ) ) ;
81
- process . off ( 'exit' , onExit ) ;
74
+ process . off ( 'exit' , killProcessGroup ) ;
82
75
} ) ;
83
76
this . exitCode = this . exited . then ( r => r . exitCode ) ;
84
77
}
85
78
86
79
async close ( ) {
87
80
if ( ! this . process . killed )
88
- this . process . kill ( ) ;
81
+ this . _killProcessGroup ( ) ;
89
82
return this . exited ;
90
83
}
91
84
85
+ private _killProcessGroup ( ) {
86
+ if ( ! this . process . pid || this . process . killed )
87
+ return ;
88
+ try {
89
+ if ( process . platform === 'win32' )
90
+ execSync ( `taskkill /pid ${ this . process . pid } /T /F /FI "MEMUSAGE gt 0"` ) ;
91
+ else
92
+ process . kill ( - this . process . pid , 'SIGKILL' ) ;
93
+ } catch ( e ) {
94
+ // the process might have already stopped
95
+ }
96
+ }
97
+
92
98
async cleanExit ( ) {
93
99
const r = await this . exited ;
94
100
if ( r . exitCode )
0 commit comments