Skip to content

Commit 4d64727

Browse files
JacopoPatroclotargos
authored andcommitted
test_runner: emit event when file changes in watch mode
PR-URL: #57903 Reviewed-By: Pietro Marchini <pietro.marchini94@gmail.com> Reviewed-By: Jake Yuesong Li <jake.yuesong@gmail.com>
1 parent d99d657 commit 4d64727

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

doc/api/test.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,9 @@ const customReporter = new Transform({
11211121
case 'test:watch:drained':
11221122
callback(null, 'test watch queue drained');
11231123
break;
1124+
case 'test:watch:restarted':
1125+
callback(null, 'test watch restarted due to file change');
1126+
break;
11241127
case 'test:start':
11251128
callback(null, `test ${event.data.name} started`);
11261129
break;
@@ -1166,6 +1169,9 @@ const customReporter = new Transform({
11661169
case 'test:watch:drained':
11671170
callback(null, 'test watch queue drained');
11681171
break;
1172+
case 'test:watch:restarted':
1173+
callback(null, 'test watch restarted due to file change');
1174+
break;
11691175
case 'test:start':
11701176
callback(null, `test ${event.data.name} started`);
11711177
break;
@@ -1210,6 +1216,9 @@ export default async function * customReporter(source) {
12101216
case 'test:watch:drained':
12111217
yield 'test watch queue drained\n';
12121218
break;
1219+
case 'test:watch:restarted':
1220+
yield 'test watch restarted due to file change\n';
1221+
break;
12131222
case 'test:start':
12141223
yield `test ${event.data.name} started\n`;
12151224
break;
@@ -1250,6 +1259,9 @@ module.exports = async function * customReporter(source) {
12501259
case 'test:watch:drained':
12511260
yield 'test watch queue drained\n';
12521261
break;
1262+
case 'test:watch:restarted':
1263+
yield 'test watch restarted due to file change\n';
1264+
break;
12531265
case 'test:start':
12541266
yield `test ${event.data.name} started\n`;
12551267
break;
@@ -3175,6 +3187,10 @@ generated for each test file in addition to a final cumulative summary.
31753187

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

3190+
### Event: `'test:watch:restarted'`
3191+
3192+
Emitted when one or more tests are restarted due to a file change in watch mode.
3193+
31783194
## Class: `TestContext`
31793195

31803196
<!-- YAML

lib/internal/test_runner/runner.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ function watchFiles(testFiles, opts) {
481481
// Reset the topLevel counter
482482
opts.root.harness.counters.topLevel = 0;
483483
}
484+
484485
await runningSubtests.get(file);
485486
runningSubtests.set(file, runTestFile(file, filesWatcher, opts));
486487
}
@@ -508,6 +509,8 @@ function watchFiles(testFiles, opts) {
508509
// Reset the root start time to recalculate the duration
509510
// of the run
510511
opts.root.clearExecutionTime();
512+
opts.root.reporter[kEmitMessage]('test:watch:restarted');
513+
511514
// Restart test files
512515
if (opts.isolation === 'none') {
513516
PromisePrototypeThen(restartTestFile(kIsolatedProcessName), undefined, (error) => {

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,56 @@ describe('test runner watch mode', () => {
257257
assert.notDeepStrictEqual(durations[0][1], durations[1][1]);
258258
});
259259

260+
it('should emit test:watch:restarted when file is updated', async () => {
261+
let alreadyDrained = false;
262+
const events = [];
263+
const testWatchRestarted = common.mustCall(1);
264+
265+
const controller = new AbortController();
266+
const stream = run({
267+
cwd: tmpdir.path,
268+
watch: true,
269+
signal: controller.signal,
270+
}).on('data', function({ type }) {
271+
events.push(type);
272+
if (type === 'test:watch:restarted') {
273+
testWatchRestarted();
274+
}
275+
if (type === 'test:watch:drained') {
276+
if (alreadyDrained) {
277+
controller.abort();
278+
}
279+
alreadyDrained = true;
280+
}
281+
});
282+
283+
await once(stream, 'test:watch:drained');
284+
285+
writeFileSync(join(tmpdir.path, 'test.js'), fixtureContent['test.js']);
286+
287+
// eslint-disable-next-line no-unused-vars
288+
for await (const _ of stream);
289+
290+
assert.partialDeepStrictEqual(events, [
291+
'test:watch:drained',
292+
'test:watch:restarted',
293+
'test:watch:drained',
294+
]);
295+
});
296+
297+
it('should not emit test:watch:restarted since watch mode is disabled', async () => {
298+
const stream = run({
299+
cwd: tmpdir.path,
300+
watch: false,
301+
});
302+
303+
stream.on('test:watch:restarted', common.mustNotCall());
304+
writeFileSync(join(tmpdir.path, 'test.js'), fixtureContent['test.js']);
305+
306+
// eslint-disable-next-line no-unused-vars
307+
for await (const _ of stream);
308+
});
309+
260310
describe('test runner watch mode with different cwd', () => {
261311
it(
262312
'should execute run using a different cwd for the runner than the process cwd',

0 commit comments

Comments
 (0)