diff --git a/core/modules/media/tests/src/FunctionalJavascript/MediaEmbedFilterConfigurationUiTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaEmbedFilterConfigurationUiTest.php
index efae01fc10e47463741ef5de7a3405043a2afeca..13513802d783cb45bfce5e574a645c93eb624547 100644
--- a/core/modules/media/tests/src/FunctionalJavascript/MediaEmbedFilterConfigurationUiTest.php
+++ b/core/modules/media/tests/src/FunctionalJavascript/MediaEmbedFilterConfigurationUiTest.php
@@ -15,6 +15,13 @@ class MediaEmbedFilterConfigurationUiTest extends MediaJavascriptTestBase {
    */
   protected $defaultTheme = 'stark';
 
+  /**
+   * {@inheritdoc}
+   *
+   * @todo Remove this class property in https://www.drupal.org/node/3091878/.
+   */
+  protected $failOnJavascriptConsoleErrors = FALSE;
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.es6.js b/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.es6.js
new file mode 100644
index 0000000000000000000000000000000000000000..421d036ee8509c22621087d071be1bfc795cd48d
--- /dev/null
+++ b/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.es6.js
@@ -0,0 +1,11 @@
+/**
+ * @file
+ *  Testing tools for JavaScript errors.
+ */
+(function ({ throwError, behaviors }) {
+  behaviors.testErrors = {
+    attach: () => {
+      throwError(new Error('A manually thrown error.'));
+    },
+  };
+})(Drupal);
diff --git a/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.js b/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.js
new file mode 100644
index 0000000000000000000000000000000000000000..a3357d06f801eb847a768e6cea2fddc31a3ac4f8
--- /dev/null
+++ b/core/modules/system/tests/modules/js_errors_test/js/js_errors_test.js
@@ -0,0 +1,16 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function (_ref) {
+  var throwError = _ref.throwError,
+      behaviors = _ref.behaviors;
+  behaviors.testErrors = {
+    attach: function attach() {
+      throwError(new Error('A manually thrown error.'));
+    }
+  };
+})(Drupal);
\ No newline at end of file
diff --git a/core/modules/system/tests/modules/js_errors_test/js_errors_test.info.yml b/core/modules/system/tests/modules/js_errors_test/js_errors_test.info.yml
new file mode 100644
index 0000000000000000000000000000000000000000..64c9225341eb1ae8c84f519d1e3fb01a3396b4e7
--- /dev/null
+++ b/core/modules/system/tests/modules/js_errors_test/js_errors_test.info.yml
@@ -0,0 +1,5 @@
+name: 'JS Errors test'
+description: 'Provides a JavaScript error that can be used for tests'
+type: module
+package: Testing
+version: VERSION
diff --git a/core/modules/system/tests/modules/js_errors_test/js_errors_test.libraries.yml b/core/modules/system/tests/modules/js_errors_test/js_errors_test.libraries.yml
new file mode 100644
index 0000000000000000000000000000000000000000..3454e7cb63448c516723758191bc78a3db104d44
--- /dev/null
+++ b/core/modules/system/tests/modules/js_errors_test/js_errors_test.libraries.yml
@@ -0,0 +1,6 @@
+errors_test:
+  version: VERSION
+  js:
+    js/js_errors_test.js: {}
+  dependencies:
+    - core/drupal
diff --git a/core/modules/system/tests/modules/js_errors_test/js_errors_test.routing.yml b/core/modules/system/tests/modules/js_errors_test/js_errors_test.routing.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d096284e25296fec1ecd79b2699e9bbd9207529e
--- /dev/null
+++ b/core/modules/system/tests/modules/js_errors_test/js_errors_test.routing.yml
@@ -0,0 +1,7 @@
+js_errors_test.errors:
+  path: '/js_errors_test'
+  defaults:
+    _controller: '\Drupal\js_errors_test\Controller\JsErrorsTestController::jsErrorsTest'
+    _title: 'JsErrorsTest'
+  requirements:
+    _access: 'TRUE'
diff --git a/core/modules/system/tests/modules/js_errors_test/src/Controller/JsErrorsTestController.php b/core/modules/system/tests/modules/js_errors_test/src/Controller/JsErrorsTestController.php
new file mode 100644
index 0000000000000000000000000000000000000000..99628a272c57d184feed6810b92db836c893a56f
--- /dev/null
+++ b/core/modules/system/tests/modules/js_errors_test/src/Controller/JsErrorsTestController.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Drupal\js_errors_test\Controller;
+
+/**
+ * Test Controller loading js_errors_test/errors_test library.
+ */
+class JsErrorsTestController {
+
+  /**
+   * Renders page that has js_errors_test/errors_test library attached.
+   *
+   * @return string[][]
+   *   Render array.
+   */
+  public function jsErrorsTest(): array {
+    return [
+      '#attached' => ['library' => ['js_errors_test/errors_test']],
+    ];
+  }
+
+}
diff --git a/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.es6.js b/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.es6.js
new file mode 100644
index 0000000000000000000000000000000000000000..dd6fe578ed362223d02007d9ac7c425138239423
--- /dev/null
+++ b/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.es6.js
@@ -0,0 +1,35 @@
+/**
+ * @file
+ *  Support code for testing JavaScript error handling in functional tests.
+ */
+(function (Drupal) {
+  if (typeof console !== 'undefined' && console.warn) {
+    const originalWarnFunction = console.warn;
+    console.warn = (warning) => {
+      const warnings = JSON.parse(
+        sessionStorage.getItem('js_testing_log_test.warnings') ||
+          JSON.stringify([]),
+      );
+      warnings.push(warning);
+      sessionStorage.setItem(
+        'js_testing_log_test.warnings',
+        JSON.stringify(warnings),
+      );
+      originalWarnFunction(warning);
+    };
+
+    const originalThrowFunction = Drupal.throwError;
+    Drupal.throwError = (error) => {
+      const errors = JSON.parse(
+        sessionStorage.getItem('js_testing_log_test.errors') ||
+          JSON.stringify([]),
+      );
+      errors.push(error.stack);
+      sessionStorage.setItem(
+        'js_testing_log_test.errors',
+        JSON.stringify(errors),
+      );
+      originalThrowFunction(error);
+    };
+  }
+})(Drupal);
diff --git a/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.js b/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.js
new file mode 100644
index 0000000000000000000000000000000000000000..2a5348723b0dc8ee65442d539840f1aa3dd88ac2
--- /dev/null
+++ b/core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.js
@@ -0,0 +1,28 @@
+/**
+* DO NOT EDIT THIS FILE.
+* See the following change record for more information,
+* https://www.drupal.org/node/2815083
+* @preserve
+**/
+
+(function (Drupal) {
+  if (typeof console !== 'undefined' && console.warn) {
+    var originalWarnFunction = console.warn;
+
+    console.warn = function (warning) {
+      var warnings = JSON.parse(sessionStorage.getItem('js_testing_log_test.warnings') || JSON.stringify([]));
+      warnings.push(warning);
+      sessionStorage.setItem('js_testing_log_test.warnings', JSON.stringify(warnings));
+      originalWarnFunction(warning);
+    };
+
+    var originalThrowFunction = Drupal.throwError;
+
+    Drupal.throwError = function (error) {
+      var errors = JSON.parse(sessionStorage.getItem('js_testing_log_test.errors') || JSON.stringify([]));
+      errors.push(error.stack);
+      sessionStorage.setItem('js_testing_log_test.errors', JSON.stringify(errors));
+      originalThrowFunction(error);
+    };
+  }
+})(Drupal);
\ No newline at end of file
diff --git a/core/modules/system/tests/modules/js_deprecation_log_test/js_deprecation_log_test.info.yml b/core/modules/system/tests/modules/js_testing_log_test/js_testing_log_test.info.yml
similarity index 100%
rename from core/modules/system/tests/modules/js_deprecation_log_test/js_deprecation_log_test.info.yml
rename to core/modules/system/tests/modules/js_testing_log_test/js_testing_log_test.info.yml
diff --git a/core/modules/system/tests/modules/js_deprecation_log_test/js_deprecation_log_test.libraries.yml b/core/modules/system/tests/modules/js_testing_log_test/js_testing_log_test.libraries.yml
similarity index 61%
rename from core/modules/system/tests/modules/js_deprecation_log_test/js_deprecation_log_test.libraries.yml
rename to core/modules/system/tests/modules/js_testing_log_test/js_testing_log_test.libraries.yml
index 1744815c98613b2925cfdb03d0958d01893b0e91..d02c19893cee2f62707f7278d5e5ec675ba4a182 100644
--- a/core/modules/system/tests/modules/js_deprecation_log_test/js_deprecation_log_test.libraries.yml
+++ b/core/modules/system/tests/modules/js_testing_log_test/js_testing_log_test.libraries.yml
@@ -1,6 +1,6 @@
 deprecation_log:
   version: VERSION
   js:
-    js/js_deprecation_log.js: { weight: -100 }
+    js/js_testing_log.js: {}
   dependencies:
     - core/drupal
diff --git a/core/modules/system/tests/modules/js_deprecation_log_test/js_deprecation_log_test.module b/core/modules/system/tests/modules/js_testing_log_test/js_testing_log_test.module
similarity index 55%
rename from core/modules/system/tests/modules/js_deprecation_log_test/js_deprecation_log_test.module
rename to core/modules/system/tests/modules/js_testing_log_test/js_testing_log_test.module
index a86a2f21fbd204bd9f23ae640c1a670ad01bbaee..d140ecfdaff7543ac963d87fe897cd070cb3102a 100644
--- a/core/modules/system/tests/modules/js_deprecation_log_test/js_deprecation_log_test.module
+++ b/core/modules/system/tests/modules/js_testing_log_test/js_testing_log_test.module
@@ -8,14 +8,14 @@
 /**
  * Implements hook_page_attachments().
  */
-function js_deprecation_log_test_page_attachments(array &$attachments) {
+function js_testing_log_test_page_attachments(array &$attachments) {
   // Unconditionally attach an asset to the page.
-  $attachments['#attached']['library'][] = 'js_deprecation_log_test/deprecation_log';
+  $attachments['#attached']['library'][] = 'js_testing_log_test/deprecation_log';
 }
 
 /**
  * Implements hook_js_settings_alter().
  */
-function js_deprecation_log_test_js_settings_alter(&$settings) {
+function js_testing_log_test_js_settings_alter(&$settings) {
   $settings['suppressDeprecationErrors'] = FALSE;
 }
diff --git a/core/modules/user/tests/src/FunctionalJavascript/PasswordWidgetThemeFunctionTest.php b/core/modules/user/tests/src/FunctionalJavascript/PasswordWidgetThemeFunctionTest.php
index af11642b98143393c88a231bcaba3d36be345121..0794c9e42398799d14f584408e01d1a4b7980b4b 100644
--- a/core/modules/user/tests/src/FunctionalJavascript/PasswordWidgetThemeFunctionTest.php
+++ b/core/modules/user/tests/src/FunctionalJavascript/PasswordWidgetThemeFunctionTest.php
@@ -15,6 +15,13 @@ class PasswordWidgetThemeFunctionTest extends WebDriverTestBase {
    */
   protected $defaultTheme = 'password_theme_function_test';
 
+  /**
+   * {@inheritdoc}
+   *
+   * @todo Remove this class property in https://www.drupal.org/node/3217947.
+   */
+  protected $failOnJavascriptConsoleErrors = FALSE;
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/profiles/nightwatch_testing/nightwatch_testing.info.yml b/core/profiles/nightwatch_testing/nightwatch_testing.info.yml
index 04289408ed9338d09c2d28762b79d06f59d34c08..6e3f05ad741c1ae080df3a99375f692d3e95cb91 100644
--- a/core/profiles/nightwatch_testing/nightwatch_testing.info.yml
+++ b/core/profiles/nightwatch_testing/nightwatch_testing.info.yml
@@ -4,4 +4,4 @@ description: 'Minimal profile for running Nightwatch tests. Includes absolutely
 version: VERSION
 hidden: true
 install:
-  - js_deprecation_log_test
+  - js_testing_log_test
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/JavascriptErrorsSuppressionTest.php b/core/tests/Drupal/FunctionalJavascriptTests/JavascriptErrorsSuppressionTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..ad0bd48217593a6031982a6000d2ed0c9532b0bb
--- /dev/null
+++ b/core/tests/Drupal/FunctionalJavascriptTests/JavascriptErrorsSuppressionTest.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Drupal\FunctionalJavascriptTests;
+
+/**
+ * Tests that Drupal.throwError can be suppressed to allow a test to pass.
+ *
+ * @group javascript
+ */
+class JavascriptErrorsSuppressionTest extends WebDriverTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['js_errors_test'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $failOnJavascriptConsoleErrors = FALSE;
+
+  /**
+   * Tests that JavaScript console errors can be suppressed.
+   */
+  public function testJavascriptErrors(): void {
+    // Visit page that will throw a JavaScript console error.
+    $this->drupalGet('js_errors_test');
+    // Ensure that errors from previous page loads will be
+    // detected.
+    $this->drupalGet('user');
+  }
+
+}
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/JavascriptErrorsTest.php b/core/tests/Drupal/FunctionalJavascriptTests/JavascriptErrorsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..bb020b2918fc603463d0e205639ff33e0d9e44fb
--- /dev/null
+++ b/core/tests/Drupal/FunctionalJavascriptTests/JavascriptErrorsTest.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Drupal\FunctionalJavascriptTests;
+
+/**
+ * Tests that Drupal.throwError will cause a deprecation warning.
+ *
+ * @group javascript
+ * @group legacy
+ */
+class JavascriptErrorsTest extends WebDriverTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'stark';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['js_errors_test'];
+
+  /**
+   * Tests that JavaScript console errors will result in a deprecation warning.
+   */
+  public function testJavascriptErrors(): void {
+    $this->expectDeprecation('Not failing JavaScript test for JavaScript errors is deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. This test had the following JavaScript errors: Error: A manually thrown error.');
+    // Visit page that will throw a JavaScript console error.
+    $this->drupalGet('js_errors_test');
+    // Ensure that errors from previous page loads will be
+    // detected.
+    $this->drupalGet('user');
+  }
+
+}
diff --git a/core/tests/Drupal/FunctionalJavascriptTests/WebDriverTestBase.php b/core/tests/Drupal/FunctionalJavascriptTests/WebDriverTestBase.php
index 516062a80409fd96995f81214b018c9ad8ee6525..20f04782735134cb24e1edea95f309af6f159184 100644
--- a/core/tests/Drupal/FunctionalJavascriptTests/WebDriverTestBase.php
+++ b/core/tests/Drupal/FunctionalJavascriptTests/WebDriverTestBase.php
@@ -16,6 +16,13 @@
  */
 abstract class WebDriverTestBase extends BrowserTestBase {
 
+  /**
+   * Determines if a test should fail on JavaScript console errors.
+   *
+   * @var bool
+   */
+  protected $failOnJavascriptConsoleErrors = TRUE;
+
   /**
    * Disables CSS animations in tests for more reliable testing.
    *
@@ -61,7 +68,7 @@ protected function initMink() {
    */
   protected function installModulesFromClassProperty(ContainerInterface $container) {
     self::$modules = [
-      'js_deprecation_log_test',
+      'js_testing_log_test',
       'jquery_keyevent_polyfill_test',
     ];
     if ($this->disableCssAnimations) {
@@ -102,12 +109,20 @@ protected function tearDown() {
         throw new \RuntimeException('Unfinished AJAX requests while tearing down a test');
       }
 
-      $warnings = $this->getSession()->evaluateScript("JSON.parse(sessionStorage.getItem('js_deprecation_log_test.warnings') || JSON.stringify([]))");
+      $warnings = $this->getSession()->evaluateScript("JSON.parse(sessionStorage.getItem('js_testing_log_test.warnings') || JSON.stringify([]))");
       foreach ($warnings as $warning) {
         if (strpos($warning, '[Deprecation]') === 0) {
           @trigger_error('Javascript Deprecation:' . substr($warning, 13), E_USER_DEPRECATED);
         }
       }
+      if ($this->failOnJavascriptConsoleErrors) {
+        $errors = $this->getSession()->evaluateScript("JSON.parse(sessionStorage.getItem('js_testing_log_test.errors') || JSON.stringify([]))");
+        if (!empty($errors)) {
+          $all_errors = implode("\n", $errors);
+          @trigger_error("Not failing JavaScript test for JavaScript errors is deprecated in drupal:9.3.0 and is removed from drupal:10.0.0. This test had the following JavaScript errors: $all_errors. See https://www.drupal.org/node/3221100", E_USER_DEPRECATED);
+        }
+      }
+
     }
     parent::tearDown();
   }
diff --git a/core/tests/Drupal/Nightwatch/Assertions/deprecationErrorExists.js b/core/tests/Drupal/Nightwatch/Assertions/deprecationErrorExists.js
index 999b8083e79e2949bd27763ec6f425653ded5854..0b8b9f64f56c85b0ee50615a16eb97ae7e0e1374 100644
--- a/core/tests/Drupal/Nightwatch/Assertions/deprecationErrorExists.js
+++ b/core/tests/Drupal/Nightwatch/Assertions/deprecationErrorExists.js
@@ -18,6 +18,6 @@ module.exports.assertion = function (expected) {
   this.command = (callback) =>
     // eslint-disable-next-line prefer-arrow-callback
     this.api.execute(function () {
-      return window.sessionStorage.getItem('js_deprecation_log_test.warnings');
+      return window.sessionStorage.getItem('js_testing_log_test.warnings');
     }, callback);
 };
diff --git a/core/tests/Drupal/Nightwatch/Assertions/noDeprecationErrors.js b/core/tests/Drupal/Nightwatch/Assertions/noDeprecationErrors.js
index 2dec7bf464b9d16d6cc328da6649fe759e6c1d62..8d5ab79b9e8a9c8ad9ca48c45827203749503e05 100644
--- a/core/tests/Drupal/Nightwatch/Assertions/noDeprecationErrors.js
+++ b/core/tests/Drupal/Nightwatch/Assertions/noDeprecationErrors.js
@@ -18,6 +18,6 @@ module.exports.assertion = function () {
   this.command = (callback) =>
     // eslint-disable-next-line prefer-arrow-callback
     this.api.execute(function () {
-      return window.sessionStorage.getItem('js_deprecation_log_test.warnings');
+      return window.sessionStorage.getItem('js_testing_log_test.warnings');
     }, callback);
 };