BxBaseMenuToolbarTest.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <?php
  2. /**
  3. * The '[Main Menu]' button (name 'main-menu') is an item of the member toolbar, on the right side of the header
  4. * next to the account, notifications and add content buttons. It used to be the only item of the site toolbar
  5. * on the left of the logo.
  6. */
  7. class BxBaseMenuToolbarTest extends BxDolTestCase
  8. {
  9. private static function readFile(string $sPath): string
  10. {
  11. $s = file_get_contents(__DIR__ . '/../../../../' . $sPath);
  12. if ($s === false)
  13. self::fail($sPath . ' is not readable.');
  14. return $s;
  15. }
  16. private function callProtected($oObject, string $sMethod, array $aArgs = [])
  17. {
  18. $oMethod = new ReflectionMethod($oObject, $sMethod);
  19. return $oMethod->invokeArgs($oObject, $aArgs);
  20. }
  21. private function getMemberToolbar(): BxTemplMenuToolbar
  22. {
  23. $aObject = BxDolMenuQuery::getMenuObject('sys_toolbar_member');
  24. if (empty($aObject))
  25. $this->markTestSkipped('The member toolbar menu is not installed.');
  26. return new BxTemplMenuToolbar($aObject, BxDolTemplate::getInstance());
  27. }
  28. private function getMemberToolbarRows(BxTemplMenuToolbar $oMenu): array
  29. {
  30. $oQuery = new ReflectionProperty($oMenu, '_oQuery');
  31. $aRows = [];
  32. foreach ($oQuery->getValue($oMenu)->getMenuItems() as $aRow)
  33. $aRows[$aRow['name']] = $aRow;
  34. if (!isset($aRows['main-menu']))
  35. $this->markTestSkipped("This site has no '[Main Menu]' item in the member toolbar (the migration is not applied).");
  36. return $aRows;
  37. }
  38. private static function isArtificer(BxTemplMenuToolbar $oMenu): bool
  39. {
  40. return strpos((new ReflectionClass($oMenu))->getFileName(), '/artificer/') !== false;
  41. }
  42. public function testFreshInstallPutsTheMainMenuInTheMemberToolbar(): void
  43. {
  44. $sSql = self::readFile('install/sql/system.sql');
  45. $this->assertDoesNotMatchRegularExpression("/\\('sys_toolbar_site', 'system', 'main-menu',/", $sSql, 'The site toolbar no longer has it.');
  46. $bFound = preg_match("/\\('sys_toolbar_member', 'system', 'main-menu', '_sys_menu_item_title_system_main_menu', [^\\n]*?, (\\d+), (\\d+), (\\d+), (\\d+), (\\d+)\\)[,;]\\n/", $sSql, $aMatch);
  47. $this->assertSame(1, $bFound, 'system.sql adds it to the member toolbar.');
  48. [, $iVisibleFor, , $iActive, , $iOrder] = array_map('intval', $aMatch);
  49. $this->assertSame(2147483647, $iVisibleFor, 'Guests see it too.');
  50. $this->assertSame(1, $iActive);
  51. $this->assertSame(9999, $iOrder, 'It stays the last button, also after modules add their own.');
  52. $sAppSql = self::readFile('modules/system/install/sql/enable-app-menus.sql');
  53. $this->assertStringContainsString("SET `active_api`=1 WHERE `set_name`='sys_toolbar_member' AND `module`='system' AND `name`='main-menu';", $sAppSql);
  54. $this->assertStringNotContainsString("`set_name`='sys_toolbar_site' AND `module`='system' AND `name`='main-menu'", $sAppSql);
  55. }
  56. public function testHeaderHasNoLeftToolbar(): void
  57. {
  58. foreach (['template/_page_toolbar.html', 'modules/boonex/artificer/template/header.html'] as $sPath) {
  59. $sHtml = self::readFile($sPath);
  60. $this->assertStringNotContainsString('<bx_menu:sys_toolbar_site />', $sHtml, $sPath . ' renders nothing left of the logo.');
  61. $this->assertStringContainsString('<bx_menu:sys_toolbar_member />', $sHtml, $sPath);
  62. }
  63. }
  64. public function testMainMenuOpensTheSiteSidebar(): void
  65. {
  66. $oMenu = $this->getMemberToolbar();
  67. if (!self::isArtificer($oMenu))
  68. $this->markTestSkipped('The site sidebar belongs to the Artificer template.');
  69. $aRows = $this->getMemberToolbarRows($oMenu);
  70. $a = $this->callProtected($oMenu, '_getMenuItem', [$aRows['main-menu']]);
  71. $this->assertIsArray($a);
  72. $this->assertStringContainsString('bx-sidebar-site-trigger', $a['class_add_a'], 'The sidebar script binds to this class.');
  73. $this->assertFalse($a['bx_if:onclick']['condition'], 'No sliding menu opens on top of the sidebar.');
  74. $this->assertContains('lg:hidden', explode(' ', $a['class_add']), 'Wide screens show the main menu inline and have no sidebar.');
  75. $this->assertStringContainsString('aria-controls="bx-sidebar-site"', $a['attrs']);
  76. $this->assertStringContainsString('aria-expanded="false"', $a['attrs']);
  77. }
  78. public function testApiReadsTheToolbarWithoutWarnings(): void
  79. {
  80. $mixedApiBackup = $_GET['api'] ?? null;
  81. $_GET['api'] = 1;
  82. $aWarnings = [];
  83. set_error_handler(function ($iErrno, $sError, $sFile, $iLine) use (&$aWarnings) {
  84. $aWarnings[] = $sError . ' in ' . $sFile . ':' . $iLine;
  85. return true;
  86. }, E_WARNING | E_NOTICE);
  87. try {
  88. //--- Show every item, as a signed-in member sees 'add-content', 'account' and the rest.
  89. $aObject = BxDolMenuQuery::getMenuObject('sys_toolbar_member');
  90. if (empty($aObject))
  91. $this->markTestSkipped('The member toolbar menu is not installed.');
  92. $oMenu = new class($aObject, BxDolTemplate::getInstance()) extends BxTemplMenuToolbar {
  93. protected function _isVisible($a)
  94. {
  95. return true;
  96. }
  97. };
  98. $aItems = [];
  99. foreach ($this->getMemberToolbarRows($oMenu) as $sName => $aRow)
  100. if (($a = $this->callProtected($oMenu, '_getMenuItem', [$aRow])) !== false)
  101. $aItems[$sName] = $a;
  102. }
  103. finally {
  104. restore_error_handler();
  105. if ($mixedApiBackup === null)
  106. unset($_GET['api']);
  107. else
  108. $_GET['api'] = $mixedApiBackup;
  109. }
  110. $this->assertSame([], $aWarnings, 'A PHP warning printed into api.php output breaks the JSON NEO reads.');
  111. $this->assertArrayHasKey('main-menu', $aItems);
  112. $this->assertArrayHasKey('add-content', $aItems, 'Members-only items are rendered too.');
  113. $this->assertArrayNotHasKey('class_add', $aItems['main-menu'], 'HTML-only classes stay out of the API item.');
  114. }
  115. }