Skip to content

Commit

Permalink
test_runner: emit test:watch-drained event
Browse files Browse the repository at this point in the history
  • Loading branch information
MoLow committed May 30, 2023
1 parent 3a1f912 commit 39bc086
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 12 deletions.
4 changes: 4 additions & 0 deletions doc/api/test.md
Original file line number Diff line number Diff line change
Expand Up @@ -1539,6 +1539,10 @@ This event is only emitted if `--test` flag is passed.
Emitted when a running test writes to `stdout`.
This event is only emitted if `--test` flag is passed.

### Event: `'test:watch-drained'`

Emitted when no more tests are queued for execution in watch mode.

## Class: `TestContext`

<!-- YAML
Expand Down
30 changes: 18 additions & 12 deletions lib/internal/test_runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,6 @@ class FileTest extends Test {
}
}

const runningProcesses = new SafeMap();
const runningSubtests = new SafeMap();

function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
const subtest = root.createSubtest(FileTest, path, async (t) => {
const args = getRunArgs({ path, inspectPort, testNamePatterns });
Expand All @@ -352,11 +349,11 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
}

const child = spawn(process.execPath, args, { signal: t.signal, encoding: 'utf8', env, stdio });
runningProcesses.set(path, child);
filesWatcher?.runningProcesses.set(path, child);
filesWatcher?.watcher.watchChildProcessModules(child, path);

let err;

filesWatcher?.watchChildProcessModules(child, path);

child.on('error', (error) => {
err = error;
Expand Down Expand Up @@ -388,8 +385,12 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
finished(child.stdout, { signal: t.signal }),
]);

runningProcesses.delete(path);
runningSubtests.delete(path);
filesWatcher?.runningProcesses.delete(path);
filesWatcher?.runningSubtests.delete(path);
if (filesWatcher?.runningSubtests.size === 0) {
root.reporter[kEmitMessage]('test:watch-drained');
}

if (code !== 0 || signal !== null) {
if (!err) {
const failureType = subtest.failedSubtests ? kSubtestsFailed : kTestCodeFailure;
Expand All @@ -410,9 +411,13 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
}

function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) {
const filesWatcher = new FilesWatcher({ throttle: 500, mode: 'filter' });
filesWatcher.on('changed', ({ owners }) => {
filesWatcher.unfilterFilesOwnedBy(owners);
const runningProcesses = new SafeMap();
const runningSubtests = new SafeMap();
const watcher = new FilesWatcher({ throttle: 500, mode: 'filter' });
const filesWatcher = { __proto__: null, watcher, runningProcesses, runningSubtests };

watcher.on('changed', ({ owners }) => {
watcher.unfilterFilesOwnedBy(owners);
PromisePrototypeThen(SafePromiseAllReturnVoid(testFiles, async (file) => {
if (!owners.has(file)) {
return;
Expand All @@ -433,9 +438,10 @@ function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) {
}));
});
signal?.addEventListener('abort', () => {
filesWatcher.clear();
watcher.clear();
root.postRun();
}, { __proto__: null, once: true });

return filesWatcher;
}

Expand Down Expand Up @@ -485,7 +491,7 @@ function run(options) {
root.harness.bootstrapComplete = true;
return SafePromiseAllSettledReturnVoid(testFiles, (path) => {
const subtest = runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns);
runningSubtests.set(path, subtest);
filesWatcher?.runningSubtests.set(path, subtest);
return subtest;
});
};
Expand Down
11 changes: 11 additions & 0 deletions test/parallel/test-runner-run.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,15 @@ describe('require(\'node:test\').run', { concurrency: true }, () => {
.toArray();
assert.deepStrictEqual(result, ['this should pass']);
});

it('should emit "test:watch-drained" event on watch mode', async () => {
const controller = new AbortController();
await run({ files: [join(testFixtures, 'test/random.cjs')], watch: true, signal: controller.signal })
.on('data', function({ type }) {
console.log(type);
if (type === 'test:watch-drained') {
controller.abort();
}
});
});
});

0 comments on commit 39bc086

Please sign in to comment.