Loading core/core.libraries.yml +1 −0 Original line number Diff line number Diff line Loading @@ -374,6 +374,7 @@ drupal.ajax: - core/once - core/tabbable - core/loadjs - core/drupal.message drupal.announce: version: VERSION Loading core/misc/ajax.js +12 −0 Original line number Diff line number Diff line Loading @@ -179,6 +179,18 @@ * @type {string} */ this.name = 'AjaxError'; if (!Drupal.AjaxError.messages) { Drupal.AjaxError.messages = new Drupal.Message(); } Drupal.AjaxError.messages.add( Drupal.t( "Oops, something went wrong. Check your browser's developer console for more details.", ), { type: 'error', }, ); }; Drupal.AjaxError.prototype = new Error(); Loading core/modules/system/tests/modules/ajax_test/ajax_test.routing.yml +14 −0 Original line number Diff line number Diff line Loading @@ -115,3 +115,17 @@ ajax_test.global_events_clear_log: _controller: '\Drupal\ajax_test\Controller\AjaxTestController::globalEventsClearLog' requirements: _access: 'TRUE' ajax_test.exception_link: path: '/ajax-test/exception-link' defaults: _controller: '\Drupal\ajax_test\Controller\AjaxTestController::exceptionLink' requirements: _access: 'TRUE' ajax_test.throw_exception: path: '/ajax-test/throw-exception' defaults: _controller: '\Drupal\ajax_test\Controller\AjaxTestController::throwException' requirements: _access: 'TRUE' core/modules/system/tests/modules/ajax_test/src/Controller/AjaxTestController.php +32 −0 Original line number Diff line number Diff line Loading @@ -387,4 +387,36 @@ public function globalEventsClearLog() { return $response; } /** * Callback to provide an exception via Ajax. * * @throws \Exception * The expected exception. */ public function throwException() { throw new \Exception('This is an exception.'); } /** * Provides an Ajax link for the exception. * * @return array * The Ajax link. */ public function exceptionLink() { return [ '#type' => 'link', '#url' => Url::fromRoute('ajax_test.throw_exception'), '#title' => 'Ajax Exception', '#attributes' => [ 'class' => ['use-ajax'], ], '#attached' => [ 'library' => [ 'core/drupal.ajax', ], ], ]; } } core/tests/Drupal/FunctionalJavascriptTests/Ajax/AjaxTest.php +40 −0 Original line number Diff line number Diff line Loading @@ -251,4 +251,44 @@ protected function assertWaitPageContains(string $expected): void { }), "Page contains expected value: $expected"); } /** * Tests that Ajax errors are visible in the UI. */ public function testUiAjaxException() { $themes = [ 'olivero', 'claro', 'stark', ]; \Drupal::service('theme_installer')->install($themes); foreach ($themes as $theme) { $theme_config = \Drupal::configFactory()->getEditable('system.theme'); $theme_config->set('default', $theme); $theme_config->save(); \Drupal::service('router.builder')->rebuildIfNeeded(); $this->drupalGet('ajax-test/exception-link'); $page = $this->getSession()->getPage(); // We don't want the test to error out because of an expected Javascript // console error. $this->failOnJavascriptConsoleErrors = FALSE; // Click on the AJAX link. $this->clickLink('Ajax Exception'); $this->assertSession() ->statusMessageContainsAfterWait("Oops, something went wrong. Check your browser's developer console for more details.", 'error'); if ($theme === 'olivero') { // Check that the message can be closed. $this->click('.messages__close'); $this->assertTrue($page->find('css', '.messages--error') ->hasClass('hidden')); } } // This is needed to avoid an unfinished AJAX request error from tearDown() // because this test intentionally does not complete all AJAX requests. $this->getSession()->executeScript("delete window.jQuery"); } } Loading
core/core.libraries.yml +1 −0 Original line number Diff line number Diff line Loading @@ -374,6 +374,7 @@ drupal.ajax: - core/once - core/tabbable - core/loadjs - core/drupal.message drupal.announce: version: VERSION Loading
core/misc/ajax.js +12 −0 Original line number Diff line number Diff line Loading @@ -179,6 +179,18 @@ * @type {string} */ this.name = 'AjaxError'; if (!Drupal.AjaxError.messages) { Drupal.AjaxError.messages = new Drupal.Message(); } Drupal.AjaxError.messages.add( Drupal.t( "Oops, something went wrong. Check your browser's developer console for more details.", ), { type: 'error', }, ); }; Drupal.AjaxError.prototype = new Error(); Loading
core/modules/system/tests/modules/ajax_test/ajax_test.routing.yml +14 −0 Original line number Diff line number Diff line Loading @@ -115,3 +115,17 @@ ajax_test.global_events_clear_log: _controller: '\Drupal\ajax_test\Controller\AjaxTestController::globalEventsClearLog' requirements: _access: 'TRUE' ajax_test.exception_link: path: '/ajax-test/exception-link' defaults: _controller: '\Drupal\ajax_test\Controller\AjaxTestController::exceptionLink' requirements: _access: 'TRUE' ajax_test.throw_exception: path: '/ajax-test/throw-exception' defaults: _controller: '\Drupal\ajax_test\Controller\AjaxTestController::throwException' requirements: _access: 'TRUE'
core/modules/system/tests/modules/ajax_test/src/Controller/AjaxTestController.php +32 −0 Original line number Diff line number Diff line Loading @@ -387,4 +387,36 @@ public function globalEventsClearLog() { return $response; } /** * Callback to provide an exception via Ajax. * * @throws \Exception * The expected exception. */ public function throwException() { throw new \Exception('This is an exception.'); } /** * Provides an Ajax link for the exception. * * @return array * The Ajax link. */ public function exceptionLink() { return [ '#type' => 'link', '#url' => Url::fromRoute('ajax_test.throw_exception'), '#title' => 'Ajax Exception', '#attributes' => [ 'class' => ['use-ajax'], ], '#attached' => [ 'library' => [ 'core/drupal.ajax', ], ], ]; } }
core/tests/Drupal/FunctionalJavascriptTests/Ajax/AjaxTest.php +40 −0 Original line number Diff line number Diff line Loading @@ -251,4 +251,44 @@ protected function assertWaitPageContains(string $expected): void { }), "Page contains expected value: $expected"); } /** * Tests that Ajax errors are visible in the UI. */ public function testUiAjaxException() { $themes = [ 'olivero', 'claro', 'stark', ]; \Drupal::service('theme_installer')->install($themes); foreach ($themes as $theme) { $theme_config = \Drupal::configFactory()->getEditable('system.theme'); $theme_config->set('default', $theme); $theme_config->save(); \Drupal::service('router.builder')->rebuildIfNeeded(); $this->drupalGet('ajax-test/exception-link'); $page = $this->getSession()->getPage(); // We don't want the test to error out because of an expected Javascript // console error. $this->failOnJavascriptConsoleErrors = FALSE; // Click on the AJAX link. $this->clickLink('Ajax Exception'); $this->assertSession() ->statusMessageContainsAfterWait("Oops, something went wrong. Check your browser's developer console for more details.", 'error'); if ($theme === 'olivero') { // Check that the message can be closed. $this->click('.messages__close'); $this->assertTrue($page->find('css', '.messages--error') ->hasClass('hidden')); } } // This is needed to avoid an unfinished AJAX request error from tearDown() // because this test intentionally does not complete all AJAX requests. $this->getSession()->executeScript("delete window.jQuery"); } }