@@ -6,10 +6,37 @@ const {
66  getSummary, 
77  resolveFixturePath
88}  =  require ( '../helpers' ) ; 
9- const  pidtree  =  require ( 'pidtree'  ) ; 
9+ const  psList  =  require ( 'ps-list'  ) . default ; 
1010
1111const  REPORTER_FIXTURE_PATH  =  resolveFixturePath ( 'options/parallel/test-a' ) ; 
1212
13+ /** 
14+  * Get child processes of a given PID using ps-list 
15+  * @param  {number } pid - Parent process ID 
16+  * @param  {Object } options - Options object 
17+  * @param  {boolean } options.root - Include the parent PID in results 
18+  * @returns  {Promise<number[]> } Array of child process PIDs 
19+  */ 
20+ async  function  getChildPids ( pid )  { 
21+   return  ( 
22+     ( await  psList ( ) ) 
23+       // ppid = parent process ID 
24+       . filter ( proc  =>  proc . ppid  ===  pid ) 
25+       . map ( proc  =>  proc . pid ) 
26+   ) ; 
27+ } 
28+ 
29+ /** 
30+  * Check if a process exists using ps-list 
31+  * @param  {number } pid - Process ID to check 
32+  * @param  {Object } options - Options object 
33+  * @param  {boolean } options.root - Include the PID itself in results 
34+  * @returns  {Promise<boolean> } Array with the PID if exists, null otherwise 
35+  */ 
36+ async  function  checkProcessExists ( pid )  { 
37+   return  ( await  psList ( ) ) . some ( proc  =>  proc . pid  ===  pid ) ; 
38+ } 
39+ 
1340/** 
1441 * Run a test fixture with the same reporter in both parallel and serial modes, 
1542 * returning both outputs for comparison 
@@ -55,7 +82,7 @@ async function assertReporterOutputEquality(reporter) {
5582async  function  waitForChildPids ( pid )  { 
5683  let  childPids  =  [ ] ; 
5784  while  ( ! childPids . length )  { 
58-     childPids  =  await  pidtree ( pid ) ; 
85+     childPids  =  await  getChildPids ( pid ) ; 
5986    await  new  Promise ( resolve  =>  setTimeout ( resolve ,  100 ) ) ; 
6087  } 
6188  return  childPids ; 
@@ -475,27 +502,12 @@ describe('--parallel', function () {
475502    } ) ; 
476503  } ) ; 
477504
505+   // - `waitForChildPids` polls for created children 
506+   // - `await promise` waits for `invokeMochaAsync` to complete, which should 
507+   //   kill all children 
508+   // - `checkProcessExists` validates that each child was killed 
509+   // - if any weren't killed, the test fails 
478510  describe ( 'pool shutdown' ,  function  ( )  { 
479-     // these are unusual and deserve some explanation. we start our mocha 
480-     // subprocess, and in parallel mode, that subprocess spawns more 
481-     // subprocesses. `invokeMochaAsync` returns a tuple of a `mocha` 
482-     // `ChildProcess` object and a `Promise` (which will resolve/reject when the 
483-     // subprocess finishes its test run). we use the `pid` from the `mocha` 
484-     // `ChildProcess` to ask `pidtree` (https://npm.im/pidtree) for the 
485-     // children, which are the worker processes. the `mocha` subprocess does 
486-     // _not_ immediately spawn worker processes, so we need to _poll_ for child 
487-     // processes. when we have them, we record them.  once the `Promise` 
488-     // resolves, we then attempt to get pid information for our `mocha` process 
489-     // and _each_ worker process we retrieved earlier. if a process does not 
490-     // exist, `pidtree` will reject--this is what we _want_ to happen.  we check 
491-     // each explicitly in case the child processes are somehow orphaned. 
492-     // 
493-     // we return `null` for each in the case of the expected rejection--if the 
494-     // `Promise.all()` call results in an array containing anything _except_ a 
495-     // bunch of `null`s, then this test fails, because one of the processes is 
496-     // still running. this behavior is dependent on `workerpool@6.0.2`, which 
497-     // added a guarantee that terminating the pool will _wait_ until all child 
498-     // processes have actually exited. 
499511    describe ( 'during normal operation' ,  function  ( )  { 
500512      it ( 'should not leave orphaned processes around' ,  async  function  ( )  { 
501513        const  [ { pid} ,  promise ]  =  invokeMochaAsync ( [ 
@@ -506,17 +518,13 @@ describe('--parallel', function () {
506518        await  promise ; 
507519        return  expect ( 
508520          Promise . all ( 
509-             [ pid ,  ...childPids ] . map ( async  childPid  =>  { 
510-               let  pids  =  null ; 
511-               try  { 
512-                 pids  =  await  pidtree ( childPid ,  { root : true } ) ; 
513-               }  catch  ( ignored )  { } 
514-               return  pids ; 
515-             } ) 
521+             [ pid ,  ...childPids ] . map ( 
522+               async  childPid  =>  await  checkProcessExists ( childPid ) 
523+             ) 
516524          ) , 
517525          'when fulfilled' , 
518526          'to have items satisfying' , 
519-           null 
527+           false 
520528        ) ; 
521529      } ) ; 
522530    } ) ; 
@@ -532,17 +540,13 @@ describe('--parallel', function () {
532540        await  promise ; 
533541        return  expect ( 
534542          Promise . all ( 
535-             [ pid ,  ...childPids ] . map ( async  childPid  =>  { 
536-               let  pids  =  null ; 
537-               try  { 
538-                 pids  =  await  pidtree ( childPid ,  { root : true } ) ; 
539-               }  catch  ( ignored )  { } 
540-               return  pids ; 
541-             } ) 
543+             [ pid ,  ...childPids ] . map ( 
544+               async  childPid  =>  await  checkProcessExists ( childPid ) 
545+             ) 
542546          ) , 
543547          'when fulfilled' , 
544548          'to have items satisfying' , 
545-           null 
549+           false 
546550        ) ; 
547551      } ) ; 
548552    } ) ; 
0 commit comments