Skip to content

Commit 033d0bb

Browse files
committed
test_runner: emit test:watch:drained event
PR-URL: #48259 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
1 parent 618a9e1 commit 033d0bb

3 files changed

Lines changed: 37 additions & 12 deletions

File tree

‎doc/api/test.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,10 @@ This event is only emitted if `--test` flag is passed.
14731473
Emitted when a running test writes to `stdout`.
14741474
This event is only emitted if `--test` flag is passed.
14751475

1476+
### Event: `'test:watch:drained'`
1477+
1478+
Emitted when no more tests are queued for execution in watch mode.
1479+
14761480
## Class: `TestContext`
14771481

14781482
<!-- YAML

‎lib/internal/test_runner/runner.js‎

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -341,25 +341,25 @@ class FileTest extends Test {
341341
}
342342
}
343343

344-
construnningProcesses=newSafeMap();
345-
construnningSubtests=newSafeMap();
346-
347344
functionrunTestFile(path,root,inspectPort,filesWatcher,testNamePatterns){
345+
constwatchMode=filesWatcher!=null;
348346
constsubtest=root.createSubtest(FileTest,path,async(t)=>{
349347
constargs=getRunArgs({ path, inspectPort, testNamePatterns });
350348
conststdio=['pipe','pipe','pipe'];
351349
constenv={ ...process.env,NODE_TEST_CONTEXT: 'child-v8'};
352-
if(filesWatcher){
350+
if(watchMode){
353351
stdio.push('ipc');
354352
env.WATCH_REPORT_DEPENDENCIES='1';
355353
}
356354

357355
constchild=spawn(process.execPath,args,{signal: t.signal,encoding: 'utf8', env, stdio });
358-
runningProcesses.set(path,child);
356+
if(watchMode){
357+
filesWatcher.runningProcesses.set(path,child);
358+
filesWatcher.watcher.watchChildProcessModules(child,path);
359+
}
359360

360361
leterr;
361362

362-
filesWatcher?.watchChildProcessModules(child,path);
363363

364364
child.on('error',(error)=>{
365365
err=error;
@@ -391,8 +391,14 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
391391
finished(child.stdout,{signal: t.signal}),
392392
]);
393393

394-
runningProcesses.delete(path);
395-
runningSubtests.delete(path);
394+
if(watchMode){
395+
filesWatcher.runningProcesses.delete(path);
396+
filesWatcher.runningSubtests.delete(path);
397+
if(filesWatcher.runningSubtests.size===0){
398+
root.reporter[kEmitMessage]('test:watch:drained');
399+
}
400+
}
401+
396402
if(code!==0||signal!==null){
397403
if(!err){
398404
constfailureType=subtest.failedSubtests ? kSubtestsFailed : kTestCodeFailure;
@@ -413,9 +419,13 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
413419
}
414420

415421
functionwatchFiles(testFiles,root,inspectPort,signal,testNamePatterns){
416-
constfilesWatcher=newFilesWatcher({throttle: 500,mode: 'filter', signal });
417-
filesWatcher.on('changed',({ owners })=>{
418-
filesWatcher.unfilterFilesOwnedBy(owners);
422+
construnningProcesses=newSafeMap();
423+
construnningSubtests=newSafeMap();
424+
constwatcher=newFilesWatcher({throttle: 500,mode: 'filter', signal });
425+
constfilesWatcher={__proto__: null, watcher, runningProcesses, runningSubtests };
426+
427+
watcher.on('changed',({ owners })=>{
428+
watcher.unfilterFilesOwnedBy(owners);
419429
PromisePrototypeThen(SafePromiseAllReturnVoid(testFiles,async(file)=>{
420430
if(!owners.has(file)){
421431
return;
@@ -436,6 +446,7 @@ function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) {
436446
}));
437447
});
438448
signal?.addEventListener('abort',()=>root.postRun(),{__proto__: null,once: true});
449+
439450
returnfilesWatcher;
440451
}
441452

@@ -485,7 +496,7 @@ function run(options) {
485496
root.harness.bootstrapComplete=true;
486497
returnSafePromiseAllSettledReturnVoid(testFiles,(path)=>{
487498
constsubtest=runTestFile(path,root,inspectPort,filesWatcher,testNamePatterns);
488-
runningSubtests.set(path,subtest);
499+
filesWatcher?.runningSubtests.set(path,subtest);
489500
returnsubtest;
490501
});
491502
};

‎test/parallel/test-runner-run.mjs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,14 @@ describe('require(\'node:test\').run', { concurrency: true }, () => {
132132
.toArray();
133133
assert.deepStrictEqual(result,['this should pass']);
134134
});
135+
136+
it('should emit "test:watch:drained" event on watch mode',async()=>{
137+
constcontroller=newAbortController();
138+
awaitrun({files: [join(testFixtures,'test/random.cjs')],watch: true,signal: controller.signal})
139+
.on('data',function({ type }){
140+
if(type==='test:watch:drained'){
141+
controller.abort();
142+
}
143+
});
144+
});
135145
});

0 commit comments

Comments
 (0)