From e4284d2d91a1188a8ed8f59112e65e375f50e68f Mon Sep 17 00:00:00 2001 From: effulgentsia <alex.bronstein@acquia.com> Date: Wed, 30 Jun 2021 14:26:18 -0700 Subject: [PATCH] Issue #3091870 by tedbow, phenaproxima, alexpott, bnjmnm, tim.plunkett, lauriii, mradcliffe: Fail Functional Javascript tests that throw Javascript errors --- .../MediaEmbedFilterConfigurationUiTest.php | 7 ++++ .../js_errors_test/js/js_errors_test.es6.js | 11 ++++++ .../js_errors_test/js/js_errors_test.js | 16 ++++++++ .../js_errors_test/js_errors_test.info.yml | 5 +++ .../js_errors_test.libraries.yml | 6 +++ .../js_errors_test/js_errors_test.routing.yml | 7 ++++ .../src/Controller/JsErrorsTestController.php | 22 +++++++++++ .../js/js_testing_log.es6.js | 35 +++++++++++++++++ .../js_testing_log_test/js/js_testing_log.js | 28 ++++++++++++++ .../js_testing_log_test.info.yml} | 0 .../js_testing_log_test.libraries.yml} | 2 +- .../js_testing_log_test.module} | 6 +-- .../PasswordWidgetThemeFunctionTest.php | 7 ++++ .../nightwatch_testing.info.yml | 2 +- .../JavascriptErrorsSuppressionTest.php | 38 +++++++++++++++++++ .../JavascriptErrorsTest.php | 35 +++++++++++++++++ .../WebDriverTestBase.php | 19 +++++++++- .../Assertions/deprecationErrorExists.js | 2 +- .../Assertions/noDeprecationErrors.js | 2 +- 19 files changed, 241 insertions(+), 9 deletions(-) create mode 100644 core/modules/system/tests/modules/js_errors_test/js/js_errors_test.es6.js create mode 100644 core/modules/system/tests/modules/js_errors_test/js/js_errors_test.js create mode 100644 core/modules/system/tests/modules/js_errors_test/js_errors_test.info.yml create mode 100644 core/modules/system/tests/modules/js_errors_test/js_errors_test.libraries.yml create mode 100644 core/modules/system/tests/modules/js_errors_test/js_errors_test.routing.yml create mode 100644 core/modules/system/tests/modules/js_errors_test/src/Controller/JsErrorsTestController.php create mode 100644 core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.es6.js create mode 100644 core/modules/system/tests/modules/js_testing_log_test/js/js_testing_log.js rename core/modules/system/tests/modules/{js_deprecation_log_test/js_deprecation_log_test.info.yml => js_testing_log_test/js_testing_log_test.info.yml} (100%) rename core/modules/system/tests/modules/{js_deprecation_log_test/js_deprecation_log_test.libraries.yml => js_testing_log_test/js_testing_log_test.libraries.yml} (61%) rename core/modules/system/tests/modules/{js_deprecation_log_test/js_deprecation_log_test.module => js_testing_log_test/js_testing_log_test.module} (55%) create mode 100644 core/tests/Drupal/FunctionalJavascriptTests/JavascriptErrorsSuppressionTest.php create mode 100644 core/tests/Drupal/FunctionalJavascriptTests/JavascriptErrorsTest.php diff --git a/core/modules/media/tests/src/FunctionalJavascript/MediaEmbedFilterConfigurationUiTest.php b/core/modules/media/tests/src/FunctionalJavascript/MediaEmbedFilterConfigurationUiTest.php index efae01fc10e4..13513802d783 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 000000000000..421d036ee850 --- /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 000000000000..a3357d06f801 --- /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 000000000000..64c9225341eb --- /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 000000000000..3454e7cb6344 --- /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 000000000000..d096284e2529 --- /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 000000000000..99628a272c57 --- /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 000000000000..dd6fe578ed36 --- /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 000000000000..2a5348723b0d --- /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 1744815c9861..d02c19893cee 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 a86a2f21fbd2..d140ecfdaff7 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 af11642b9814..0794c9e42398 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 04289408ed93..6e3f05ad741c 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 000000000000..ad0bd4821759 --- /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 000000000000..bb020b2918fc --- /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 516062a80409..20f047827351 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 999b8083e79e..0b8b9f64f56c 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 2dec7bf464b9..8d5ab79b9e8a 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); }; -- GitLab