test: split test-runner-watch-mode

The test has been flaky for years and new platforms keep popping
up. As it squeezes too many independent test cases into one file,
split them into individual files to avoid masking regressions
and help only mark the real flaky ones as flaky. This might also
help with the flakiness itself by avoiding updating a shared tmpdir
being watched by differet tests and avoiding running all these
time-consuming tests in one file, which can cause a timeout
on slow machines.

PR-URL: https://github.com/nodejs/node/pull/60391
Refs: https://github.com/nodejs/node/issues/49605
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: Jake Yuesong Li <jake.yuesong@gmail.com>
Reviewed-By: Chemi Atlow <chemi@atlow.co.il>
This commit is contained in:
Joyee Cheung 2025-10-24 12:59:47 +02:00 committed by Antoine du Hamel
parent e78e0cf6e7
commit bbca57584b
No known key found for this signature in database
GPG Key ID: 20B1A390B168D356
18 changed files with 117 additions and 49 deletions

View File

@ -60,7 +60,7 @@ async function testRunnerWatch({
['--watch', '--test', '--test-reporter=spec',
isolation ? `--test-isolation=${isolation}` : '',
file ? fixturePaths[file] : undefined].filter(Boolean),
{ encoding: 'utf8', stdio: ['inherit', 'pipe', 'inherit'], cwd: tmpdir.path });
{ encoding: 'utf8', stdio: 'pipe', cwd: tmpdir.path });
let stdout = '';
let currentRun = '';
const runs = [];

View File

@ -50,10 +50,6 @@ test-runner-run-watch: PASS, FLAKY
# https://github.com/nodejs/node/issues/58353
test-http2-debug: PASS, FLAKY
[$system==linux || $system==win32]
# https://github.com/nodejs/node/issues/49605
test-runner-watch-mode: PASS,FLAKY
[$system==macos]
# https://github.com/nodejs/node/issues/42741
test-http-server-headers-timeout-keepalive: PASS,FLAKY

View File

@ -1,44 +0,0 @@
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
import { describe, it, beforeEach } from 'node:test';
skipIfNoWatch();
describe('test runner watch mode', () => {
beforeEach(refreshForTestRunnerWatch);
for (const isolation of ['none', 'process']) {
describe(`isolation: ${isolation}`, () => {
it('should run tests repeatedly', async () => {
await testRunnerWatch({ file: 'test.js', fileToUpdate: 'test.js', isolation });
});
it('should run tests with dependency repeatedly', async () => {
await testRunnerWatch({ file: 'test.js', fileToUpdate: 'dependency.js', isolation });
});
it('should run tests with ESM dependency', async () => {
await testRunnerWatch({ file: 'test.js', fileToUpdate: 'dependency.mjs', isolation });
});
it('should support running tests without a file', async () => {
await testRunnerWatch({ fileToUpdate: 'test.js', isolation });
});
it('should support a watched test file rename', async () => {
await testRunnerWatch({ fileToUpdate: 'test.js', action: 'rename', isolation });
});
it('should not throw when delete a watched test file', async () => {
await testRunnerWatch({ fileToUpdate: 'test.js', action: 'delete', isolation });
});
it('should run new tests when a new file is created in the watched directory', {
todo: isolation === 'none' ?
'This test is failing when isolation is set to none and must be fixed' :
undefined,
}, async () => {
await testRunnerWatch({ action: 'create', fileToCreate: 'new-test-file.test.js', isolation });
});
});
}
});

View File

@ -5,3 +5,7 @@ prefix test-runner
# sample-test : PASS,FLAKY
[true] # This section applies to all platforms
# https://github.com/nodejs/node/pull/54888#issuecomment-2351128116
# TODO(pmarchini): This test is failing when isolation is set to none and must be fixed.
test-watch-create-isolation-none: SKIP

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=none runs tests when a new file is created in the watched directory
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ action: 'create', fileToCreate: 'new-test-file.test.js', isolation: 'none' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=process runs tests when a new file is created in the watched directory
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ action: 'create', fileToCreate: 'new-test-file.test.js', isolation: 'process' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=none does not throw when deleting a watched test file
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ fileToUpdate: 'test.js', action: 'delete', isolation: 'none' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=process does not throw when deleting a watched test file
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ fileToUpdate: 'test.js', action: 'delete', isolation: 'process' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=none runs tests with dependency repeatedly
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ file: 'test.js', fileToUpdate: 'dependency.js', isolation: 'none' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=process runs tests with dependency repeatedly
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ file: 'test.js', fileToUpdate: 'dependency.js', isolation: 'process' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=none runs tests with ESM dependency
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ file: 'test.js', fileToUpdate: 'dependency.mjs', isolation: 'none' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=process runs tests with ESM dependency
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ file: 'test.js', fileToUpdate: 'dependency.mjs', isolation: 'process' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=none runs tests without a file argument
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ fileToUpdate: 'test.js', isolation: 'none' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=process runs tests without a file argument
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ fileToUpdate: 'test.js', isolation: 'process' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=none handles a watched test file rename
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ fileToUpdate: 'test.js', action: 'rename', isolation: 'none' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=process handles a watched test file rename
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ fileToUpdate: 'test.js', action: 'rename', isolation: 'process' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=none runs tests repeatedly
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ file: 'test.js', fileToUpdate: 'test.js', isolation: 'none' });

View File

@ -0,0 +1,8 @@
// Test --test --watch --test-isolation=process runs tests repeatedly
import '../common/index.mjs';
import { skipIfNoWatch, refreshForTestRunnerWatch, testRunnerWatch } from '../common/watch.js';
skipIfNoWatch();
refreshForTestRunnerWatch();
await testRunnerWatch({ file: 'test.js', fileToUpdate: 'test.js', isolation: 'process' });