See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace core; 18 19 use flexible_table; 20 use testable_flexible_table; 21 22 defined('MOODLE_INTERNAL') || die(); 23 24 global $CFG; 25 require_once($CFG->libdir . '/tablelib.php'); 26 require_once($CFG->libdir . '/tests/fixtures/testable_flexible_table.php'); 27 28 /** 29 * Test some of tablelib. 30 * 31 * @package core 32 * @category test 33 * @copyright 2013 Damyon Wiese <damyon@moodle.com> 34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 35 */ 36 class tablelib_test extends \advanced_testcase { 37 protected function generate_columns($cols) { 38 $columns = array(); 39 foreach (range(0, $cols - 1) as $j) { 40 array_push($columns, 'column' . $j); 41 } 42 return $columns; 43 } 44 45 protected function generate_headers($cols) { 46 $columns = array(); 47 foreach (range(0, $cols - 1) as $j) { 48 array_push($columns, 'Column ' . $j); 49 } 50 return $columns; 51 } 52 53 protected function generate_data($rows, $cols) { 54 $data = array(); 55 56 foreach (range(0, $rows - 1) as $i) { 57 $row = array(); 58 foreach (range(0, $cols - 1) as $j) { 59 $val = 'row ' . $i . ' col ' . $j; 60 $row['column' . $j] = $val; 61 } 62 array_push($data, $row); 63 } 64 return $data; 65 } 66 67 /** 68 * Create a table with properties as passed in params, add data and output html. 69 * 70 * @param string[] $columns The columns of the table. 71 * @param string[] $headers The header of the table. 72 * @param bool $sortable Sorting of the table. 73 * @param bool $collapsible Is table collapsible. 74 * @param string[] $suppress Suppress columns. 75 * @param string[] $nosorting No sorting. 76 * @param (array|object)[] $data The data of the table. 77 * @param int $pagesize Page size of the table 78 * @param string $caption Caption of the table. 79 * @param array $captionattribute The attribute of the caption. 80 */ 81 protected function run_table_test($columns, $headers, $sortable, $collapsible, $suppress, $nosorting, $data, 82 $pagesize, $caption = '', $captionattribute = []) { 83 $table = $this->create_and_setup_table($columns, $headers, $sortable, $collapsible, $suppress, $nosorting, 84 $caption, $captionattribute); 85 $table->pagesize($pagesize, count($data)); 86 foreach ($data as $row) { 87 $table->add_data_keyed($row); 88 } 89 $table->finish_output(); 90 } 91 92 /** 93 * Create a table with properties as passed in params. 94 * 95 * @param string[] $columns The columns of the table. 96 * @param string[] $headers The header of the table. 97 * @param bool $sortable Sorting of the table. 98 * @param bool $collapsible Is table collapsible. 99 * @param string[] $suppress Suppress columns. 100 * @param string[] $nosorting No sorting. 101 * @param string $caption Caption of the table. 102 * @param array $captionattribute The attribute of the caption. 103 * @return flexible_table 104 */ 105 protected function create_and_setup_table($columns, $headers, $sortable, $collapsible, $suppress, $nosorting, 106 $caption = '', $captionattribute = '') { 107 $table = new flexible_table('tablelib_test'); 108 109 $table->define_columns($columns); 110 $table->define_headers($headers); 111 $table->define_baseurl('/invalid.php'); 112 113 $table->sortable($sortable); 114 $table->collapsible($collapsible); 115 foreach ($suppress as $column) { 116 $table->column_suppress($column); 117 } 118 119 foreach ($nosorting as $column) { 120 $table->no_sorting($column); 121 } 122 if ($caption) { 123 $table->set_caption($caption, $captionattribute); 124 } 125 126 $table->setup(); 127 return $table; 128 } 129 130 public function test_empty_table() { 131 $this->expectOutputRegex('/' . get_string('nothingtodisplay') . '/'); 132 $this->run_table_test( 133 array('column1', 'column2'), // Columns. 134 array('Column 1', 'Column 2'), // Headers. 135 true, // Sortable. 136 false, // Collapsible. 137 array(), // Suppress columns. 138 array(), // No sorting. 139 array(), // Data. 140 10 // Page size. 141 ); 142 } 143 144 public function test_has_next_pagination() { 145 146 $data = $this->generate_data(11, 2); 147 $columns = $this->generate_columns(2); 148 $headers = $this->generate_headers(2); 149 150 // Search for pagination controls containing 'page-link"\saria-label="Next"'. 151 $this->expectOutputRegex('/Next page/'); 152 153 $this->run_table_test( 154 $columns, 155 $headers, 156 true, 157 false, 158 array(), 159 array(), 160 $data, 161 10 162 ); 163 } 164 165 public function test_has_hide() { 166 167 $data = $this->generate_data(11, 2); 168 $columns = $this->generate_columns(2); 169 $headers = $this->generate_headers(2); 170 171 // Search for 'hide' links in the column headers. 172 $this->expectOutputRegex('/' . get_string('hide') . '/'); 173 174 $this->run_table_test( 175 $columns, 176 $headers, 177 true, 178 true, 179 array(), 180 array(), 181 $data, 182 10 183 ); 184 } 185 186 public function test_has_not_hide() { 187 188 $data = $this->generate_data(11, 2); 189 $columns = $this->generate_columns(2); 190 $headers = $this->generate_headers(2); 191 192 // Make sure there are no 'hide' links in the headers. 193 194 ob_start(); 195 $this->run_table_test( 196 $columns, 197 $headers, 198 true, 199 false, 200 array(), 201 array(), 202 $data, 203 10 204 ); 205 $output = ob_get_contents(); 206 ob_end_clean(); 207 $this->assertStringNotContainsString(get_string('hide'), $output); 208 } 209 210 public function test_has_sort() { 211 212 $data = $this->generate_data(11, 2); 213 $columns = $this->generate_columns(2); 214 $headers = $this->generate_headers(2); 215 216 // Search for pagination controls containing '1.*2</a>.*Next</a>'. 217 $this->expectOutputRegex('/' . get_string('sortby') . '/'); 218 219 $this->run_table_test( 220 $columns, 221 $headers, 222 true, 223 false, 224 array(), 225 array(), 226 $data, 227 10 228 ); 229 } 230 231 public function test_has_not_sort() { 232 233 $data = $this->generate_data(11, 2); 234 $columns = $this->generate_columns(2); 235 $headers = $this->generate_headers(2); 236 237 // Make sure there are no 'Sort by' links in the headers. 238 239 ob_start(); 240 $this->run_table_test( 241 $columns, 242 $headers, 243 false, 244 false, 245 array(), 246 array(), 247 $data, 248 10 249 ); 250 $output = ob_get_contents(); 251 ob_end_clean(); 252 $this->assertStringNotContainsString(get_string('sortby'), $output); 253 } 254 255 public function test_has_not_next_pagination() { 256 257 $data = $this->generate_data(10, 2); 258 $columns = $this->generate_columns(2); 259 $headers = $this->generate_headers(2); 260 261 // Make sure there are no 'Next' links in the pagination. 262 263 ob_start(); 264 $this->run_table_test( 265 $columns, 266 $headers, 267 true, 268 false, 269 array(), 270 array(), 271 $data, 272 10 273 ); 274 275 $output = ob_get_contents(); 276 ob_end_clean(); 277 $this->assertStringNotContainsString(get_string('next'), $output); 278 } 279 280 public function test_1_col() { 281 282 $data = $this->generate_data(100, 1); 283 $columns = $this->generate_columns(1); 284 $headers = $this->generate_headers(1); 285 286 $this->expectOutputRegex('/row 0 col 0/'); 287 288 $this->run_table_test( 289 $columns, 290 $headers, 291 true, 292 false, 293 array(), 294 array(), 295 $data, 296 10 297 ); 298 } 299 300 public function test_empty_rows() { 301 302 $data = $this->generate_data(1, 5); 303 $columns = $this->generate_columns(5); 304 $headers = $this->generate_headers(5); 305 306 // Test that we have at least 5 columns generated for each empty row. 307 $this->expectOutputRegex('/emptyrow.*r9_c4/'); 308 309 $this->run_table_test( 310 $columns, 311 $headers, 312 true, 313 false, 314 array(), 315 array(), 316 $data, 317 10 318 ); 319 } 320 321 public function test_5_cols() { 322 323 $data = $this->generate_data(100, 5); 324 $columns = $this->generate_columns(5); 325 $headers = $this->generate_headers(5); 326 327 $this->expectOutputRegex('/row 0 col 0/'); 328 329 $this->run_table_test( 330 $columns, 331 $headers, 332 true, 333 false, 334 array(), 335 array(), 336 $data, 337 10 338 ); 339 } 340 341 public function test_50_cols() { 342 343 $data = $this->generate_data(100, 50); 344 $columns = $this->generate_columns(50); 345 $headers = $this->generate_headers(50); 346 347 $this->expectOutputRegex('/row 0 col 0/'); 348 349 $this->run_table_test( 350 $columns, 351 $headers, 352 true, 353 false, 354 array(), 355 array(), 356 $data, 357 10 358 ); 359 } 360 361 /** 362 * Data provider for test_fullname_column 363 * 364 * @return array 365 */ 366 public function fullname_column_provider() { 367 return [ 368 ['language'], 369 ['alternatename lastname'], 370 ['firstname lastnamephonetic'], 371 ]; 372 } 373 374 /** 375 * Test fullname column observes configured alternate fullname format configuration 376 * 377 * @param string $format 378 * @return void 379 * 380 * @dataProvider fullname_column_provider 381 */ 382 public function test_fullname_column(string $format) { 383 $this->resetAfterTest(); 384 $this->setAdminUser(); 385 386 set_config('alternativefullnameformat', $format); 387 388 $user = $this->getDataGenerator()->create_user(); 389 390 $table = $this->create_and_setup_table(['fullname'], [], true, false, [], []); 391 $this->assertStringContainsString(fullname($user, true), $table->format_row($user)['fullname']); 392 } 393 394 /** 395 * Test fullname column ignores fullname format configuration for a user with viewfullnames capability prohibited 396 * 397 * @param string $format 398 * @return void 399 * 400 * @dataProvider fullname_column_provider 401 */ 402 public function test_fullname_column_prohibit_viewfullnames(string $format) { 403 global $DB, $CFG; 404 405 $this->resetAfterTest(); 406 407 set_config('alternativefullnameformat', $format); 408 409 $currentuser = $this->getDataGenerator()->create_user(); 410 $this->setUser($currentuser); 411 412 // Prohibit the viewfullnames from the default user role. 413 $userrole = $DB->get_record('role', ['id' => $CFG->defaultuserroleid]); 414 role_change_permission($userrole->id, \context_system::instance(), 'moodle/site:viewfullnames', CAP_PROHIBIT); 415 416 $user = $this->getDataGenerator()->create_user(); 417 418 $table = $this->create_and_setup_table(['fullname'], [], true, false, [], []); 419 $this->assertStringContainsString(fullname($user, false), $table->format_row($user)['fullname']); 420 } 421 422 public function test_get_row_html() { 423 $data = $this->generate_data(1, 5); 424 $columns = $this->generate_columns(5); 425 $headers = $this->generate_headers(5); 426 $data = array_keys(array_flip($data[0])); 427 428 $table = new flexible_table('tablelib_test'); 429 $table->define_columns($columns); 430 $table->define_headers($headers); 431 $table->define_baseurl('/invalid.php'); 432 433 $row = $table->get_row_html($data); 434 $this->assertMatchesRegularExpression('/row 0 col 0/', $row); 435 $this->assertMatchesRegularExpression('/<tr class=""/', $row); 436 $this->assertMatchesRegularExpression('/<td class="cell c0"/', $row); 437 } 438 439 public function test_persistent_table() { 440 global $SESSION; 441 442 $data = $this->generate_data(5, 5); 443 $columns = $this->generate_columns(5); 444 $headers = $this->generate_headers(5); 445 446 // Testing without persistence first to verify that the results are different. 447 $table1 = new flexible_table('tablelib_test'); 448 $table1->define_columns($columns); 449 $table1->define_headers($headers); 450 $table1->define_baseurl('/invalid.php'); 451 452 $table1->sortable(true); 453 $table1->collapsible(true); 454 455 $table1->is_persistent(false); 456 $_GET['thide'] = 'column0'; 457 $_GET['tsort'] = 'column1'; 458 $_GET['tifirst'] = 'A'; 459 $_GET['tilast'] = 'Z'; 460 461 foreach ($data as $row) { 462 $table1->add_data_keyed($row); 463 } 464 $table1->setup(); 465 466 // Clear session data between each new table. 467 unset($SESSION->flextable); 468 469 $table2 = new flexible_table('tablelib_test'); 470 $table2->define_columns($columns); 471 $table2->define_headers($headers); 472 $table2->define_baseurl('/invalid.php'); 473 474 $table2->sortable(true); 475 $table2->collapsible(true); 476 477 $table2->is_persistent(false); 478 unset($_GET); 479 480 foreach ($data as $row) { 481 $table2->add_data_keyed($row); 482 } 483 $table2->setup(); 484 485 $this->assertNotEquals($table1, $table2); 486 487 unset($SESSION->flextable); 488 489 // Now testing with persistence to check that the tables are the same. 490 $table3 = new flexible_table('tablelib_test'); 491 $table3->define_columns($columns); 492 $table3->define_headers($headers); 493 $table3->define_baseurl('/invalid.php'); 494 495 $table3->sortable(true); 496 $table3->collapsible(true); 497 498 $table3->is_persistent(true); 499 $_GET['thide'] = 'column0'; 500 $_GET['tsort'] = 'column1'; 501 $_GET['tifirst'] = 'A'; 502 $_GET['tilast'] = 'Z'; 503 504 foreach ($data as $row) { 505 $table3->add_data_keyed($row); 506 } 507 $table3->setup(); 508 509 unset($SESSION->flextable); 510 511 $table4 = new flexible_table('tablelib_test'); 512 $table4->define_columns($columns); 513 $table4->define_headers($headers); 514 $table4->define_baseurl('/invalid.php'); 515 516 $table4->sortable(true); 517 $table4->collapsible(true); 518 519 $table4->is_persistent(true); 520 unset($_GET); 521 522 foreach ($data as $row) { 523 $table4->add_data_keyed($row); 524 } 525 $table4->setup(); 526 527 $this->assertEquals($table3, $table4); 528 529 unset($SESSION->flextable); 530 531 // Finally, another test with no persistence, but without clearing the session data. 532 $table5 = new flexible_table('tablelib_test'); 533 $table5->define_columns($columns); 534 $table5->define_headers($headers); 535 $table5->define_baseurl('/invalid.php'); 536 537 $table5->sortable(true); 538 $table5->collapsible(true); 539 540 $table5->is_persistent(true); 541 $_GET['thide'] = 'column0'; 542 $_GET['tsort'] = 'column1'; 543 $_GET['tifirst'] = 'A'; 544 $_GET['tilast'] = 'Z'; 545 546 foreach ($data as $row) { 547 $table5->add_data_keyed($row); 548 } 549 $table5->setup(); 550 551 $table6 = new flexible_table('tablelib_test'); 552 $table6->define_columns($columns); 553 $table6->define_headers($headers); 554 $table6->define_baseurl('/invalid.php'); 555 556 $table6->sortable(true); 557 $table6->collapsible(true); 558 559 $table6->is_persistent(true); 560 unset($_GET); 561 562 foreach ($data as $row) { 563 $table6->add_data_keyed($row); 564 } 565 $table6->setup(); 566 567 $this->assertEquals($table5, $table6); 568 } 569 570 /** 571 * Helper method for preparing tables instances in {@link self::test_can_be_reset()}. 572 * 573 * @param string $tableid 574 * @return testable_flexible_table 575 */ 576 protected function prepare_table_for_reset_test($tableid) { 577 global $SESSION; 578 579 unset($SESSION->flextable[$tableid]); 580 581 $data = $this->generate_data(25, 3); 582 $columns = array('column0', 'column1', 'column2'); 583 $headers = $this->generate_headers(3); 584 585 $table = new testable_flexible_table($tableid); 586 $table->define_baseurl('/invalid.php'); 587 $table->define_columns($columns); 588 $table->define_headers($headers); 589 $table->collapsible(true); 590 $table->is_persistent(false); 591 592 return $table; 593 } 594 595 public function test_can_be_reset() { 596 // Table in its default state (as if seen for the first time), nothing to reset. 597 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 598 $table->setup(); 599 $this->assertFalse($table->can_be_reset()); 600 601 // Table in its default state with default sorting defined, nothing to reset. 602 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 603 $table->sortable(true, 'column1', SORT_DESC); 604 $table->setup(); 605 $this->assertFalse($table->can_be_reset()); 606 607 // Table explicitly sorted by the default column & direction, nothing to reset. 608 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 609 $table->sortable(true, 'column1', SORT_DESC); 610 $_GET['tsort'] = 'column1'; 611 $_GET['tdir'] = SORT_DESC; 612 $table->setup(); 613 unset($_GET['tsort']); 614 unset($_GET['tdir']); 615 $this->assertFalse($table->can_be_reset()); 616 617 // Table explicitly sorted twice by the default column & direction, nothing to reset. 618 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 619 $table->sortable(true, 'column1', SORT_DESC); 620 $_GET['tsort'] = 'column1'; 621 $_GET['tdir'] = SORT_DESC; 622 $table->setup(); 623 $table->setup(); // Set up again to simulate the second page request. 624 unset($_GET['tsort']); 625 unset($_GET['tdir']); 626 $this->assertFalse($table->can_be_reset()); 627 628 // Table sorted by other than default column, can be reset. 629 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 630 $table->sortable(true, 'column1', SORT_DESC); 631 $_GET['tsort'] = 'column2'; 632 $table->setup(); 633 unset($_GET['tsort']); 634 $this->assertTrue($table->can_be_reset()); 635 636 // Table sorted by other than default direction, can be reset. 637 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 638 $table->sortable(true, 'column1', SORT_DESC); 639 $_GET['tsort'] = 'column1'; 640 $_GET['tdir'] = SORT_ASC; 641 $table->setup(); 642 unset($_GET['tsort']); 643 unset($_GET['tdir']); 644 $this->assertTrue($table->can_be_reset()); 645 646 // Table sorted by the default column after another sorting previously selected. 647 // This leads to different ORDER BY than just having a single sort defined, can be reset. 648 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 649 $table->sortable(true, 'column1', SORT_DESC); 650 $_GET['tsort'] = 'column0'; 651 $table->setup(); 652 $_GET['tsort'] = 'column1'; 653 $table->setup(); 654 unset($_GET['tsort']); 655 $this->assertTrue($table->can_be_reset()); 656 657 // Table having some column collapsed, can be reset. 658 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 659 $_GET['thide'] = 'column2'; 660 $table->setup(); 661 unset($_GET['thide']); 662 $this->assertTrue($table->can_be_reset()); 663 664 // Table having some column explicitly expanded, nothing to reset. 665 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 666 $_GET['tshow'] = 'column2'; 667 $table->setup(); 668 unset($_GET['tshow']); 669 $this->assertFalse($table->can_be_reset()); 670 671 // Table after expanding a collapsed column, nothing to reset. 672 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 673 $_GET['thide'] = 'column0'; 674 $table->setup(); 675 $_GET['tshow'] = 'column0'; 676 $table->setup(); 677 unset($_GET['thide']); 678 unset($_GET['tshow']); 679 $this->assertFalse($table->can_be_reset()); 680 681 // Table with some name filtering enabled, can be reset. 682 $table = $this->prepare_table_for_reset_test(uniqid('tablelib_test_')); 683 $_GET['tifirst'] = 'A'; 684 $table->setup(); 685 unset($_GET['tifirst']); 686 $this->assertTrue($table->can_be_reset()); 687 } 688 689 /** 690 * Test export in CSV format 691 */ 692 public function test_table_export() { 693 $table = new flexible_table('tablelib_test_export'); 694 $table->define_baseurl('/invalid.php'); 695 $table->define_columns(['c1', 'c2', 'c3']); 696 $table->define_headers(['Col1', 'Col2', 'Col3']); 697 698 ob_start(); 699 $table->is_downloadable(true); 700 $table->is_downloading('csv'); 701 702 $table->setup(); 703 $table->add_data(['column0' => 'a', 'column1' => 'b', 'column2' => 'c']); 704 $output = ob_get_contents(); 705 ob_end_clean(); 706 707 $this->assertEquals("Col1,Col2,Col3\na,b,c\n", substr($output, 3)); 708 } 709 710 /** 711 * Test the initials functionality. 712 * 713 * @dataProvider initials_provider 714 * @param string|null $getvalue 715 * @param string|null $setvalue 716 * @param string|null $finalvalue 717 */ 718 public function test_initials_first_set(?string $getvalue, ?string $setvalue, ?string $finalvalue): void { 719 global $_GET; 720 721 $this->resetAfterTest(true); 722 723 $table = new flexible_table('tablelib_test'); 724 725 $user = $this->getDataGenerator()->create_user(); 726 727 $table->define_columns(['fullname']); 728 $table->define_headers(['Fullname']); 729 $table->define_baseurl('/invalid.php'); 730 $table->initialbars(true); 731 732 if ($getvalue !== null) { 733 $_GET['tifirst'] = $getvalue; 734 } 735 736 if ($setvalue !== null) { 737 $table->set_first_initial($setvalue); 738 } 739 740 $table->setup(); 741 742 $this->assertEquals($finalvalue, $table->get_initial_first()); 743 } 744 745 /** 746 * Test the initials functionality. 747 * 748 * @dataProvider initials_provider 749 * @param string|null $getvalue 750 * @param string|null $setvalue 751 * @param string|null $finalvalue 752 */ 753 public function test_initials_last_set(?string $getvalue, ?string $setvalue, ?string $finalvalue): void { 754 global $_GET; 755 756 $this->resetAfterTest(true); 757 758 $table = new flexible_table('tablelib_test'); 759 760 $user = $this->getDataGenerator()->create_user(); 761 762 $table->define_columns(['fullname']); 763 $table->define_headers(['Fullname']); 764 $table->define_baseurl('/invalid.php'); 765 $table->initialbars(true); 766 767 if ($getvalue !== null) { 768 $_GET['tilast'] = $getvalue; 769 } 770 771 if ($setvalue !== null) { 772 $table->set_last_initial($setvalue); 773 } 774 775 $table->setup(); 776 777 $this->assertEquals($finalvalue, $table->get_initial_last()); 778 } 779 780 /** 781 * Data for testing initials providers. 782 * 783 * @return array 784 */ 785 public function initials_provider(): array { 786 return [ 787 [null, null, null], 788 ['A', null, 'A'], 789 ['Z', null, 'Z'], 790 [null, 'A', 'A'], 791 [null, 'Z', 'Z'], 792 ['A', 'Z', 'Z'], 793 ['Z', 'A', 'A'], 794 ]; 795 } 796 797 /** 798 * Data test for set and render caption for table. 799 * 800 * @covers ::set_caption_for_table 801 * @covers ::render_caption_for_table 802 */ 803 public function test_set_and_render_caption_for_table(): void { 804 $data = $this->generate_data(10, 2); 805 $columns = $this->generate_columns(2); 806 $headers = $this->generate_headers(2); 807 $caption = 'Caption for table'; 808 $captionattribute = ['class' => 'inline']; 809 $this->run_table_test( 810 $columns, 811 $headers, 812 // Sortable. 813 true, 814 // Collapsible. 815 false, 816 // Suppress columns. 817 [], 818 // No sorting. 819 [], 820 // Data. 821 $data, 822 // Page size. 823 10, 824 // Caption for table. 825 $caption, 826 // Caption attribute. 827 $captionattribute, 828 ); 829 $this->expectOutputRegex('/' . '<caption class="inline">' . $caption . '<\/caption>' . '/'); 830 } 831 832 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body