TableTest.php 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. <?php
  2. namespace Drupal\KernelTests\Core\Render\Element;
  3. use Drupal\KernelTests\KernelTestBase;
  4. /**
  5. * Tests built-in table theme functions.
  6. *
  7. * @group Theme
  8. */
  9. class TableTest extends KernelTestBase {
  10. /**
  11. * Modules to enable.
  12. *
  13. * @var array
  14. */
  15. public static $modules = ['system', 'form_test'];
  16. /**
  17. * Tableheader.js provides 'sticky' table headers, and is included by default.
  18. */
  19. public function testThemeTableStickyHeaders() {
  20. $header = ['one', 'two', 'three'];
  21. $rows = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
  22. $table = [
  23. '#type' => 'table',
  24. '#header' => $header,
  25. '#rows' => $rows,
  26. '#sticky' => TRUE,
  27. ];
  28. $this->render($table);
  29. // Make sure tableheader.js was attached.
  30. $tableheader = $this->xpath("//script[contains(@src, 'tableheader.js')]");
  31. $this->assertEqual(count($tableheader), 1);
  32. $this->assertRaw('sticky-enabled');
  33. }
  34. /**
  35. * If $sticky is FALSE, no tableheader.js should be included.
  36. */
  37. public function testThemeTableNoStickyHeaders() {
  38. $header = ['one', 'two', 'three'];
  39. $rows = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
  40. $attributes = [];
  41. $caption = NULL;
  42. $colgroups = [];
  43. $table = [
  44. '#type' => 'table',
  45. '#header' => $header,
  46. '#rows' => $rows,
  47. '#attributes' => $attributes,
  48. '#caption' => $caption,
  49. '#colgroups' => $colgroups,
  50. '#sticky' => FALSE,
  51. ];
  52. $this->render($table);
  53. // Make sure tableheader.js was not attached.
  54. $tableheader = $this->xpath("//script[contains(@src, 'tableheader.js')]");
  55. $this->assertEqual(count($tableheader), 0);
  56. $this->assertNoRaw('sticky-enabled');
  57. }
  58. /**
  59. * Tests that the table header is printed correctly even if there are no rows,
  60. * and that the empty text is displayed correctly.
  61. */
  62. public function testThemeTableWithEmptyMessage() {
  63. $header = [
  64. 'Header 1',
  65. [
  66. 'data' => 'Header 2',
  67. 'colspan' => 2,
  68. ],
  69. ];
  70. $table = [
  71. '#type' => 'table',
  72. '#header' => $header,
  73. '#rows' => [],
  74. '#empty' => 'Empty row.',
  75. ];
  76. // Enable the Classy theme.
  77. \Drupal::service('theme_handler')->install(['classy']);
  78. $this->config('system.theme')->set('default', 'classy')->save();
  79. $this->render($table);
  80. $this->removeWhiteSpace();
  81. $this->assertRaw('<thead><tr><th>Header 1</th><th colspan="2">Header 2</th></tr>', 'Table header found.');
  82. $this->assertRaw('<tr class="odd"><td colspan="3" class="empty message">Empty row.</td>', 'Colspan on #empty row found.');
  83. }
  84. /**
  85. * Tests that the 'no_striping' option works correctly.
  86. */
  87. public function testThemeTableWithNoStriping() {
  88. $rows = [
  89. [
  90. 'data' => [1],
  91. 'no_striping' => TRUE,
  92. ],
  93. ];
  94. $table = [
  95. '#type' => 'table',
  96. '#rows' => $rows,
  97. ];
  98. $this->render($table);
  99. $this->assertNoRaw('class="odd"', 'Odd/even classes were not added because $no_striping = TRUE.');
  100. $this->assertNoRaw('no_striping', 'No invalid no_striping HTML attribute was printed.');
  101. }
  102. /**
  103. * Test that the 'footer' option works correctly.
  104. */
  105. public function testThemeTableFooter() {
  106. $footer = [
  107. [
  108. 'data' => [1],
  109. ],
  110. ['Foo'],
  111. ];
  112. $table = [
  113. '#type' => 'table',
  114. '#rows' => [],
  115. '#footer' => $footer,
  116. ];
  117. $this->render($table);
  118. $this->removeWhiteSpace();
  119. $this->assertRaw('<tfoot><tr><td>1</td></tr><tr><td>Foo</td></tr></tfoot>', 'Table footer found.');
  120. }
  121. /**
  122. * Tests that the 'header' option in cells works correctly.
  123. */
  124. public function testThemeTableHeaderCellOption() {
  125. $rows = [
  126. [
  127. ['data' => 1, 'header' => TRUE],
  128. ['data' => 1, 'header' => FALSE],
  129. ['data' => 1],
  130. ],
  131. ];
  132. $table = [
  133. '#type' => 'table',
  134. '#rows' => $rows,
  135. ];
  136. $this->render($table);
  137. $this->removeWhiteSpace();
  138. $this->assertRaw('<th>1</th><td>1</td><td>1</td>', 'The th and td tags was printed correctly.');
  139. }
  140. /**
  141. * Tests that the 'responsive-table' class is applied correctly.
  142. */
  143. public function testThemeTableResponsive() {
  144. $header = ['one', 'two', 'three'];
  145. $rows = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
  146. $table = [
  147. '#type' => 'table',
  148. '#header' => $header,
  149. '#rows' => $rows,
  150. '#responsive' => TRUE,
  151. ];
  152. $this->render($table);
  153. $this->assertRaw('responsive-enabled', 'The responsive-enabled class was printed correctly.');
  154. }
  155. /**
  156. * Tests that the 'responsive-table' class is not applied without headers.
  157. */
  158. public function testThemeTableNotResponsiveHeaders() {
  159. $rows = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
  160. $table = [
  161. '#type' => 'table',
  162. '#rows' => $rows,
  163. '#responsive' => TRUE,
  164. ];
  165. $this->render($table);
  166. $this->assertNoRaw('responsive-enabled', 'The responsive-enabled class is not applied without table headers.');
  167. }
  168. /**
  169. * Tests that 'responsive-table' class only applied when responsive is TRUE.
  170. */
  171. public function testThemeTableNotResponsiveProperty() {
  172. $header = ['one', 'two', 'three'];
  173. $rows = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
  174. $table = [
  175. '#type' => 'table',
  176. '#header' => $header,
  177. '#rows' => $rows,
  178. '#responsive' => FALSE,
  179. ];
  180. $this->render($table);
  181. $this->assertNoRaw('responsive-enabled', 'The responsive-enabled class is not applied without the "responsive" property set to TRUE.');
  182. }
  183. /**
  184. * Tests 'priority-medium' and 'priority-low' classes.
  185. */
  186. public function testThemeTableResponsivePriority() {
  187. $header = [
  188. // Test associative header indices.
  189. 'associative_key' => ['data' => 1, 'class' => [RESPONSIVE_PRIORITY_MEDIUM]],
  190. // Test non-associative header indices.
  191. ['data' => 2, 'class' => [RESPONSIVE_PRIORITY_LOW]],
  192. // Test no responsive priorities.
  193. ['data' => 3],
  194. ];
  195. $rows = [[4, 5, 6]];
  196. $table = [
  197. '#type' => 'table',
  198. '#header' => $header,
  199. '#rows' => $rows,
  200. '#responsive' => TRUE,
  201. ];
  202. $this->render($table);
  203. $this->assertRaw('<th class="priority-medium">1</th>', 'Header 1: the priority-medium class was applied correctly.');
  204. $this->assertRaw('<th class="priority-low">2</th>', 'Header 2: the priority-low class was applied correctly.');
  205. $this->assertRaw('<th>3</th>', 'Header 3: no priority classes were applied.');
  206. $this->assertRaw('<td class="priority-medium">4</td>', 'Cell 1: the priority-medium class was applied correctly.');
  207. $this->assertRaw('<td class="priority-low">5</td>', 'Cell 2: the priority-low class was applied correctly.');
  208. $this->assertRaw('<td>6</td>', 'Cell 3: no priority classes were applied.');
  209. }
  210. /**
  211. * Tests header elements with a mix of string and render array values.
  212. */
  213. public function testThemeTableHeaderRenderArray() {
  214. $header = [
  215. [
  216. 'data' => [
  217. '#markup' => 'one',
  218. ],
  219. ],
  220. 'two',
  221. [
  222. 'data' => [
  223. '#type' => 'html_tag',
  224. '#tag' => 'b',
  225. '#value' => 'three',
  226. ],
  227. ],
  228. ];
  229. $rows = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
  230. $table = [
  231. '#type' => 'table',
  232. '#header' => $header,
  233. '#rows' => $rows,
  234. '#responsive' => FALSE,
  235. ];
  236. $this->render($table);
  237. $this->removeWhiteSpace();
  238. $this->assertRaw('<thead><tr><th>one</th><th>two</th><th><b>three</b></th></tr>', 'Table header found.');
  239. }
  240. /**
  241. * Tests row elements with a mix of string and render array values.
  242. */
  243. public function testThemeTableRowRenderArray() {
  244. $header = ['one', 'two', 'three'];
  245. $rows = [
  246. [
  247. '1-one',
  248. [
  249. 'data' => '1-two'
  250. ],
  251. '1-three',
  252. ],
  253. [
  254. [
  255. 'data' => [
  256. '#markup' => '2-one',
  257. ],
  258. ],
  259. '2-two',
  260. [
  261. 'data' => [
  262. '#type' => 'html_tag',
  263. '#tag' => 'b',
  264. '#value' => '2-three',
  265. ],
  266. ],
  267. ],
  268. ];
  269. $table = [
  270. '#type' => 'table',
  271. '#header' => $header,
  272. '#rows' => $rows,
  273. '#responsive' => FALSE,
  274. ];
  275. $this->render($table);
  276. $this->removeWhiteSpace();
  277. $this->assertRaw('<tbody><tr><td>1-one</td><td>1-two</td><td>1-three</td></tr>', 'Table row 1 found.');
  278. $this->assertRaw('<tr><td>2-one</td><td>2-two</td><td><b>2-three</b></td></tr></tbody>', 'Table row 2 found.');
  279. }
  280. /**
  281. * Tests that the select/checkbox label is being generated and escaped.
  282. */
  283. public function testThemeTableTitle() {
  284. $form = \Drupal::formBuilder()->getForm('\Drupal\form_test\Form\FormTestTableForm');
  285. $this->render($form);
  286. $this->assertEscaped('Update <em>kitten</em>');
  287. $this->assertRaw('Update my favourite fruit is <strong>bananas</strong>');
  288. }
  289. }