Skip to content

Commit

Permalink
test_runner: stop watch mode when abortSignal aborted
Browse files Browse the repository at this point in the history
PR-URL: #48259
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
  • Loading branch information
MoLow committed Jul 6, 2023
1 parent 27f195f commit 618a9e1
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 5 deletions.
7 changes: 4 additions & 3 deletions lib/internal/test_runner/runner.js
Expand Up @@ -412,8 +412,8 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
return subtest.start();
}

function watchFiles(testFiles, root, inspectPort, testNamePatterns) {
const filesWatcher = new FilesWatcher({ throttle: 500, mode: 'filter' });
function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) {
const filesWatcher = new FilesWatcher({ throttle: 500, mode: 'filter', signal });
filesWatcher.on('changed', ({ owners }) => {
filesWatcher.unfilterFilesOwnedBy(owners);
PromisePrototypeThen(SafePromiseAllReturnVoid(testFiles, async (file) => {
Expand All @@ -435,6 +435,7 @@ function watchFiles(testFiles, root, inspectPort, testNamePatterns) {
triggerUncaughtException(error, true /* fromPromise */);
}));
});
signal?.addEventListener('abort', () => root.postRun(), { __proto__: null, once: true });
return filesWatcher;
}

Expand Down Expand Up @@ -477,7 +478,7 @@ function run(options) {
let postRun = () => root.postRun();
let filesWatcher;
if (watch) {
filesWatcher = watchFiles(testFiles, root, inspectPort, testNamePatterns);
filesWatcher = watchFiles(testFiles, root, inspectPort, signal, testNamePatterns);
postRun = undefined;
}
const runFiles = () => {
Expand Down
8 changes: 6 additions & 2 deletions lib/internal/watch_mode/files_watcher.js
Expand Up @@ -30,14 +30,18 @@ class FilesWatcher extends EventEmitter {
#ownerDependencies = new SafeMap();
#throttle;
#mode;
#signal;

constructor({ throttle = 500, mode = 'filter' } = kEmptyObject) {
constructor({ throttle = 500, mode = 'filter', signal } = kEmptyObject) {
super();

validateNumber(throttle, 'options.throttle', 0, TIMEOUT_MAX);
validateOneOf(mode, 'options.mode', ['filter', 'all']);
this.#throttle = throttle;
this.#mode = mode;
this.#signal = signal;

signal?.addEventListener('abort', () => this.clear(), { __proto__: null, once: true });
}

#isPathWatched(path) {
Expand Down Expand Up @@ -89,7 +93,7 @@ class FilesWatcher extends EventEmitter {
if (this.#isPathWatched(path)) {
return;
}
const watcher = watch(path, { recursive });
const watcher = watch(path, { recursive, signal: this.#signal });
watcher.on('change', (eventType, fileName) => this
.#onChange(recursive ? resolve(path, fileName) : path));
this.#watchers.set(path, { handle: watcher, recursive });
Expand Down
15 changes: 15 additions & 0 deletions test/parallel/test-runner-run.mjs
Expand Up @@ -117,4 +117,19 @@ describe('require(\'node:test\').run', { concurrency: true }, () => {
assert.strictEqual(result[2], 'ok 1 - this should be skipped # SKIP test name does not match pattern\n');
assert.strictEqual(result[5], 'ok 2 - this should be executed\n');
});

it('should stop watch mode when abortSignal aborts', async () => {
const controller = new AbortController();
const result = await run({ files: [join(testFixtures, 'test/random.cjs')], watch: true, signal: controller.signal })
.compose(async function* (source) {
for await (const chunk of source) {
if (chunk.type === 'test:pass') {
controller.abort();
yield chunk.data.name;
}
}
})
.toArray();
assert.deepStrictEqual(result, ['this should pass']);
});
});

0 comments on commit 618a9e1

Please sign in to comment.