Skip to content

Commit 521d43e

Browse files
test_runner: emit test:watch:restarted event when file changes in watch mode
1 parent 6cdcaa9 commit 521d43e

File tree

3 files changed

+69
-0
lines changed

3 files changed

+69
-0
lines changed

doc/api/test.md

+16
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,9 @@ const customReporter = new Transform({
11141114
case 'test:watch:drained':
11151115
callback(null, 'test watch queue drained');
11161116
break;
1117+
case 'test:watch:restarted':
1118+
callback(null, 'test watch restarted due to file change');
1119+
break;
11171120
case 'test:start':
11181121
callback(null, `test ${event.data.name} started`);
11191122
break;
@@ -1159,6 +1162,9 @@ const customReporter = new Transform({
11591162
case 'test:watch:drained':
11601163
callback(null, 'test watch queue drained');
11611164
break;
1165+
case 'test:watch:restarted':
1166+
callback(null, 'test watch restarted due to file change');
1167+
break;
11621168
case 'test:start':
11631169
callback(null, `test ${event.data.name} started`);
11641170
break;
@@ -1203,6 +1209,9 @@ export default async function * customReporter(source) {
12031209
case 'test:watch:drained':
12041210
yield 'test watch queue drained\n';
12051211
break;
1212+
case 'test:watch:restarted':
1213+
yield 'test watch restarted due to file change\n';
1214+
break;
12061215
case 'test:start':
12071216
yield `test ${event.data.name} started\n`;
12081217
break;
@@ -1243,6 +1252,9 @@ module.exports = async function * customReporter(source) {
12431252
case 'test:watch:drained':
12441253
yield 'test watch queue drained\n';
12451254
break;
1255+
case 'test:watch:restarted':
1256+
yield 'test watch restarted due to file change\n';
1257+
break;
12461258
case 'test:start':
12471259
yield `test ${event.data.name} started\n`;
12481260
break;
@@ -3158,6 +3170,10 @@ generated for each test file in addition to a final cumulative summary.
31583170

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

3173+
### Event: `'test:watch:restarted'`
3174+
3175+
Emitted when one or more tests are restarted due to a file change in watch mode.
3176+
31613177
## Class: `TestContext`
31623178

31633179
<!-- YAML

lib/internal/test_runner/runner.js

+3
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,7 @@ function watchFiles(testFiles, opts) {
480480
// Reset the topLevel counter
481481
opts.root.harness.counters.topLevel = 0;
482482
}
483+
483484
await runningSubtests.get(file);
484485
runningSubtests.set(file, runTestFile(file, filesWatcher, opts));
485486
}
@@ -507,6 +508,8 @@ function watchFiles(testFiles, opts) {
507508
// Reset the root start time to recalculate the duration
508509
// of the run
509510
opts.root.clearExecutionTime();
511+
opts.root.reporter[kEmitMessage]('test:watch:restarted');
512+
510513
// Restart test files
511514
if (opts.isolation === 'none') {
512515
PromisePrototypeThen(restartTestFile(kIsolatedProcessName), undefined, (error) => {

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

+50
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)