diff --git a/lib/internal/test_runner/harness.js b/lib/internal/test_runner/harness.js index fbe166b68ee494a..82e417eafda72b5 100644 --- a/lib/internal/test_runner/harness.js +++ b/lib/internal/test_runner/harness.js @@ -163,6 +163,7 @@ function setup(root) { const exitHandler = async () => { if (root.subtests.length === 0 && (root.hooks.before.length > 0 || root.hooks.after.length > 0)) { // Run global before/after hooks in case there are no tests + await root.runHook('before', root.getRunArgs()); await root.run(); } root.postRun(new ERR_TEST_FAILURE( diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index 1c461a07f16bfaf..30ab6f1d24b8e1d 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -682,8 +682,10 @@ class Test extends AsyncResource { if (name === 'before' || name === 'after') { hook.run = runOnce(hook.run, kRunOnceOptions); } - if (name === 'before' && this.startTime !== null) { - // Test has already started, run the hook immediately + // If the test has already started, run the hook immediately. Do not run + // top level hooks immediately though so that we have a chance to load all + // of the tests. + if (name === 'before' && this.startTime !== null && this.parent !== null) { PromisePrototypeThen(hook.run(this.getRunArgs()), () => { if (hook.error != null) { this.fail(hook.error); diff --git a/test/fixtures/test-runner/output/global-hooks-with-no-tests.snapshot b/test/fixtures/test-runner/output/global-hooks-with-no-tests.snapshot index 9d622d8f3939bf7..110a8883122698a 100644 --- a/test/fixtures/test-runner/output/global-hooks-with-no-tests.snapshot +++ b/test/fixtures/test-runner/output/global-hooks-with-no-tests.snapshot @@ -1,5 +1,5 @@ -before TAP version 13 +before after 1..0 # tests 0