RenderElementTypesTest.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. <?php
  2. namespace Drupal\KernelTests\Core\Render\Element;
  3. use Drupal\Component\Utility\Html;
  4. use Drupal\Core\Url;
  5. use Drupal\KernelTests\KernelTestBase;
  6. /**
  7. * Tests the markup of core render element types passed to drupal_render().
  8. *
  9. * @group Common
  10. */
  11. class RenderElementTypesTest extends KernelTestBase {
  12. /**
  13. * Modules to enable.
  14. *
  15. * @var array
  16. */
  17. public static $modules = ['system', 'router_test'];
  18. protected function setUp() {
  19. parent::setUp();
  20. $this->installConfig(['system']);
  21. \Drupal::service('router.builder')->rebuild();
  22. }
  23. /**
  24. * Asserts that an array of elements is rendered properly.
  25. *
  26. * @param array $elements
  27. * The render element array to test.
  28. * @param string $expected_html
  29. * The expected markup.
  30. * @param string $message
  31. * Assertion message.
  32. */
  33. protected function assertElements(array $elements, $expected_html, $message) {
  34. $actual_html = (string) \Drupal::service('renderer')->renderRoot($elements);
  35. $out = '<table><tr>';
  36. $out .= '<td valign="top"><pre>' . Html::escape($expected_html) . '</pre></td>';
  37. $out .= '<td valign="top"><pre>' . Html::escape($actual_html) . '</pre></td>';
  38. $out .= '</tr></table>';
  39. $this->verbose($out);
  40. $this->assertIdentical($actual_html, $expected_html, Html::escape($message));
  41. }
  42. /**
  43. * Tests system #type 'container'.
  44. */
  45. public function testContainer() {
  46. // Basic container with no attributes.
  47. $this->assertElements([
  48. '#type' => 'container',
  49. '#markup' => 'foo',
  50. ], "<div>foo</div>\n", "#type 'container' with no HTML attributes");
  51. // Container with a class.
  52. $this->assertElements([
  53. '#type' => 'container',
  54. '#markup' => 'foo',
  55. '#attributes' => [
  56. 'class' => ['bar'],
  57. ],
  58. ], '<div class="bar">foo</div>' . "\n", "#type 'container' with a class HTML attribute");
  59. // Container with children.
  60. $this->assertElements([
  61. '#type' => 'container',
  62. 'child' => [
  63. '#markup' => 'foo',
  64. ],
  65. ], "<div>foo</div>\n", "#type 'container' with child elements");
  66. }
  67. /**
  68. * Tests system #type 'html_tag'.
  69. */
  70. public function testHtmlTag() {
  71. // Test void element.
  72. $this->assertElements([
  73. '#type' => 'html_tag',
  74. '#tag' => 'meta',
  75. '#value' => 'ignored',
  76. '#attributes' => [
  77. 'name' => 'description',
  78. 'content' => 'Drupal test',
  79. ],
  80. ], '<meta name="description" content="Drupal test" />' . "\n", "#type 'html_tag', void element renders properly");
  81. // Test non-void element.
  82. $this->assertElements([
  83. '#type' => 'html_tag',
  84. '#tag' => 'section',
  85. '#value' => 'value',
  86. '#attributes' => [
  87. 'class' => ['unicorns'],
  88. ],
  89. ], '<section class="unicorns">value</section>' . "\n", "#type 'html_tag', non-void element renders properly");
  90. // Test empty void element tag.
  91. $this->assertElements([
  92. '#type' => 'html_tag',
  93. '#tag' => 'link',
  94. ], "<link />\n", "#type 'html_tag' empty void element renders properly");
  95. // Test empty non-void element tag.
  96. $this->assertElements([
  97. '#type' => 'html_tag',
  98. '#tag' => 'section',
  99. ], "<section></section>\n", "#type 'html_tag' empty non-void element renders properly");
  100. }
  101. /**
  102. * Tests system #type 'more_link'.
  103. */
  104. public function testMoreLink() {
  105. $elements = [
  106. [
  107. 'name' => "#type 'more_link' anchor tag generation without extra classes",
  108. 'value' => [
  109. '#type' => 'more_link',
  110. '#url' => Url::fromUri('https://www.drupal.org'),
  111. ],
  112. 'expected' => '//div[@class="more-link"]/a[@href="https://www.drupal.org" and text()="More"]',
  113. ],
  114. [
  115. 'name' => "#type 'more_link' anchor tag generation with different link text",
  116. 'value' => [
  117. '#type' => 'more_link',
  118. '#url' => Url::fromUri('https://www.drupal.org'),
  119. '#title' => 'More Titles',
  120. ],
  121. 'expected' => '//div[@class="more-link"]/a[@href="https://www.drupal.org" and text()="More Titles"]',
  122. ],
  123. [
  124. 'name' => "#type 'more_link' anchor tag generation with attributes on wrapper",
  125. 'value' => [
  126. '#type' => 'more_link',
  127. '#url' => Url::fromUri('https://www.drupal.org'),
  128. '#theme_wrappers' => [
  129. 'container' => [
  130. '#attributes' => [
  131. 'title' => 'description',
  132. 'class' => ['more-link', 'drupal', 'test'],
  133. ],
  134. ],
  135. ],
  136. ],
  137. 'expected' => '//div[@title="description" and contains(@class, "more-link") and contains(@class, "drupal") and contains(@class, "test")]/a[@href="https://www.drupal.org" and text()="More"]',
  138. ],
  139. [
  140. 'name' => "#type 'more_link' anchor tag with a relative path",
  141. 'value' => [
  142. '#type' => 'more_link',
  143. '#url' => Url::fromRoute('router_test.1'),
  144. ],
  145. 'expected' => '//div[@class="more-link"]/a[@href="' . Url::fromRoute('router_test.1')->toString() . '" and text()="More"]',
  146. ],
  147. [
  148. 'name' => "#type 'more_link' anchor tag with a route",
  149. 'value' => [
  150. '#type' => 'more_link',
  151. '#url' => Url::fromRoute('router_test.1'),
  152. ],
  153. 'expected' => '//div[@class="more-link"]/a[@href="' . \Drupal::urlGenerator()->generate('router_test.1') . '" and text()="More"]',
  154. ],
  155. [
  156. 'name' => "#type 'more_link' anchor tag with an absolute path",
  157. 'value' => [
  158. '#type' => 'more_link',
  159. '#url' => Url::fromRoute('system.admin_content'),
  160. '#options' => ['absolute' => TRUE],
  161. ],
  162. 'expected' => '//div[@class="more-link"]/a[@href="' . Url::fromRoute('system.admin_content')->setAbsolute()->toString() . '" and text()="More"]',
  163. ],
  164. [
  165. 'name' => "#type 'more_link' anchor tag to the front page",
  166. 'value' => [
  167. '#type' => 'more_link',
  168. '#url' => Url::fromRoute('<front>'),
  169. ],
  170. 'expected' => '//div[@class="more-link"]/a[@href="' . Url::fromRoute('<front>')->toString() . '" and text()="More"]',
  171. ],
  172. ];
  173. foreach ($elements as $element) {
  174. $xml = new \SimpleXMLElement(\Drupal::service('renderer')->renderRoot($element['value']));
  175. $result = $xml->xpath($element['expected']);
  176. $this->assertTrue($result, '"' . $element['name'] . '" input rendered correctly by drupal_render().');
  177. }
  178. }
  179. /**
  180. * Tests system #type 'system_compact_link'.
  181. */
  182. public function testSystemCompactLink() {
  183. $elements = [
  184. [
  185. 'name' => "#type 'system_compact_link' when admin compact mode is off",
  186. 'value' => [
  187. '#type' => 'system_compact_link',
  188. ],
  189. 'expected' => '//div[@class="compact-link"]/a[contains(@href, "admin/compact/on?") and text()="Hide descriptions"]',
  190. ],
  191. [
  192. 'name' => "#type 'system_compact_link' when adding extra attributes",
  193. 'value' => [
  194. '#type' => 'system_compact_link',
  195. '#attributes' => [
  196. 'class' => ['kittens-rule'],
  197. ],
  198. ],
  199. 'expected' => '//div[@class="compact-link"]/a[contains(@href, "admin/compact/on?") and @class="kittens-rule" and text()="Hide descriptions"]',
  200. ],
  201. ];
  202. foreach ($elements as $element) {
  203. $xml = new \SimpleXMLElement(\Drupal::service('renderer')->renderRoot($element['value']));
  204. $result = $xml->xpath($element['expected']);
  205. $this->assertTrue($result, '"' . $element['name'] . '" is rendered correctly by drupal_render().');
  206. }
  207. // Set admin compact mode on for additional tests.
  208. \Drupal::request()->cookies->set('Drupal_visitor_admin_compact_mode', TRUE);
  209. $element = [
  210. 'name' => "#type 'system_compact_link' when admin compact mode is on",
  211. 'value' => [
  212. '#type' => 'system_compact_link',
  213. ],
  214. 'expected' => '//div[@class="compact-link"]/a[contains(@href, "admin/compact?") and text()="Show descriptions"]',
  215. ];
  216. $xml = new \SimpleXMLElement(\Drupal::service('renderer')->renderRoot($element['value']));
  217. $result = $xml->xpath($element['expected']);
  218. $this->assertTrue($result, '"' . $element['name'] . '" is rendered correctly by drupal_render().');
  219. }
  220. }