AjaxTest.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <?php
  2. namespace Drupal\FunctionalJavascriptTests\Ajax;
  3. use Drupal\FunctionalJavascriptTests\WebDriverTestBase;
  4. /**
  5. * Tests AJAX responses.
  6. *
  7. * @group Ajax
  8. */
  9. class AjaxTest extends WebDriverTestBase {
  10. /**
  11. * {@inheritdoc}
  12. */
  13. public static $modules = ['ajax_test'];
  14. public function testAjaxWithAdminRoute() {
  15. \Drupal::service('theme_installer')->install(['stable', 'seven']);
  16. $theme_config = \Drupal::configFactory()->getEditable('system.theme');
  17. $theme_config->set('admin', 'seven');
  18. $theme_config->set('default', 'stable');
  19. $theme_config->save();
  20. $account = $this->drupalCreateUser(['view the administration theme']);
  21. $this->drupalLogin($account);
  22. // First visit the site directly via the URL. This should render it in the
  23. // admin theme.
  24. $this->drupalGet('admin/ajax-test/theme');
  25. $assert = $this->assertSession();
  26. $assert->pageTextContains('Current theme: seven');
  27. // Now click the modal, which should also use the admin theme.
  28. $this->drupalGet('ajax-test/dialog');
  29. $assert->pageTextNotContains('Current theme: stable');
  30. $this->clickLink('Link 8 (ajax)');
  31. $assert->assertWaitOnAjaxRequest();
  32. $assert->pageTextContains('Current theme: stable');
  33. $assert->pageTextNotContains('Current theme: seven');
  34. }
  35. /**
  36. * Test that AJAX loaded libraries are not retained between requests.
  37. *
  38. * @see https://www.drupal.org/node/2647916
  39. */
  40. public function testDrupalSettingsCachingRegression() {
  41. $this->drupalGet('ajax-test/dialog');
  42. $assert = $this->assertSession();
  43. $session = $this->getSession();
  44. // Insert a fake library into the already loaded library settings.
  45. $fake_library = 'fakeLibrary/fakeLibrary';
  46. $session->evaluateScript("drupalSettings.ajaxPageState.libraries = drupalSettings.ajaxPageState.libraries + ',$fake_library';");
  47. $libraries = $session->evaluateScript('drupalSettings.ajaxPageState.libraries');
  48. // Test that the fake library is set.
  49. $this->assertContains($fake_library, $libraries);
  50. // Click on the AJAX link.
  51. $this->clickLink('Link 8 (ajax)');
  52. $assert->assertWaitOnAjaxRequest();
  53. // Test that the fake library is still set after the AJAX call.
  54. $libraries = $session->evaluateScript('drupalSettings.ajaxPageState.libraries');
  55. $this->assertContains($fake_library, $libraries);
  56. // Reload the page, this should reset the loaded libraries and remove the
  57. // fake library.
  58. $this->drupalGet('ajax-test/dialog');
  59. $libraries = $session->evaluateScript('drupalSettings.ajaxPageState.libraries');
  60. $this->assertNotContains($fake_library, $libraries);
  61. // Click on the AJAX link again, and the libraries should still not contain
  62. // the fake library.
  63. $this->clickLink('Link 8 (ajax)');
  64. $assert->assertWaitOnAjaxRequest();
  65. $libraries = $session->evaluateScript('drupalSettings.ajaxPageState.libraries');
  66. $this->assertNotContains($fake_library, $libraries);
  67. }
  68. /**
  69. * Tests that various AJAX responses with DOM elements are correctly inserted.
  70. *
  71. * After inserting DOM elements, Drupal JavaScript behaviors should be
  72. * reattached and all top-level elements of type Node.ELEMENT_NODE need to be
  73. * part of the context.
  74. */
  75. public function testInsertAjaxResponse() {
  76. $render_single_root = [
  77. 'pre-wrapped-div' => '<div class="pre-wrapped">pre-wrapped<script> var test;</script></div>',
  78. 'pre-wrapped-span' => '<span class="pre-wrapped">pre-wrapped<script> var test;</script></span>',
  79. 'pre-wrapped-whitespace' => ' <div class="pre-wrapped-whitespace">pre-wrapped-whitespace</div>' . "\n",
  80. 'not-wrapped' => 'not-wrapped',
  81. 'comment-string-not-wrapped' => '<!-- COMMENT -->comment-string-not-wrapped',
  82. 'comment-not-wrapped' => '<!-- COMMENT --><div class="comment-not-wrapped">comment-not-wrapped</div>',
  83. 'svg' => '<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"><rect x="0" y="0" height="10" width="10" fill="green"/></svg>',
  84. 'empty' => '',
  85. ];
  86. $render_multiple_root_unwrapper = [
  87. 'mixed' => ' foo <!-- COMMENT --> foo bar<div class="a class"><p>some string</p></div> additional not wrapped strings, <!-- ANOTHER COMMENT --> <p>final string</p>',
  88. 'top-level-only' => '<div>element #1</div><div>element #2</div>',
  89. 'top-level-only-pre-whitespace' => ' <div>element #1</div><div>element #2</div> ',
  90. 'top-level-only-middle-whitespace-span' => '<span>element #1</span> <span>element #2</span>',
  91. 'top-level-only-middle-whitespace-div' => '<div>element #1</div> <div>element #2</div>',
  92. ];
  93. // This is temporary behavior for BC reason.
  94. $render_multiple_root_wrapper = [];
  95. foreach ($render_multiple_root_unwrapper as $key => $render) {
  96. $render_multiple_root_wrapper["$key--effect"] = '<div>' . $render . '</div>';
  97. }
  98. $expected_renders = array_merge(
  99. $render_single_root,
  100. $render_multiple_root_wrapper,
  101. $render_multiple_root_unwrapper
  102. );
  103. // Checking default process of wrapping Ajax content.
  104. foreach ($expected_renders as $render_type => $expected) {
  105. $this->assertInsert($render_type, $expected);
  106. }
  107. // Checking custom ajaxWrapperMultipleRootElements wrapping.
  108. $custom_wrapper_multiple_root = <<<JS
  109. (function($, Drupal){
  110. Drupal.theme.ajaxWrapperMultipleRootElements = function (elements) {
  111. return $('<div class="my-favorite-div"></div>').append(elements);
  112. };
  113. }(jQuery, Drupal));
  114. JS;
  115. $expected = '<div class="my-favorite-div"><span>element #1</span> <span>element #2</span></div>';
  116. $this->assertInsert('top-level-only-middle-whitespace-span--effect', $expected, $custom_wrapper_multiple_root);
  117. // Checking custom ajaxWrapperNewContent wrapping.
  118. $custom_wrapper_new_content = <<<JS
  119. (function($, Drupal){
  120. Drupal.theme.ajaxWrapperNewContent = function (elements) {
  121. return $('<div class="div-wrapper-forever"></div>').append(elements);
  122. };
  123. }(jQuery, Drupal));
  124. JS;
  125. $expected = '<div class="div-wrapper-forever"></div>';
  126. $this->assertInsert('empty', $expected, $custom_wrapper_new_content);
  127. }
  128. /**
  129. * Assert insert.
  130. *
  131. * @param string $render_type
  132. * Render type.
  133. * @param string $expected
  134. * Expected result.
  135. * @param string $script
  136. * Script for additional theming.
  137. */
  138. public function assertInsert($render_type, $expected, $script = '') {
  139. // Check insert to block element.
  140. $this->drupalGet('ajax-test/insert-block-wrapper');
  141. $this->getSession()->executeScript($script);
  142. $this->clickLink("Link html $render_type");
  143. $this->assertWaitPageContains('<div class="ajax-target-wrapper"><div id="ajax-target">' . $expected . '</div></div>');
  144. $this->drupalGet('ajax-test/insert-block-wrapper');
  145. $this->getSession()->executeScript($script);
  146. $this->clickLink("Link replaceWith $render_type");
  147. $this->assertWaitPageContains('<div class="ajax-target-wrapper">' . $expected . '</div>');
  148. // Check insert to inline element.
  149. $this->drupalGet('ajax-test/insert-inline-wrapper');
  150. $this->getSession()->executeScript($script);
  151. $this->clickLink("Link html $render_type");
  152. $this->assertWaitPageContains('<div class="ajax-target-wrapper"><span id="ajax-target-inline">' . $expected . '</span></div>');
  153. $this->drupalGet('ajax-test/insert-inline-wrapper');
  154. $this->getSession()->executeScript($script);
  155. $this->clickLink("Link replaceWith $render_type");
  156. $this->assertWaitPageContains('<div class="ajax-target-wrapper">' . $expected . '</div>');
  157. }
  158. /**
  159. * Asserts that page contains an expected value after waiting.
  160. *
  161. * @param string $expected
  162. * A needle text.
  163. */
  164. protected function assertWaitPageContains($expected) {
  165. $page = $this->getSession()->getPage();
  166. $this->assertTrue($page->waitFor(10, function () use ($page, $expected) {
  167. // Clear content from empty styles and "processed" classes after effect.
  168. $content = str_replace([' class="processed"', ' processed', ' style=""'], '', $page->getContent());
  169. return stripos($content, $expected) !== FALSE;
  170. }), "Page contains expected value: $expected");
  171. }
  172. }