Skip to content

Commit 7871ade

Browse files
committed
test_runner: report changed file on watch restart
The `test:watch:restarted` reporter event now includes a `file` property with the path of the file whose change triggered the restart. The watcher already surfaces this path through the `changed` event since it started printing the changed file name, so this just forwards it to consumers of the reporter stream. Fixes: #63786 Signed-off-by: Paul Bouchon <mail@bitpshr.net>
1 parent 892976d commit 7871ade

3 files changed

Lines changed: 61 additions & 2 deletions

File tree

‎doc/api/test.md‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3933,6 +3933,18 @@ Emitted when no more tests are queued for execution in watch mode.
39333933

39343934
### Event: `'test:watch:restarted'`
39353935

3936+
<!-- YAML
3937+
changes:
3938+
- version: REPLACEME
3939+
pr-url: https://github.com/nodejs/node/pull/64457
3940+
description: Added the `file` property to the event data.
3941+
-->
3942+
3943+
* `data` {Object}
3944+
* `file` {string|undefined} The path of the file whose change triggered the
3945+
restart. This value is `undefined` when the triggering file cannot be
3946+
determined.
3947+
39363948
Emitted when one or more tests are restarted due to a file change in watch mode.
39373949

39383950
## `getTestContext()`

‎lib/internal/test_runner/runner.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ function watchFiles(testFiles, opts) {
631631
}
632632

633633
// Watch for changes in current filtered files
634-
const onChanged = ({ owners, eventType }) => {
634+
const onChanged = ({ owners, eventType, trigger }) => {
635635
if (!opts.hasFiles && (eventType === 'rename' || eventType === 'change')) {
636636
const updatedTestFiles = createTestFileList(opts.globPatterns, opts.cwd);
637637
const newFileName = ArrayPrototypeFind(updatedTestFiles, (x) => !ArrayPrototypeIncludes(testFiles, x));
@@ -653,7 +653,7 @@ function watchFiles(testFiles, opts) {
653653
// Reset the root start time to recalculate the duration
654654
// of the run
655655
opts.root.clearExecutionTime();
656-
opts.root.reporter[kEmitMessage]('test:watch:restarted');
656+
opts.root.reporter[kEmitMessage]('test:watch:restarted', { __proto__: null, file: trigger });
657657

658658
// Restart test files
659659
if (opts.isolation === 'none') {
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Test run({ watch: true }) reports the triggering file path in the
2+
// test:watch:restarted event data.
3+
import * as common from '../common/index.mjs';
4+
import { run } from 'node:test';
5+
import assert from 'node:assert';
6+
import { writeFileSync } from 'node:fs';
7+
import { join } from 'node:path';
8+
import { once } from 'node:events';
9+
import tmpdir from '../common/tmpdir.js';
10+
import { refreshForTestRunnerWatch, skipIfNoWatch, fixtureContent } from '../common/watch.js';
11+
12+
skipIfNoWatch();
13+
refreshForTestRunnerWatch();
14+
15+
const changedFile = join(tmpdir.path, 'test.js');
16+
17+
let alreadyDrained = false;
18+
const restartedFiles = [];
19+
const onRestarted = common.mustCall((file) => {
20+
restartedFiles.push(file);
21+
}, 1);
22+
23+
const controller = new AbortController();
24+
const stream = run({
25+
cwd: tmpdir.path,
26+
watch: true,
27+
signal: controller.signal,
28+
}).on('data', function({ type, data }) {
29+
if (type === 'test:watch:restarted') {
30+
onRestarted(data.file);
31+
}
32+
if (type === 'test:watch:drained') {
33+
if (alreadyDrained) {
34+
controller.abort();
35+
}
36+
alreadyDrained = true;
37+
}
38+
});
39+
40+
await once(stream, 'test:watch:drained');
41+
42+
writeFileSync(changedFile, fixtureContent['test.js']);
43+
44+
// eslint-disable-next-line no-unused-vars
45+
for await (const _ of stream);
46+
47+
assert.deepStrictEqual(restartedFiles, [changedFile]);

0 commit comments

Comments
 (0)