Skip to content

Commit

Permalink
test_runner: refactor isolation handling into separate functions
Browse files Browse the repository at this point in the history
  • Loading branch information
pmarchini committed Dec 11, 2024
1 parent 4f3b8ad commit 3e66180
Showing 1 changed file with 110 additions and 93 deletions.
203 changes: 110 additions & 93 deletions lib/internal/test_runner/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand All @@ -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 () => {
Expand Down

0 comments on commit 3e66180

Please sign in to comment.