From e36e4ffd49e3df64a92287c63fc0b16f1119a975 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 16 Feb 2023 17:58:37 -0500 Subject: [PATCH] test_runner: handle errors not bound to tests This commit addresses a previously untested branch of the code. It is possible when using the test runner that an error occurs outside of a test. In this case, the test runner would simply rethrow the error. This commit updates the logic to handle the error in the same fashion as other uncaughtExceptions. --- lib/internal/test_runner/harness.js | 15 ++++++--------- test/message/test_runner_output.js | 6 ++++++ test/message/test_runner_output.out | 1 + test/message/test_runner_output_cli.out | 1 + test/message/test_runner_output_spec_reporter.out | 1 + 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/internal/test_runner/harness.js b/lib/internal/test_runner/harness.js index 5fc85bae11356a..af63e521f9e43f 100644 --- a/lib/internal/test_runner/harness.js +++ b/lib/internal/test_runner/harness.js @@ -43,15 +43,12 @@ function createProcessEventHandler(eventName, rootTest) { // Check if this error is coming from a test. If it is, fail the test. const test = testResources.get(executionAsyncId()); - if (!test) { - throw err; - } - - if (test.finished) { - // If the test is already finished, report this as a top level - // diagnostic since this is a malformed test. - const msg = `Warning: Test "${test.name}" generated asynchronous ` + - 'activity after the test ended. This activity created the error ' + + if (!test || test.finished) { + // If the test is already finished or the resource that created the error + // is not mapped to a Test, report this as a top level diagnostic. + const src = test ? `Test "${test.name}"` : 'A resource'; + const msg = `Warning: ${src} generated asynchronous activity after ` + + 'the test ended. This activity created the error ' + `"${err}" and would have caused the test to fail, but instead ` + `triggered an ${eventName} event.`; diff --git a/test/message/test_runner_output.js b/test/message/test_runner_output.js index 593f069d8f4606..a53ded3dfde3ac 100644 --- a/test/message/test_runner_output.js +++ b/test/message/test_runner_output.js @@ -383,3 +383,9 @@ test('unfinished test with unhandledRejection', async () => { setTimeout(() => Promise.reject(new Error('bar'))); }); }); + +// Verify that uncaught exceptions outside of any tests are handled after the +// test harness has finished bootstrapping itself. +setImmediate(() => { + throw new Error('uncaught from outside of a test'); +}); diff --git a/test/message/test_runner_output.out b/test/message/test_runner_output.out index 2609833304e246..862f96047995fb 100644 --- a/test/message/test_runner_output.out +++ b/test/message/test_runner_output.out @@ -637,6 +637,7 @@ not ok 65 - invalid subtest fail 1..65 # Warning: Test "unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. # Warning: Test "async unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from async unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. +# Warning: A resource generated asynchronous activity after the test ended. This activity created the error "Error: uncaught from outside of a test" and would have caused the test to fail, but instead triggered an uncaughtException event. # Warning: Test "immediate throw - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: thrown from immediate throw fail" and would have caused the test to fail, but instead triggered an uncaughtException event. # Warning: Test "immediate reject - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from immediate reject fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. # Warning: Test "callback called twice in different ticks" generated asynchronous activity after the test ended. This activity created the error "Error [ERR_TEST_FAILURE]: callback invoked multiple times" and would have caused the test to fail, but instead triggered an uncaughtException event. diff --git a/test/message/test_runner_output_cli.out b/test/message/test_runner_output_cli.out index 72957397c05454..435bad728eb363 100644 --- a/test/message/test_runner_output_cli.out +++ b/test/message/test_runner_output_cli.out @@ -636,6 +636,7 @@ not ok 65 - invalid subtest fail ... # Warning: Test "unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. # Warning: Test "async unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from async unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. +# Warning: A resource generated asynchronous activity after the test ended. This activity created the error "Error: uncaught from outside of a test" and would have caused the test to fail, but instead triggered an uncaughtException event. # Warning: Test "immediate throw - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: thrown from immediate throw fail" and would have caused the test to fail, but instead triggered an uncaughtException event. # Warning: Test "immediate reject - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from immediate reject fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. # Warning: Test "callback called twice in different ticks" generated asynchronous activity after the test ended. This activity created the error "Error [ERR_TEST_FAILURE]: callback invoked multiple times" and would have caused the test to fail, but instead triggered an uncaughtException event. diff --git a/test/message/test_runner_output_spec_reporter.out b/test/message/test_runner_output_spec_reporter.out index 591dc9a76d64d0..3e2e0e746ca00b 100644 --- a/test/message/test_runner_output_spec_reporter.out +++ b/test/message/test_runner_output_spec_reporter.out @@ -270,6 +270,7 @@ Warning: Test "unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. Warning: Test "async unhandled rejection - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from async unhandled rejection fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. + Warning: A resource generated asynchronous activity after the test ended. This activity created the error "Error: uncaught from outside of a test" and would have caused the test to fail, but instead triggered an uncaughtException event. Warning: Test "immediate throw - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: thrown from immediate throw fail" and would have caused the test to fail, but instead triggered an uncaughtException event. Warning: Test "immediate reject - passes but warns" generated asynchronous activity after the test ended. This activity created the error "Error: rejected from immediate reject fail" and would have caused the test to fail, but instead triggered an unhandledRejection event. Warning: Test "callback called twice in different ticks" generated asynchronous activity after the test ended. This activity created the error "Error [ERR_TEST_FAILURE]: callback invoked multiple times" and would have caused the test to fail, but instead triggered an uncaughtException event.