Skip to content

Commit c9f8e8c

Browse files
MoLowtargos
authored andcommitted
test_runner: stop watch mode when abortSignal aborted
PR-URL: #48259 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Benjamin Gruenbaum <[email protected]>
1 parent d681e5f commit c9f8e8c

File tree

3 files changed

+25
-5
lines changed

3 files changed

+25
-5
lines changed

lib/internal/test_runner/runner.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,8 @@ function runTestFile(path, root, inspectPort, filesWatcher, testNamePatterns) {
409409
return subtest.start();
410410
}
411411

412-
function watchFiles(testFiles, root, inspectPort, testNamePatterns) {
413-
const filesWatcher = new FilesWatcher({ throttle: 500, mode: 'filter' });
412+
function watchFiles(testFiles, root, inspectPort, signal, testNamePatterns) {
413+
const filesWatcher = new FilesWatcher({ throttle: 500, mode: 'filter', signal });
414414
filesWatcher.on('changed', ({ owners }) => {
415415
filesWatcher.unfilterFilesOwnedBy(owners);
416416
PromisePrototypeThen(SafePromiseAllReturnVoid(testFiles, async (file) => {
@@ -432,6 +432,7 @@ function watchFiles(testFiles, root, inspectPort, testNamePatterns) {
432432
triggerUncaughtException(error, true /* fromPromise */);
433433
}));
434434
});
435+
signal?.addEventListener('abort', () => root.postRun(), { __proto__: null, once: true });
435436
return filesWatcher;
436437
}
437438

@@ -474,7 +475,7 @@ function run(options) {
474475
let postRun = () => root.postRun();
475476
let filesWatcher;
476477
if (watch) {
477-
filesWatcher = watchFiles(testFiles, root, inspectPort, testNamePatterns);
478+
filesWatcher = watchFiles(testFiles, root, inspectPort, signal, testNamePatterns);
478479
postRun = undefined;
479480
}
480481
const runFiles = () => {

lib/internal/watch_mode/files_watcher.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,18 @@ class FilesWatcher extends EventEmitter {
3030
#ownerDependencies = new SafeMap();
3131
#throttle;
3232
#mode;
33+
#signal;
3334

34-
constructor({ throttle = 500, mode = 'filter' } = kEmptyObject) {
35+
constructor({ throttle = 500, mode = 'filter', signal } = kEmptyObject) {
3536
super();
3637

3738
validateNumber(throttle, 'options.throttle', 0, TIMEOUT_MAX);
3839
validateOneOf(mode, 'options.mode', ['filter', 'all']);
3940
this.#throttle = throttle;
4041
this.#mode = mode;
42+
this.#signal = signal;
43+
44+
signal?.addEventListener('abort', () => this.clear(), { __proto__: null, once: true });
4145
}
4246

4347
#isPathWatched(path) {
@@ -89,7 +93,7 @@ class FilesWatcher extends EventEmitter {
8993
if (this.#isPathWatched(path)) {
9094
return;
9195
}
92-
const watcher = watch(path, { recursive });
96+
const watcher = watch(path, { recursive, signal: this.#signal });
9397
watcher.on('change', (eventType, fileName) => this
9498
.#onChange(recursive ? resolve(path, fileName) : path));
9599
this.#watchers.set(path, { handle: watcher, recursive });

test/parallel/test-runner-run.mjs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,19 @@ describe('require(\'node:test\').run', { concurrency: true }, () => {
117117
assert.strictEqual(result[2], 'ok 1 - this should be skipped # SKIP test name does not match pattern\n');
118118
assert.strictEqual(result[5], 'ok 2 - this should be executed\n');
119119
});
120+
121+
it('should stop watch mode when abortSignal aborts', async () => {
122+
const controller = new AbortController();
123+
const result = await run({ files: [join(testFixtures, 'test/random.cjs')], watch: true, signal: controller.signal })
124+
.compose(async function* (source) {
125+
for await (const chunk of source) {
126+
if (chunk.type === 'test:pass') {
127+
controller.abort();
128+
yield chunk.data.name;
129+
}
130+
}
131+
})
132+
.toArray();
133+
assert.deepStrictEqual(result, ['this should pass']);
134+
});
120135
});

0 commit comments

Comments
 (0)