From 70074ab9b91f19df48aa77110fc12fc13b408407 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Tue, 16 Jul 2024 15:12:29 +0200 Subject: [PATCH 01/24] test_runner: fix support watch with run(), add globPatterns option Signed-off-by: Matteo Collina --- doc/api/test.md | 11 ++ lib/internal/main/test_runner.js | 1 + lib/internal/test_runner/runner.js | 19 +-- test/fixtures/test-runner-watch.mjs | 24 +++ test/parallel/test-runner-run-watch.mjs | 187 +++++++++++++++++++++++ test/parallel/test-runner-run.mjs | 10 +- test/parallel/test-runner-watch-mode.mjs | 17 ++- 7 files changed, 253 insertions(+), 16 deletions(-) create mode 100644 test/fixtures/test-runner-watch.mjs create mode 100644 test/parallel/test-runner-run-watch.mjs diff --git a/doc/api/test.md b/doc/api/test.md index e0d4bee17a7483..53669e4852e9fe 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -1239,6 +1239,14 @@ added: - v18.9.0 - v16.19.0 changes: + - version: REPLACEME + pr-url: REPLACEME + description: Added the `globPatterns` option. + - version: + - v22.0.0 + - v20.14.0 + pr-url: https://github.com/nodejs/node/pull/52038 + description: Added the `forceExit` option. - version: - v22.0.0 - v20.14.0 @@ -1265,6 +1273,9 @@ changes: * `forceExit`: {boolean} Configures the test runner to exit the process once all known tests have finished executing even if the event loop would otherwise remain active. **Default:** `false`. + * `globPatterns`: {Array} An array containing the list of glob patterns to + match test files. **Default:** matching files from + [test runner execution model][]. * `inspectPort` {number|Function} Sets inspector port of test child process. This can be a number, or a function that takes no arguments and returns a number. If a nullish value is provided, each process gets its own port, diff --git a/lib/internal/main/test_runner.js b/lib/internal/main/test_runner.js index 3f86ddb84bb64e..1774ad43f9cf10 100644 --- a/lib/internal/main/test_runner.js +++ b/lib/internal/main/test_runner.js @@ -42,6 +42,7 @@ const options = { setup: setupTestReporters, timeout: perFileTimeout, shard, + globPatterns: process.argv.slice(1), }; debug('test runner configuration:', options); run(options).on('test:fail', (data) => { diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index 6fd1cb72f3b508..fc35e42cf3b343 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -1,4 +1,3 @@ -'use strict'; const { ArrayIsArray, ArrayPrototypeEvery, @@ -10,7 +9,6 @@ const { ArrayPrototypeMap, ArrayPrototypePush, ArrayPrototypeShift, - ArrayPrototypeSlice, ArrayPrototypeSome, ArrayPrototypeSort, ObjectAssign, @@ -88,10 +86,12 @@ const kCanceledTests = new SafeSet() let kResistStopPropagation; -function createTestFileList() { +function createTestFileList(patterns) { const cwd = process.cwd(); - const hasUserSuppliedPattern = process.argv.length > 1; - const patterns = hasUserSuppliedPattern ? ArrayPrototypeSlice(process.argv, 1) : [kDefaultPattern]; + const hasUserSuppliedPattern = patterns != null; + if (!patterns || patterns.length === 0) { + patterns = [kDefaultPattern]; + } const glob = new Glob(patterns, { __proto__: null, cwd, @@ -345,7 +345,6 @@ function runTestFile(path, filesWatcher, opts) { let err; - child.on('error', (error) => { err = error; }); @@ -419,8 +418,8 @@ function watchFiles(testFiles, opts) { opts.root.harness.watching = true; watcher.on('changed', ({ owners, eventType }) => { - if (eventType === 'rename') { - const updatedTestFiles = createTestFileList(); + if (!opts.hasFiles && eventType === 'rename') { + const updatedTestFiles = createTestFileList(opts.globPatterns); const newFileName = ArrayPrototypeFind(updatedTestFiles, (x) => !ArrayPrototypeIncludes(testFiles, x)); const previousFileName = ArrayPrototypeFind(testFiles, (x) => !ArrayPrototypeIncludes(updatedTestFiles, x)); @@ -559,7 +558,7 @@ function run(options = kEmptyObject) { root.postRun(); return root.reporter; } - let testFiles = files ?? createTestFileList(); + let testFiles = files ?? createTestFileList(options.globPatterns); if (shard) { testFiles = ArrayPrototypeFilter(testFiles, (_, index) => index % shard.total === shard.index - 1); @@ -574,6 +573,8 @@ function run(options = kEmptyObject) { inspectPort, testNamePatterns, testSkipPatterns, + hasFiles: files != null, + globPatterns: options.globPatterns, only, forceExit, }; diff --git a/test/fixtures/test-runner-watch.mjs b/test/fixtures/test-runner-watch.mjs new file mode 100644 index 00000000000000..2c2d427dadb472 --- /dev/null +++ b/test/fixtures/test-runner-watch.mjs @@ -0,0 +1,24 @@ +import { run } from 'node:test'; +import { tap } from 'node:test/reporters'; +import { parseArgs } from 'node:util'; + +const options = { + file: { + type: 'string', + }, +}; +const { + values, + positionals, +} = parseArgs({ args: process.argv.slice(2), options }); + +let files; + +if (values.file) { + files = [values.file]; +} + +run({ + files, + watch: true +}).compose(tap).pipe(process.stdout); \ No newline at end of file diff --git a/test/parallel/test-runner-run-watch.mjs b/test/parallel/test-runner-run-watch.mjs new file mode 100644 index 00000000000000..b60fc70c4a96a2 --- /dev/null +++ b/test/parallel/test-runner-run-watch.mjs @@ -0,0 +1,187 @@ +// Flags: --expose-internals +import * as common from '../common/index.mjs'; +import { describe, it, beforeEach } from 'node:test'; +import assert from 'node:assert'; +import { spawn } from 'node:child_process'; +import { writeFileSync, renameSync, unlinkSync, existsSync } from 'node:fs'; +import util from 'internal/util'; +import tmpdir from '../common/tmpdir.js'; +import { join } from 'node:path'; + +if (common.isIBMi) + common.skip('IBMi does not support `fs.watch()`'); + +// This test updates these files repeatedly, +// Reading them from disk is unreliable due to race conditions. +const fixtureContent = { + 'dependency.js': 'module.exports = {};', + 'dependency.mjs': 'export const a = 1;', + 'test.js': ` +const test = require('node:test'); +require('./dependency.js'); +import('./dependency.mjs'); +import('data:text/javascript,'); +test('test has ran');`, +}; + +let fixturePaths; + +function refresh() { + tmpdir.refresh(); + + fixturePaths = Object.keys(fixtureContent) + .reduce((acc, file) => ({ ...acc, [file]: tmpdir.resolve(file) }), {}); + Object.entries(fixtureContent) + .forEach(([file, content]) => writeFileSync(fixturePaths[file], content)); +} + +const runner = join(import.meta.dirname, '..', 'fixtures', 'test-runner-watch.mjs'); + +async function testWatch({ fileToUpdate, file, action = 'update', cwd = tmpdir.path }) { + const ran1 = util.createDeferredPromise(); + const ran2 = util.createDeferredPromise(); + const args = [runner]; + if (file) args.push('--file', file); + const child = spawn(process.execPath, + args, + { encoding: 'utf8', stdio: 'pipe', cwd }); + let stdout = ''; + let currentRun = ''; + const runs = []; + + child.stdout.on('data', (data) => { + stdout += data.toString(); + currentRun += data.toString(); + const testRuns = stdout.match(/# duration_ms\s\d+/g); + if (testRuns?.length >= 1) ran1.resolve(); + if (testRuns?.length >= 2) ran2.resolve(); + }); + + const testUpdate = async () => { + await ran1.promise; + const content = fixtureContent[fileToUpdate]; + const path = fixturePaths[fileToUpdate]; + const interval = setInterval(() => writeFileSync(path, content), common.platformTimeout(1000)); + await ran2.promise; + runs.push(currentRun); + clearInterval(interval); + child.kill(); + for (const run of runs) { + assert.doesNotMatch(run, /run\(\) is being called recursively/); + assert.match(run, /# tests 1/); + assert.match(run, /# pass 1/); + assert.match(run, /# fail 0/); + assert.match(run, /# cancelled 0/); + } + }; + + const testRename = async () => { + await ran1.promise; + const fileToRenamePath = tmpdir.resolve(fileToUpdate); + const newFileNamePath = tmpdir.resolve(`test-renamed-${fileToUpdate}`); + const interval = setInterval(() => renameSync(fileToRenamePath, newFileNamePath), common.platformTimeout(1000)); + await ran2.promise; + runs.push(currentRun); + clearInterval(interval); + child.kill(); + + for (const run of runs) { + assert.doesNotMatch(run, /run\(\) is being called recursively/); + assert.doesNotMatch(run, /MODULE_NOT_FOUND/); + assert.match(run, /# tests 1/); + assert.match(run, /# pass 1/); + assert.match(run, /# fail 0/); + assert.match(run, /# cancelled 0/); + } + }; + + const testRename2 = async () => { + await ran1.promise; + const fileToRenamePath = tmpdir.resolve(fileToUpdate); + const newFileNamePath = tmpdir.resolve(`test-renamed-${fileToUpdate}`); + const interval = setInterval(() => renameSync(fileToRenamePath, newFileNamePath), common.platformTimeout(1000)); + await ran2.promise; + runs.push(currentRun); + clearInterval(interval); + child.kill(); + + for (const run of runs) { + assert.doesNotMatch(run, /run\(\) is being called recursively/); + assert.match(run, /# tests 1/); + assert.match(run, /# pass 1/); + assert.match(run, /# fail 0/); + assert.match(run, /# cancelled 0/); + assert.match(run, /MODULE_NOT_FOUND/); + } + }; + + const testDelete = async () => { + await ran1.promise; + const fileToDeletePath = tmpdir.resolve(fileToUpdate); + const interval = setInterval(() => { + if (existsSync(fileToDeletePath)) { + unlinkSync(fileToDeletePath); + } else { + ran2.resolve(); + } + }, common.platformTimeout(1000)); + await ran2.promise; + runs.push(currentRun); + clearInterval(interval); + child.kill(); + + for (const run of runs) { + assert.doesNotMatch(run, /MODULE_NOT_FOUND/); + } + }; + + action === 'update' && await testUpdate(); + action === 'rename' && await testRename(); + action === 'rename2' && await testRename2(); + action === 'delete' && await testDelete(); +} + +describe('test runner watch mode', () => { + beforeEach(refresh); + it('should run tests repeatedly', async () => { + await testWatch({ file: 'test.js', fileToUpdate: 'test.js' }); + }); + + it('should run tests with dependency repeatedly', async () => { + await testWatch({ file: 'test.js', fileToUpdate: 'dependency.js' }); + }); + + it('should run tests with ESM dependency', async () => { + await testWatch({ file: 'test.js', fileToUpdate: 'dependency.mjs' }); + }); + + it('should support running tests without a file', async () => { + await testWatch({ fileToUpdate: 'test.js' }); + }); + + it('should support a watched test file rename', async () => { + await testWatch({ fileToUpdate: 'test.js', action: 'rename' }); + }); + + it('should not throw when delete a watched test file', async () => { + await testWatch({ fileToUpdate: 'test.js', action: 'delete' }); + }); + + it('should run tests with dependency repeatedly in a different cwd', async () => { + await testWatch({ + file: join(tmpdir.path, 'test.js'), + fileToUpdate: 'dependency.js', + cwd: import.meta.dirname, + action: 'rename2' + }); + }); + + it('should handle ranames in a different cwd', async () => { + await testWatch({ + file: join(tmpdir.path, 'test.js'), + fileToUpdate: 'test.js', + cwd: import.meta.dirname, + action: 'rename2' + }); + }); +}); diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index 54e882c4ecabe3..516e26983ad56d 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -4,9 +4,15 @@ import { join } from 'node:path'; import { describe, it, run } from 'node:test'; import { dot, spec, tap } from 'node:test/reporters'; import assert from 'node:assert'; +import tmpdir from '../common/tmpdir.js'; const testFixtures = fixtures.path('test-runner'); +// This is needed, because calling run() with no files will +// load files matching from cwd, which includes all content of test/ +tmpdir.refresh(); +process.chdir(tmpdir.path); + describe('require(\'node:test\').run', { concurrency: true }, () => { it('should run with no tests', async () => { const stream = run({ files: [] }); @@ -135,6 +141,7 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { }) .compose(tap) .toArray(); + assert.strictEqual(result[2], 'ok 1 - this should be executed\n'); assert.strictEqual(result[4], '1..1\n'); assert.strictEqual(result[5], '# tests 1\n'); @@ -391,6 +398,7 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { const executedTestFiles = []; stream.on('test:fail', common.mustNotCall()); stream.on('test:pass', (passedTest) => { + process._rawDebug(passedTest.file); executedTestFiles.push(passedTest.file); }); // eslint-disable-next-line no-unused-vars @@ -488,7 +496,7 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { }); }); - it('should run with no files', async () => { + it.only('should run with no files', async () => { const stream = run({ files: undefined }).compose(tap); diff --git a/test/parallel/test-runner-watch-mode.mjs b/test/parallel/test-runner-watch-mode.mjs index 4af48ea409ddbb..6407ee90c3fd91 100644 --- a/test/parallel/test-runner-watch-mode.mjs +++ b/test/parallel/test-runner-watch-mode.mjs @@ -1,6 +1,6 @@ // Flags: --expose-internals import * as common from '../common/index.mjs'; -import { describe, it } from 'node:test'; +import { describe, it, beforeEach } from 'node:test'; import assert from 'node:assert'; import { spawn } from 'node:child_process'; import { writeFileSync, renameSync, unlinkSync, existsSync } from 'node:fs'; @@ -11,7 +11,7 @@ import tmpdir from '../common/tmpdir.js'; if (common.isIBMi) common.skip('IBMi does not support `fs.watch()`'); -tmpdir.refresh(); +let fixturePaths; // This test updates these files repeatedly, // Reading them from disk is unreliable due to race conditions. @@ -25,10 +25,14 @@ import('./dependency.mjs'); import('data:text/javascript,'); test('test has ran');`, }; -const fixturePaths = Object.keys(fixtureContent) - .reduce((acc, file) => ({ ...acc, [file]: tmpdir.resolve(file) }), {}); -Object.entries(fixtureContent) - .forEach(([file, content]) => writeFileSync(fixturePaths[file], content)); + +function refresh() { + tmpdir.refresh(); + fixturePaths = Object.keys(fixtureContent) + .reduce((acc, file) => ({ ...acc, [file]: tmpdir.resolve(file) }), {}); + Object.entries(fixtureContent) + .forEach(([file, content]) => writeFileSync(fixturePaths[file], content)); +} async function testWatch({ fileToUpdate, file, action = 'update' }) { const ran1 = util.createDeferredPromise(); @@ -109,6 +113,7 @@ async function testWatch({ fileToUpdate, file, action = 'update' }) { } describe('test runner watch mode', () => { + beforeEach(refresh); it('should run tests repeatedly', async () => { await testWatch({ file: 'test.js', fileToUpdate: 'test.js' }); }); From 61675a01744fd933a8dcd26f93783a5f56296926 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Tue, 16 Jul 2024 15:26:19 +0200 Subject: [PATCH 02/24] fixup Signed-off-by: Matteo Collina --- doc/api/test.md | 2 +- lib/internal/test_runner/runner.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/api/test.md b/doc/api/test.md index 53669e4852e9fe..923da223b21a33 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -1240,7 +1240,7 @@ added: - v16.19.0 changes: - version: REPLACEME - pr-url: REPLACEME + pr-url: https://github.com/nodejs/node/pull/53866 description: Added the `globPatterns` option. - version: - v22.0.0 diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index fc35e42cf3b343..b340fc6f781153 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -1,3 +1,5 @@ +'use strict'; + const { ArrayIsArray, ArrayPrototypeEvery, From 5ed9505ff821c9b42f4e4107ebd45f3d83cf2b61 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Tue, 16 Jul 2024 17:19:53 +0200 Subject: [PATCH 03/24] fixup Signed-off-by: Matteo Collina --- tools/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/test.py b/tools/test.py index 9d7838d7c0110a..34d0d12b4f26e8 100755 --- a/tools/test.py +++ b/tools/test.py @@ -317,7 +317,7 @@ def HasRun(self, output): class ActionsAnnotationProgressIndicator(DotsProgressIndicator): def AboutToRun(self, case): case.additional_flags = case.additional_flags.copy() if hasattr(case, 'additional_flags') else [] - case.additional_flags.append('--test-reporter=./tools/github_reporter/index.js') + case.additional_flags.append('--test-reporter=' + root_path + '/tools/github_reporter/index.js') case.additional_flags.append('--test-reporter-destination=stdout') def GetAnnotationInfo(self, test, output): From 895896fc381b6b389f1c0a8a35ef6bbde25dd502 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 18 Jul 2024 14:51:33 +0200 Subject: [PATCH 04/24] fixup Signed-off-by: Matteo Collina --- lib/internal/test_runner/runner.js | 15 +++++++++++++-- test/parallel/test-runner-run.mjs | 15 ++++++++++++++- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index b340fc6f781153..425045cbb2b426 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -484,6 +484,7 @@ function run(options = kEmptyObject) { watch, setup, only, + globPatterns } = options; if (files != null) { @@ -504,6 +505,16 @@ function run(options = kEmptyObject) { if (only != null) { validateBoolean(only, 'options.only'); } + if (globPatterns != null) { + validateArray(globPatterns, 'options.globPatterns'); + } + + if (globPatterns?.length > 0 && files?.length > 0) { + throw new ERR_INVALID_ARG_VALUE( + 'options.globPatterns', globPatterns, 'is not supported when specifying \'options.files\'' + ); + } + if (shard != null) { validateObject(shard, 'options.shard'); // Avoid re-evaluating the shard object in case it's a getter @@ -560,7 +571,7 @@ function run(options = kEmptyObject) { root.postRun(); return root.reporter; } - let testFiles = files ?? createTestFileList(options.globPatterns); + let testFiles = files ?? createTestFileList(globPatterns); if (shard) { testFiles = ArrayPrototypeFilter(testFiles, (_, index) => index % shard.total === shard.index - 1); @@ -576,7 +587,7 @@ function run(options = kEmptyObject) { testNamePatterns, testSkipPatterns, hasFiles: files != null, - globPatterns: options.globPatterns, + globPatterns, only, forceExit, }; diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index 516e26983ad56d..578b16041660c4 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -475,6 +475,19 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { })); }); + it('should only allow array in options.globPatterns', async () => { + [Symbol(), {}, () => {}, 0, 1, 0n, 1n, '', '1', Promise.resolve([]), true, false] + .forEach((globPatterns) => assert.throws(() => run({ globPatterns}), { + code: 'ERR_INVALID_ARG_TYPE' + })); + }); + + it('should not allow files and globPatterns used together', () => { + assert.throws(() => run({ files: ['a.js'], globPatterns: ['*.js'] }), { + code: 'ERR_INVALID_ARG_VALUE' + }); + }); + it('should only allow object as options', () => { [Symbol(), [], () => {}, 0, 1, 0n, 1n, '', '1', true, false] .forEach((options) => assert.throws(() => run(options), { @@ -496,7 +509,7 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { }); }); - it.only('should run with no files', async () => { + it('should run with no files', async () => { const stream = run({ files: undefined }).compose(tap); From 37247a74390578d471627d79a680406848cfcee4 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 18 Jul 2024 14:52:55 +0200 Subject: [PATCH 05/24] Apply suggestions from code review Co-authored-by: Chemi Atlow --- test/parallel/test-runner-run-watch.mjs | 30 ++++++------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/test/parallel/test-runner-run-watch.mjs b/test/parallel/test-runner-run-watch.mjs index b60fc70c4a96a2..51f5f2d31fd6fb 100644 --- a/test/parallel/test-runner-run-watch.mjs +++ b/test/parallel/test-runner-run-watch.mjs @@ -87,31 +87,15 @@ async function testWatch({ fileToUpdate, file, action = 'update', cwd = tmpdir.p for (const run of runs) { assert.doesNotMatch(run, /run\(\) is being called recursively/); - assert.doesNotMatch(run, /MODULE_NOT_FOUND/); - assert.match(run, /# tests 1/); - assert.match(run, /# pass 1/); - assert.match(run, /# fail 0/); - assert.match(run, /# cancelled 0/); - } - }; - - const testRename2 = async () => { - await ran1.promise; - const fileToRenamePath = tmpdir.resolve(fileToUpdate); - const newFileNamePath = tmpdir.resolve(`test-renamed-${fileToUpdate}`); - const interval = setInterval(() => renameSync(fileToRenamePath, newFileNamePath), common.platformTimeout(1000)); - await ran2.promise; - runs.push(currentRun); - clearInterval(interval); - child.kill(); - - for (const run of runs) { - assert.doesNotMatch(run, /run\(\) is being called recursively/); + if (action === 'rename2') { + assert.match(run, /MODULE_NOT_FOUND/); + } else { + assert.doesNotMatch(run, /MODULE_NOT_FOUND/); + } assert.match(run, /# tests 1/); assert.match(run, /# pass 1/); assert.match(run, /# fail 0/); assert.match(run, /# cancelled 0/); - assert.match(run, /MODULE_NOT_FOUND/); } }; @@ -163,7 +147,7 @@ describe('test runner watch mode', () => { await testWatch({ fileToUpdate: 'test.js', action: 'rename' }); }); - it('should not throw when delete a watched test file', async () => { + it('should not throw when deleting a watched test file', async () => { await testWatch({ fileToUpdate: 'test.js', action: 'delete' }); }); @@ -176,7 +160,7 @@ describe('test runner watch mode', () => { }); }); - it('should handle ranames in a different cwd', async () => { + it('should handle renames in a different cwd', async () => { await testWatch({ file: join(tmpdir.path, 'test.js'), fileToUpdate: 'test.js', From 807e4736fb579ec90141f2d650b80353c4d659ca Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 18 Jul 2024 14:53:21 +0200 Subject: [PATCH 06/24] fixup Signed-off-by: Matteo Collina --- test/parallel/test-runner-run.mjs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index 578b16041660c4..43f8aa542de7dc 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -398,7 +398,6 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { const executedTestFiles = []; stream.on('test:fail', common.mustNotCall()); stream.on('test:pass', (passedTest) => { - process._rawDebug(passedTest.file); executedTestFiles.push(passedTest.file); }); // eslint-disable-next-line no-unused-vars From aaa0f99cd42ae9bb96e1c3176810f819c5447bed Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 18 Jul 2024 14:55:50 +0200 Subject: [PATCH 07/24] fixup Signed-off-by: Matteo Collina --- lib/internal/test_runner/runner.js | 4 ++-- test/parallel/test-runner-run-watch.mjs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index 425045cbb2b426..787a5fc2ee57fb 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -484,7 +484,7 @@ function run(options = kEmptyObject) { watch, setup, only, - globPatterns + globPatterns, } = options; if (files != null) { @@ -511,7 +511,7 @@ function run(options = kEmptyObject) { if (globPatterns?.length > 0 && files?.length > 0) { throw new ERR_INVALID_ARG_VALUE( - 'options.globPatterns', globPatterns, 'is not supported when specifying \'options.files\'' + 'options.globPatterns', globPatterns, 'is not supported when specifying \'options.files\'', ); } diff --git a/test/parallel/test-runner-run-watch.mjs b/test/parallel/test-runner-run-watch.mjs index 51f5f2d31fd6fb..e301188578ac32 100644 --- a/test/parallel/test-runner-run-watch.mjs +++ b/test/parallel/test-runner-run-watch.mjs @@ -121,7 +121,7 @@ async function testWatch({ fileToUpdate, file, action = 'update', cwd = tmpdir.p action === 'update' && await testUpdate(); action === 'rename' && await testRename(); - action === 'rename2' && await testRename2(); + action === 'rename2' && await testRename(); action === 'delete' && await testDelete(); } From fb8003d9acae346c8d719298966be2eb46ee861a Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 18 Jul 2024 17:31:53 +0200 Subject: [PATCH 08/24] fixup Signed-off-by: Matteo Collina --- tools/test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/test.py b/tools/test.py index 34d0d12b4f26e8..63786b8f7c557f 100755 --- a/tools/test.py +++ b/tools/test.py @@ -317,7 +317,8 @@ def HasRun(self, output): class ActionsAnnotationProgressIndicator(DotsProgressIndicator): def AboutToRun(self, case): case.additional_flags = case.additional_flags.copy() if hasattr(case, 'additional_flags') else [] - case.additional_flags.append('--test-reporter=' + root_path + '/tools/github_reporter/index.js') + root_path = abspath(join(dirname(__file__), '../')) + os.sep + case.additional_flags.append('--test-reporter=' + root_path + 'tools/github_reporter/index.js') case.additional_flags.append('--test-reporter-destination=stdout') def GetAnnotationInfo(self, test, output): From 95eae04a1c7b29fd59ba1eaa12e6ca9f500aa0b0 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 18 Jul 2024 17:37:21 +0200 Subject: [PATCH 09/24] fixup Signed-off-by: Matteo Collina --- doc/api/test.md | 5 ----- test/parallel/test-runner-run.mjs | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/doc/api/test.md b/doc/api/test.md index 923da223b21a33..84ef00dcbd3aa5 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -1247,11 +1247,6 @@ changes: - v20.14.0 pr-url: https://github.com/nodejs/node/pull/52038 description: Added the `forceExit` option. - - version: - - v22.0.0 - - v20.14.0 - pr-url: https://github.com/nodejs/node/pull/52038 - description: Added the `forceExit` option. - version: - v20.1.0 - v18.17.0 diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index 43f8aa542de7dc..d2805c7847a9a6 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -476,7 +476,7 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { it('should only allow array in options.globPatterns', async () => { [Symbol(), {}, () => {}, 0, 1, 0n, 1n, '', '1', Promise.resolve([]), true, false] - .forEach((globPatterns) => assert.throws(() => run({ globPatterns}), { + .forEach((globPatterns) => assert.throws(() => run({ globPatterns }), { code: 'ERR_INVALID_ARG_TYPE' })); }); From 5f9b0a2106166f86548cc75a4f787fdeba550955 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 18 Jul 2024 17:38:15 +0200 Subject: [PATCH 10/24] fixup Signed-off-by: Matteo Collina --- test/fixtures/test-runner-watch.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/test-runner-watch.mjs b/test/fixtures/test-runner-watch.mjs index 2c2d427dadb472..6780b31c541690 100644 --- a/test/fixtures/test-runner-watch.mjs +++ b/test/fixtures/test-runner-watch.mjs @@ -21,4 +21,4 @@ if (values.file) { run({ files, watch: true -}).compose(tap).pipe(process.stdout); \ No newline at end of file +}).compose(tap).pipe(process.stdout); From 8eddb4ed0b1158c37c06405057c6b5e908f052be Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 18 Jul 2024 18:11:14 +0200 Subject: [PATCH 11/24] fixup Signed-off-by: Matteo Collina --- lib/internal/main/test_runner.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/internal/main/test_runner.js b/lib/internal/main/test_runner.js index 1774ad43f9cf10..a42c1e5dff64cc 100644 --- a/lib/internal/main/test_runner.js +++ b/lib/internal/main/test_runner.js @@ -1,5 +1,9 @@ 'use strict'; +const { + ArrayPrototypeSlice, +} = primordials; + const { prepareMainThreadExecution, markBootstrapComplete, @@ -42,7 +46,7 @@ const options = { setup: setupTestReporters, timeout: perFileTimeout, shard, - globPatterns: process.argv.slice(1), + globPatterns: ArrayPrototypeSlice(process.argv, 1), }; debug('test runner configuration:', options); run(options).on('test:fail', (data) => { From d7ad6ee483a907b099dcb8404395b6bb69b7edc2 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Thu, 18 Jul 2024 18:27:21 +0200 Subject: [PATCH 12/24] fixup Signed-off-by: Matteo Collina --- doc/api/test.md | 2 ++ lib/internal/test_runner/runner.js | 15 +++++++++++---- test/parallel/test-runner-run.mjs | 11 ++++++----- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/doc/api/test.md b/doc/api/test.md index 84ef00dcbd3aa5..7b2c4376a9a4c5 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -1263,6 +1263,8 @@ changes: parallel. If `false`, it would only run one test file at a time. **Default:** `false`. + * `cwd` {string} The current working directory for the test runner. + **Default:** `process.cwd()`. * `files`: {Array} An array containing the list of files to run. **Default** matching files from [test runner execution model][]. * `forceExit`: {boolean} Configures the test runner to exit the process once diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index 787a5fc2ee57fb..4756068841b7db 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -51,6 +51,7 @@ const { validateFunction, validateObject, validateInteger, + validateString, } = require('internal/validators'); const { getInspectPort, isUsingInspector, isInspectorMessage } = require('internal/util/inspector'); const { isRegExp } = require('internal/util/types'); @@ -88,8 +89,7 @@ const kCanceledTests = new SafeSet() let kResistStopPropagation; -function createTestFileList(patterns) { - const cwd = process.cwd(); +function createTestFileList(cwd, patterns) { const hasUserSuppliedPattern = patterns != null; if (!patterns || patterns.length === 0) { patterns = [kDefaultPattern]; @@ -421,7 +421,7 @@ function watchFiles(testFiles, opts) { watcher.on('changed', ({ owners, eventType }) => { if (!opts.hasFiles && eventType === 'rename') { - const updatedTestFiles = createTestFileList(opts.globPatterns); + const updatedTestFiles = createTestFileList(opts.cwd, opts.globPatterns); const newFileName = ArrayPrototypeFind(updatedTestFiles, (x) => !ArrayPrototypeIncludes(testFiles, x)); const previousFileName = ArrayPrototypeFind(testFiles, (x) => !ArrayPrototypeIncludes(updatedTestFiles, x)); @@ -484,6 +484,7 @@ function run(options = kEmptyObject) { watch, setup, only, + cwd, globPatterns, } = options; @@ -530,6 +531,11 @@ function run(options = kEmptyObject) { if (setup != null) { validateFunction(setup, 'options.setup'); } + + if (cwd != null) { + validateString(cwd, 'options.cwd'); + } + if (testNamePatterns != null) { if (!ArrayIsArray(testNamePatterns)) { testNamePatterns = [testNamePatterns]; @@ -571,7 +577,7 @@ function run(options = kEmptyObject) { root.postRun(); return root.reporter; } - let testFiles = files ?? createTestFileList(globPatterns); + let testFiles = files ?? createTestFileList(cwd, globPatterns); if (shard) { testFiles = ArrayPrototypeFilter(testFiles, (_, index) => index % shard.total === shard.index - 1); @@ -590,6 +596,7 @@ function run(options = kEmptyObject) { globPatterns, only, forceExit, + cwd, }; if (watch) { filesWatcher = watchFiles(testFiles, opts); diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index d2805c7847a9a6..8d0f4704e9dbd0 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -8,11 +8,6 @@ import tmpdir from '../common/tmpdir.js'; const testFixtures = fixtures.path('test-runner'); -// This is needed, because calling run() with no files will -// load files matching from cwd, which includes all content of test/ -tmpdir.refresh(); -process.chdir(tmpdir.path); - describe('require(\'node:test\').run', { concurrency: true }, () => { it('should run with no tests', async () => { const stream = run({ files: [] }); @@ -509,7 +504,9 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { }); it('should run with no files', async () => { + tmpdir.refresh(); const stream = run({ + cwd: tmpdir.path, files: undefined }).compose(tap); stream.on('test:fail', common.mustNotCall()); @@ -520,7 +517,9 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { }); it('should run with no files and use spec reporter', async () => { + tmpdir.refresh(); const stream = run({ + cwd: tmpdir.path, files: undefined }).compose(spec); stream.on('test:fail', common.mustNotCall()); @@ -531,7 +530,9 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { }); it('should run with no files and use dot reporter', async () => { + tmpdir.refresh(); const stream = run({ + cwd: tmpdir.path, files: undefined }).compose(dot); stream.on('test:fail', common.mustNotCall()); From 51ec7e22dcde84f8fbfa6836791af0c2f8967bac Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Fri, 19 Jul 2024 16:30:36 +0200 Subject: [PATCH 13/24] Revert "fixup" This reverts commit d7ad6ee483a907b099dcb8404395b6bb69b7edc2. --- doc/api/test.md | 2 -- lib/internal/test_runner/runner.js | 15 ++++----------- test/parallel/test-runner-run.mjs | 11 +++++------ 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/doc/api/test.md b/doc/api/test.md index 7b2c4376a9a4c5..84ef00dcbd3aa5 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -1263,8 +1263,6 @@ changes: parallel. If `false`, it would only run one test file at a time. **Default:** `false`. - * `cwd` {string} The current working directory for the test runner. - **Default:** `process.cwd()`. * `files`: {Array} An array containing the list of files to run. **Default** matching files from [test runner execution model][]. * `forceExit`: {boolean} Configures the test runner to exit the process once diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index 4756068841b7db..787a5fc2ee57fb 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -51,7 +51,6 @@ const { validateFunction, validateObject, validateInteger, - validateString, } = require('internal/validators'); const { getInspectPort, isUsingInspector, isInspectorMessage } = require('internal/util/inspector'); const { isRegExp } = require('internal/util/types'); @@ -89,7 +88,8 @@ const kCanceledTests = new SafeSet() let kResistStopPropagation; -function createTestFileList(cwd, patterns) { +function createTestFileList(patterns) { + const cwd = process.cwd(); const hasUserSuppliedPattern = patterns != null; if (!patterns || patterns.length === 0) { patterns = [kDefaultPattern]; @@ -421,7 +421,7 @@ function watchFiles(testFiles, opts) { watcher.on('changed', ({ owners, eventType }) => { if (!opts.hasFiles && eventType === 'rename') { - const updatedTestFiles = createTestFileList(opts.cwd, opts.globPatterns); + const updatedTestFiles = createTestFileList(opts.globPatterns); const newFileName = ArrayPrototypeFind(updatedTestFiles, (x) => !ArrayPrototypeIncludes(testFiles, x)); const previousFileName = ArrayPrototypeFind(testFiles, (x) => !ArrayPrototypeIncludes(updatedTestFiles, x)); @@ -484,7 +484,6 @@ function run(options = kEmptyObject) { watch, setup, only, - cwd, globPatterns, } = options; @@ -531,11 +530,6 @@ function run(options = kEmptyObject) { if (setup != null) { validateFunction(setup, 'options.setup'); } - - if (cwd != null) { - validateString(cwd, 'options.cwd'); - } - if (testNamePatterns != null) { if (!ArrayIsArray(testNamePatterns)) { testNamePatterns = [testNamePatterns]; @@ -577,7 +571,7 @@ function run(options = kEmptyObject) { root.postRun(); return root.reporter; } - let testFiles = files ?? createTestFileList(cwd, globPatterns); + let testFiles = files ?? createTestFileList(globPatterns); if (shard) { testFiles = ArrayPrototypeFilter(testFiles, (_, index) => index % shard.total === shard.index - 1); @@ -596,7 +590,6 @@ function run(options = kEmptyObject) { globPatterns, only, forceExit, - cwd, }; if (watch) { filesWatcher = watchFiles(testFiles, opts); diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index 8d0f4704e9dbd0..d2805c7847a9a6 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -8,6 +8,11 @@ import tmpdir from '../common/tmpdir.js'; const testFixtures = fixtures.path('test-runner'); +// This is needed, because calling run() with no files will +// load files matching from cwd, which includes all content of test/ +tmpdir.refresh(); +process.chdir(tmpdir.path); + describe('require(\'node:test\').run', { concurrency: true }, () => { it('should run with no tests', async () => { const stream = run({ files: [] }); @@ -504,9 +509,7 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { }); it('should run with no files', async () => { - tmpdir.refresh(); const stream = run({ - cwd: tmpdir.path, files: undefined }).compose(tap); stream.on('test:fail', common.mustNotCall()); @@ -517,9 +520,7 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { }); it('should run with no files and use spec reporter', async () => { - tmpdir.refresh(); const stream = run({ - cwd: tmpdir.path, files: undefined }).compose(spec); stream.on('test:fail', common.mustNotCall()); @@ -530,9 +531,7 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { }); it('should run with no files and use dot reporter', async () => { - tmpdir.refresh(); const stream = run({ - cwd: tmpdir.path, files: undefined }).compose(dot); stream.on('test:fail', common.mustNotCall()); From 4a29e295b374b77842f3122b3d5554ce2b94de98 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Fri, 19 Jul 2024 16:42:25 +0200 Subject: [PATCH 14/24] fixup Signed-off-by: Matteo Collina --- .../test-runner-run-files-undefined.mjs | 52 +++++++++++++++++++ test/parallel/test-runner-run.mjs | 39 -------------- 2 files changed, 52 insertions(+), 39 deletions(-) create mode 100644 test/parallel/test-runner-run-files-undefined.mjs diff --git a/test/parallel/test-runner-run-files-undefined.mjs b/test/parallel/test-runner-run-files-undefined.mjs new file mode 100644 index 00000000000000..25422f1a6dbe16 --- /dev/null +++ b/test/parallel/test-runner-run-files-undefined.mjs @@ -0,0 +1,52 @@ +import * as common from '../common/index.mjs'; +import tmpdir from '../common/tmpdir.js'; +import { describe, it, run, beforeEach } from 'node:test'; +import { dot, spec, tap } from 'node:test/reporters'; +import child_process from 'child_process'; +import { fork } from 'node:child_process'; + +if (process.env.CHILD === 'true') { + describe('require(\'node:test\').run with no files', { concurrency: true }, () => { + beforeEach(() => { + tmpdir.refresh(); + process.chdir(tmpdir.path); + }) + + it('should neither pass or fail', async () => { + const stream = run({ + files: undefined + }).compose(tap); + stream.on('test:fail', common.mustNotCall()); + stream.on('test:pass', common.mustNotCall()); + + // eslint-disable-next-line no-unused-vars + for await (const _ of stream); + }); + + it('can use the spec reporter', async () => { + const stream = run({ + files: undefined + }).compose(spec); + stream.on('test:fail', common.mustNotCall()); + stream.on('test:pass', common.mustNotCall()); + + // eslint-disable-next-line no-unused-vars + for await (const _ of stream); + }); + + it('can use the dot reporter', async () => { + const stream = run({ + files: undefined + }).compose(dot); + stream.on('test:fail', common.mustNotCall()); + stream.on('test:pass', common.mustNotCall()); + + // eslint-disable-next-line no-unused-vars + for await (const _ of stream); + }); + }) +} else { + const child = fork(import.meta.filename, [], { + env: { CHILD: 'true' } + }); +} diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index d2805c7847a9a6..42baddb45d1ce6 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -2,17 +2,11 @@ import * as common from '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; import { join } from 'node:path'; import { describe, it, run } from 'node:test'; -import { dot, spec, tap } from 'node:test/reporters'; import assert from 'node:assert'; import tmpdir from '../common/tmpdir.js'; const testFixtures = fixtures.path('test-runner'); -// This is needed, because calling run() with no files will -// load files matching from cwd, which includes all content of test/ -tmpdir.refresh(); -process.chdir(tmpdir.path); - describe('require(\'node:test\').run', { concurrency: true }, () => { it('should run with no tests', async () => { const stream = run({ files: [] }); @@ -508,39 +502,6 @@ describe('require(\'node:test\').run', { concurrency: true }, () => { }); }); - it('should run with no files', async () => { - const stream = run({ - files: undefined - }).compose(tap); - stream.on('test:fail', common.mustNotCall()); - stream.on('test:pass', common.mustNotCall()); - - // eslint-disable-next-line no-unused-vars - for await (const _ of stream); - }); - - it('should run with no files and use spec reporter', async () => { - const stream = run({ - files: undefined - }).compose(spec); - stream.on('test:fail', common.mustNotCall()); - stream.on('test:pass', common.mustNotCall()); - - // eslint-disable-next-line no-unused-vars - for await (const _ of stream); - }); - - it('should run with no files and use dot reporter', async () => { - const stream = run({ - files: undefined - }).compose(dot); - stream.on('test:fail', common.mustNotCall()); - stream.on('test:pass', common.mustNotCall()); - - // eslint-disable-next-line no-unused-vars - for await (const _ of stream); - }); - it('should avoid running recursively', async () => { const stream = run({ files: [join(testFixtures, 'recursive_run.js')] }); let stderr = ''; From 71df5bf69f176aaeaedab61a02675249297d35fe Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Fri, 19 Jul 2024 17:37:17 +0200 Subject: [PATCH 15/24] fixup Signed-off-by: Matteo Collina --- test/parallel/test-runner-run-files-undefined.mjs | 7 +++---- test/parallel/test-runner-run.mjs | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test/parallel/test-runner-run-files-undefined.mjs b/test/parallel/test-runner-run-files-undefined.mjs index 25422f1a6dbe16..bed2bf9c5a07a9 100644 --- a/test/parallel/test-runner-run-files-undefined.mjs +++ b/test/parallel/test-runner-run-files-undefined.mjs @@ -2,7 +2,6 @@ import * as common from '../common/index.mjs'; import tmpdir from '../common/tmpdir.js'; import { describe, it, run, beforeEach } from 'node:test'; import { dot, spec, tap } from 'node:test/reporters'; -import child_process from 'child_process'; import { fork } from 'node:child_process'; if (process.env.CHILD === 'true') { @@ -10,7 +9,7 @@ if (process.env.CHILD === 'true') { beforeEach(() => { tmpdir.refresh(); process.chdir(tmpdir.path); - }) + }); it('should neither pass or fail', async () => { const stream = run({ @@ -44,9 +43,9 @@ if (process.env.CHILD === 'true') { // eslint-disable-next-line no-unused-vars for await (const _ of stream); }); - }) + }); } else { - const child = fork(import.meta.filename, [], { + fork(import.meta.filename, [], { env: { CHILD: 'true' } }); } diff --git a/test/parallel/test-runner-run.mjs b/test/parallel/test-runner-run.mjs index 42baddb45d1ce6..e331b70dd1cb88 100644 --- a/test/parallel/test-runner-run.mjs +++ b/test/parallel/test-runner-run.mjs @@ -2,8 +2,8 @@ import * as common from '../common/index.mjs'; import * as fixtures from '../common/fixtures.mjs'; import { join } from 'node:path'; import { describe, it, run } from 'node:test'; +import { dot, spec, tap } from 'node:test/reporters'; import assert from 'node:assert'; -import tmpdir from '../common/tmpdir.js'; const testFixtures = fixtures.path('test-runner'); From 09785dc0fa6094e868aa00a05325f048fcfb944a Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Fri, 19 Jul 2024 17:40:35 +0200 Subject: [PATCH 16/24] fixup Signed-off-by: Matteo Collina --- doc/api/test.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/test.md b/doc/api/test.md index 84ef00dcbd3aa5..9c3dcd568b86bd 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -1269,8 +1269,8 @@ changes: all known tests have finished executing even if the event loop would otherwise remain active. **Default:** `false`. * `globPatterns`: {Array} An array containing the list of glob patterns to - match test files. **Default:** matching files from - [test runner execution model][]. + match test files. This option cannot be used together with `files`. + **Default:** matching files from [test runner execution model][]. * `inspectPort` {number|Function} Sets inspector port of test child process. This can be a number, or a function that takes no arguments and returns a number. If a nullish value is provided, each process gets its own port, From 182949dcc8839b154439507ea10945a278c2fb0a Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Mon, 22 Jul 2024 12:24:33 +0200 Subject: [PATCH 17/24] Update test/parallel/test-runner-run-files-undefined.mjs Co-authored-by: Colin Ihrig --- test/parallel/test-runner-run-files-undefined.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/parallel/test-runner-run-files-undefined.mjs b/test/parallel/test-runner-run-files-undefined.mjs index bed2bf9c5a07a9..842a6539d0d4ad 100644 --- a/test/parallel/test-runner-run-files-undefined.mjs +++ b/test/parallel/test-runner-run-files-undefined.mjs @@ -47,5 +47,7 @@ if (process.env.CHILD === 'true') { } else { fork(import.meta.filename, [], { env: { CHILD: 'true' } + }).on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); }); } From c761443afff897ba06fd06c734fe3ccb39d4b4db Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Mon, 22 Jul 2024 12:42:23 +0200 Subject: [PATCH 18/24] fixup Signed-off-by: Matteo Collina --- test/parallel/test-runner-run-files-undefined.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-runner-run-files-undefined.mjs b/test/parallel/test-runner-run-files-undefined.mjs index 842a6539d0d4ad..41c0f3b429371c 100644 --- a/test/parallel/test-runner-run-files-undefined.mjs +++ b/test/parallel/test-runner-run-files-undefined.mjs @@ -3,6 +3,7 @@ import tmpdir from '../common/tmpdir.js'; import { describe, it, run, beforeEach } from 'node:test'; import { dot, spec, tap } from 'node:test/reporters'; import { fork } from 'node:child_process'; +import assert from 'node:assert'; if (process.env.CHILD === 'true') { describe('require(\'node:test\').run with no files', { concurrency: true }, () => { @@ -48,6 +49,6 @@ if (process.env.CHILD === 'true') { fork(import.meta.filename, [], { env: { CHILD: 'true' } }).on('exit', common.mustCall((code) => { - assert.strictEqual(code, 0); - }); + assert.strictEqual(code, 0); + })); } From d2900298b92226de6910a2e79f1c35d5e9aa6ce6 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Mon, 22 Jul 2024 15:31:35 +0200 Subject: [PATCH 19/24] skipping test on aix Signed-off-by: Matteo Collina --- test/parallel/test-runner-run-files-undefined.mjs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/parallel/test-runner-run-files-undefined.mjs b/test/parallel/test-runner-run-files-undefined.mjs index 41c0f3b429371c..c147bc3f0f3ffd 100644 --- a/test/parallel/test-runner-run-files-undefined.mjs +++ b/test/parallel/test-runner-run-files-undefined.mjs @@ -45,6 +45,8 @@ if (process.env.CHILD === 'true') { for await (const _ of stream); }); }); +} else if (common.isAIX) { + console.log('1..0 # Skipped: test runner watch mode'); } else { fork(import.meta.filename, [], { env: { CHILD: 'true' } From 9b164ab5ed7c0f954529ce1449f682a374987448 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Tue, 23 Jul 2024 09:20:25 +0200 Subject: [PATCH 20/24] fixup Signed-off-by: Matteo Collina --- test/parallel/test-runner-run-files-undefined.mjs | 7 ++++++- test/parallel/test-runner-watch-mode.mjs | 3 +-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/parallel/test-runner-run-files-undefined.mjs b/test/parallel/test-runner-run-files-undefined.mjs index c147bc3f0f3ffd..9d08b10a4550cd 100644 --- a/test/parallel/test-runner-run-files-undefined.mjs +++ b/test/parallel/test-runner-run-files-undefined.mjs @@ -5,6 +5,11 @@ import { dot, spec, tap } from 'node:test/reporters'; import { fork } from 'node:child_process'; import assert from 'node:assert'; +if (common.hasCrypto) { + console.log('1..0 # Skipped: no crypto'); + process.exit(0); +} + if (process.env.CHILD === 'true') { describe('require(\'node:test\').run with no files', { concurrency: true }, () => { beforeEach(() => { @@ -46,7 +51,7 @@ if (process.env.CHILD === 'true') { }); }); } else if (common.isAIX) { - console.log('1..0 # Skipped: test runner watch mode'); + console.log('1..0 # Skipped: test runner without specifying files fails on AIX'); } else { fork(import.meta.filename, [], { env: { CHILD: 'true' } diff --git a/test/parallel/test-runner-watch-mode.mjs b/test/parallel/test-runner-watch-mode.mjs index 6407ee90c3fd91..26a0d73ab19845 100644 --- a/test/parallel/test-runner-watch-mode.mjs +++ b/test/parallel/test-runner-watch-mode.mjs @@ -7,7 +7,6 @@ import { writeFileSync, renameSync, unlinkSync, existsSync } from 'node:fs'; import util from 'internal/util'; import tmpdir from '../common/tmpdir.js'; - if (common.isIBMi) common.skip('IBMi does not support `fs.watch()`'); @@ -134,7 +133,7 @@ describe('test runner watch mode', () => { await testWatch({ fileToUpdate: 'test.js', action: 'rename' }); }); - it('should not throw when delete a watched test file', async () => { + it('should not throw when delete a watched test file', { skip: common.isAIX }, async () => { await testWatch({ fileToUpdate: 'test.js', action: 'delete' }); }); }); From 82bf7f20a01cfd17db37a1e2d31567429480fefd Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Tue, 23 Jul 2024 09:48:53 +0200 Subject: [PATCH 21/24] fixup Signed-off-by: Matteo Collina --- tools/test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/test.py b/tools/test.py index 63786b8f7c557f..6ee22e15f7421c 100755 --- a/tools/test.py +++ b/tools/test.py @@ -317,8 +317,8 @@ def HasRun(self, output): class ActionsAnnotationProgressIndicator(DotsProgressIndicator): def AboutToRun(self, case): case.additional_flags = case.additional_flags.copy() if hasattr(case, 'additional_flags') else [] - root_path = abspath(join(dirname(__file__), '../')) + os.sep - case.additional_flags.append('--test-reporter=' + root_path + 'tools/github_reporter/index.js') + reporter_path = abspath(join(dirname(__file__), '..', 'tools', 'github_reporter', 'index.js')) + case.additional_flags.append('--test-reporter=' + reporter_path) case.additional_flags.append('--test-reporter-destination=stdout') def GetAnnotationInfo(self, test, output): From cdf2a0310b4b1044b4dcc1eac4309700b87b5367 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Tue, 23 Jul 2024 12:28:38 +0200 Subject: [PATCH 22/24] fixup Signed-off-by: Matteo Collina --- test/parallel/test-runner-run-watch.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-runner-run-watch.mjs b/test/parallel/test-runner-run-watch.mjs index e301188578ac32..389093063a793e 100644 --- a/test/parallel/test-runner-run-watch.mjs +++ b/test/parallel/test-runner-run-watch.mjs @@ -147,7 +147,7 @@ describe('test runner watch mode', () => { await testWatch({ fileToUpdate: 'test.js', action: 'rename' }); }); - it('should not throw when deleting a watched test file', async () => { + it('should not throw when deleting a watched test file', { skip: common.isAIX }, async () => { await testWatch({ fileToUpdate: 'test.js', action: 'delete' }); }); From bd7d8e2c81078b672b3a0b5bc5446de17be96013 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Wed, 24 Jul 2024 10:31:50 +0200 Subject: [PATCH 23/24] fixup Signed-off-by: Matteo Collina --- tools/test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/test.py b/tools/test.py index 6ee22e15f7421c..9d7838d7c0110a 100755 --- a/tools/test.py +++ b/tools/test.py @@ -317,8 +317,7 @@ def HasRun(self, output): class ActionsAnnotationProgressIndicator(DotsProgressIndicator): def AboutToRun(self, case): case.additional_flags = case.additional_flags.copy() if hasattr(case, 'additional_flags') else [] - reporter_path = abspath(join(dirname(__file__), '..', 'tools', 'github_reporter', 'index.js')) - case.additional_flags.append('--test-reporter=' + reporter_path) + case.additional_flags.append('--test-reporter=./tools/github_reporter/index.js') case.additional_flags.append('--test-reporter-destination=stdout') def GetAnnotationInfo(self, test, output): From 689bd6d3602fe0a8162204cdb3b6b62b0ca5a308 Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Wed, 24 Jul 2024 12:49:22 +0200 Subject: [PATCH 24/24] fixup Signed-off-by: Matteo Collina --- test/parallel/test-runner-run-watch.mjs | 4 ++++ test/parallel/test-runner-watch-mode.mjs | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/test/parallel/test-runner-run-watch.mjs b/test/parallel/test-runner-run-watch.mjs index 389093063a793e..0445637bb6123c 100644 --- a/test/parallel/test-runner-run-watch.mjs +++ b/test/parallel/test-runner-run-watch.mjs @@ -3,6 +3,7 @@ import * as common from '../common/index.mjs'; import { describe, it, beforeEach } from 'node:test'; import assert from 'node:assert'; import { spawn } from 'node:child_process'; +import { once } from 'node:events'; import { writeFileSync, renameSync, unlinkSync, existsSync } from 'node:fs'; import util from 'internal/util'; import tmpdir from '../common/tmpdir.js'; @@ -66,6 +67,7 @@ async function testWatch({ fileToUpdate, file, action = 'update', cwd = tmpdir.p runs.push(currentRun); clearInterval(interval); child.kill(); + await once(child, 'exit'); for (const run of runs) { assert.doesNotMatch(run, /run\(\) is being called recursively/); assert.match(run, /# tests 1/); @@ -84,6 +86,7 @@ async function testWatch({ fileToUpdate, file, action = 'update', cwd = tmpdir.p runs.push(currentRun); clearInterval(interval); child.kill(); + await once(child, 'exit'); for (const run of runs) { assert.doesNotMatch(run, /run\(\) is being called recursively/); @@ -113,6 +116,7 @@ async function testWatch({ fileToUpdate, file, action = 'update', cwd = tmpdir.p runs.push(currentRun); clearInterval(interval); child.kill(); + await once(child, 'exit'); for (const run of runs) { assert.doesNotMatch(run, /MODULE_NOT_FOUND/); diff --git a/test/parallel/test-runner-watch-mode.mjs b/test/parallel/test-runner-watch-mode.mjs index 26a0d73ab19845..a55f404a4f7010 100644 --- a/test/parallel/test-runner-watch-mode.mjs +++ b/test/parallel/test-runner-watch-mode.mjs @@ -1,6 +1,7 @@ // Flags: --expose-internals import * as common from '../common/index.mjs'; import { describe, it, beforeEach } from 'node:test'; +import { once } from 'node:events'; import assert from 'node:assert'; import { spawn } from 'node:child_process'; import { writeFileSync, renameSync, unlinkSync, existsSync } from 'node:fs'; @@ -60,6 +61,8 @@ async function testWatch({ fileToUpdate, file, action = 'update' }) { runs.push(currentRun); clearInterval(interval); child.kill(); + await once(child, 'exit'); + for (const run of runs) { assert.match(run, /# tests 1/); assert.match(run, /# pass 1/); @@ -77,6 +80,7 @@ async function testWatch({ fileToUpdate, file, action = 'update' }) { runs.push(currentRun); clearInterval(interval); child.kill(); + await once(child, 'exit'); for (const run of runs) { assert.match(run, /# tests 1/); @@ -100,6 +104,7 @@ async function testWatch({ fileToUpdate, file, action = 'update' }) { runs.push(currentRun); clearInterval(interval); child.kill(); + await once(child, 'exit'); for (const run of runs) { assert.doesNotMatch(run, /MODULE_NOT_FOUND/);