From 3e66180a971eea68a67a05363270253de7856e48 Mon Sep 17 00:00:00 2001 From: Pietro Marchini Date: Wed, 11 Dec 2024 09:58:33 +0100 Subject: [PATCH] test_runner: refactor isolation handling into separate functions --- lib/internal/test_runner/runner.js | 203 ++++++++++++++++------------- 1 file changed, 110 insertions(+), 93 deletions(-) diff --git a/lib/internal/test_runner/runner.js b/lib/internal/test_runner/runner.js index 2a954c520332f6..95a0e1d22a1888 100644 --- a/lib/internal/test_runner/runner.js +++ b/lib/internal/test_runner/runner.js @@ -692,6 +692,103 @@ function validateAndSetDefaultOptions(options) { }; } +function handleProcessIsolation(root, testFiles, opts, watch) { + let filesWatcher; + let postRun; + let teardown; + + if (watch) { + filesWatcher = watchFiles(testFiles, opts); + } else { + postRun = () => root.postRun(); + teardown = () => root.harness.teardown(); + } + + const runFiles = () => { + root.harness.bootstrapPromise = null; + root.harness.buildPromise = null; + return SafePromiseAllSettledReturnVoid(testFiles, (path) => { + const subtest = runTestFile(path, filesWatcher, opts); + filesWatcher?.runningSubtests.set(path, subtest); + return subtest; + }); + }; + + return { __proto__: null, runFiles, postRun, teardown }; +} + +function handleNoneIsolation(root, testFiles, opts, watch, cwd) { + let filesWatcher; + + if (watch) { + const absoluteTestFiles = ArrayPrototypeMap(testFiles, (file) => (isAbsolute(file) ? file : resolve(cwd, file))); + filesWatcher = watchFiles(absoluteTestFiles, opts); + return async () => { + root.harness.bootstrapPromise = null; + root.harness.buildPromise = null; + const subtest = runTestFile(kIsolatedProcessName, filesWatcher, opts); + filesWatcher?.runningSubtests.set(kIsolatedProcessName, subtest); + return subtest; + }; + } + return async () => { + const { promise, resolve: finishBootstrap } = PromiseWithResolvers(); + + await root.runInAsyncScope(async () => { + const parentURL = pathToFileURL(cwd + sep).href; + const cascadedLoader = esmLoader.getOrInitializeCascadedLoader(); + let topLevelTestCount = 0; + + root.harness.bootstrapPromise = promise; + + const userImports = getOptionValue('--import'); + for (let i = 0; i < userImports.length; i++) { + await cascadedLoader.import(userImports[i], parentURL, kEmptyObject); + } + + for (let i = 0; i < testFiles.length; ++i) { + const testFile = testFiles[i]; + const fileURL = pathToFileURL(resolve(cwd, testFile)); + const parent = i === 0 ? undefined : parentURL; + let threw = false; + let importError; + + root.entryFile = resolve(testFile); + debug('loading test file:', fileURL.href); + try { + await cascadedLoader.import(fileURL, parent, { __proto__: null }); + } catch (err) { + threw = true; + importError = err; + } + + debug( + 'loaded "%s": top level test count before = %d and after = %d', + testFile, + topLevelTestCount, + root.subtests.length, + ); + if (topLevelTestCount === root.subtests.length) { + // This file has no tests in it. Add the placeholder test. + const subtest = root.createSubtest(Test, testFile); + if (threw) { + subtest.fail(importError); + } + startSubtestAfterBootstrap(subtest); + } + + topLevelTestCount = root.subtests.length; + } + }); + + debug('beginning test execution'); + root.entryFile = null; + finishBootstrap(); + root.processPendingSubtests(); + }; +} + + function run(options = kEmptyObject) { const { testNamePatterns, @@ -741,10 +838,6 @@ function run(options = kEmptyObject) { testFiles = ArrayPrototypeFilter(testFiles, (_, index) => index % shard.total === shard.index - 1); } - let teardown; - let postRun; - let filesWatcher; - let runFiles; const opts = { __proto__: null, root, @@ -762,97 +855,21 @@ function run(options = kEmptyObject) { execArgv, }; - if (isolation === 'process') { - if (process.env.NODE_TEST_CONTEXT !== undefined) { - process.emitWarning('node:test run() is being called recursively within a test file. skipping running files.'); - root.postRun(); - return root.reporter; - } - - if (watch) { - filesWatcher = watchFiles(testFiles, opts); - } else { - postRun = () => root.postRun(); - teardown = () => root.harness.teardown(); - } - - runFiles = () => { - root.harness.bootstrapPromise = null; - root.harness.buildPromise = null; - return SafePromiseAllSettledReturnVoid(testFiles, (path) => { - const subtest = runTestFile(path, filesWatcher, opts); - filesWatcher?.runningSubtests.set(path, subtest); - return subtest; - }); - }; - } else if (isolation === 'none') { - if (watch) { - const absoluteTestFiles = ArrayPrototypeMap(testFiles, (file) => (isAbsolute(file) ? file : resolve(cwd, file))); - filesWatcher = watchFiles(absoluteTestFiles, opts); - runFiles = async () => { - root.harness.bootstrapPromise = null; - root.harness.buildPromise = null; - const subtest = runTestFile(kIsolatedProcessName, filesWatcher, opts); - filesWatcher?.runningSubtests.set(kIsolatedProcessName, subtest); - return subtest; - }; - } else { - runFiles = async () => { - const { promise, resolve: finishBootstrap } = PromiseWithResolvers(); - - await root.runInAsyncScope(async () => { - const parentURL = pathToFileURL(cwd + sep).href; - const cascadedLoader = esmLoader.getOrInitializeCascadedLoader(); - let topLevelTestCount = 0; + let runFiles, postRun, teardown; - root.harness.bootstrapPromise = promise; - - const userImports = getOptionValue('--import'); - for (let i = 0; i < userImports.length; i++) { - await cascadedLoader.import(userImports[i], parentURL, kEmptyObject); - } - - for (let i = 0; i < testFiles.length; ++i) { - const testFile = testFiles[i]; - const fileURL = pathToFileURL(resolve(cwd, testFile)); - const parent = i === 0 ? undefined : parentURL; - let threw = false; - let importError; - - root.entryFile = resolve(testFile); - debug('loading test file:', fileURL.href); - try { - await cascadedLoader.import(fileURL, parent, { __proto__: null }); - } catch (err) { - threw = true; - importError = err; - } - - debug( - 'loaded "%s": top level test count before = %d and after = %d', - testFile, - topLevelTestCount, - root.subtests.length, - ); - if (topLevelTestCount === root.subtests.length) { - // This file had no tests in it. Add the placeholder test. - const subtest = root.createSubtest(Test, testFile); - if (threw) { - subtest.fail(importError); - } - startSubtestAfterBootstrap(subtest); - } - - topLevelTestCount = root.subtests.length; - } - }); + switch (isolation) { + case 'process': + if (process.env.NODE_TEST_CONTEXT !== undefined) { + process.emitWarning('node:test run() is being called recursively within a test file. skipping running files.'); + root.postRun(); + return root.reporter; + } + ({ runFiles, postRun, teardown } = handleProcessIsolation(root, testFiles, opts, watch)); + break; - debug('beginning test execution'); - root.entryFile = null; - finishBootstrap(); - root.processPendingSubtests(); - }; - } + case 'none': + runFiles = handleNoneIsolation(root, testFiles, opts, watch, cwd); + break; } const runChain = async () => {