addObserver('Category.addSubcategories', function (&$subcategories) { $subcategory = new Subcategory(); $subcategory->setId('CoreHome_TestAiInsightsSub'); $subcategory->setCategoryId('General_AIAssistants'); $subcategory->setOrder(1); $subcategories[] = $subcategory; }); MenuTop::unsetInstance(); } public function tearDown(): void { unset($_GET['idSite']); MenuTop::unsetInstance(); parent::tearDown(); } public function testTopMenuContainsAnEntryForTheAiInsightsReportingGroup() { $menu = MenuTop::getInstance()->getMenu(); $this->assertArrayHasKey('CoreHome_AIInsights', $menu); // The section is carried in the URL hash (not the query string) so it does not leak into other // links; category/subcategory are resolved client-side by the reporting SPA. $url = $menu['CoreHome_AIInsights']['_url']; $this->assertIsString($url); $this->assertStringStartsWith('index.php?', $url); [$queryPart, $hashPart] = explode('#', $url, 2); $this->assertStringContainsString('module=CoreHome', $queryPart); $this->assertStringContainsString('action=index', $queryPart); $this->assertStringNotContainsString('group=', $queryPart); $this->assertStringContainsString('group=CoreHome_AIInsights', $hashPart); // the entry is tagged so the active highlight can be synced client-side from the hash $this->assertSame('data-reporting-group="CoreHome_AIInsights"', $menu['CoreHome_AIInsights']['_attribute']); } public function testCategoryListExposesGroupsWithoutTrackingRequirement() { // AI Insights is exempt from the tracker-setup screen, the default Analytics group is not. $groups = CategoryList::get()->getGroupsWithoutTrackingRequirement(); $this->assertContains('CoreHome_AIInsights', $groups); $this->assertNotContains('', $groups); } public function testTopMenuDoesNotCreateEntriesForDefaultGroupCategories() { $menu = MenuTop::getInstance()->getMenu(); // Regular (Analytics) categories must not get their own top-menu entry. $this->assertArrayNotHasKey('General_Visitors', $menu); $this->assertArrayNotHasKey('General_Actions', $menu); } public function testAnalyticsTopMenuEntryCarriesTheDefaultReportingGroupInTheHashOnly() { $menu = MenuTop::getInstance()->getMenu(); $this->assertArrayHasKey('Dashboard_TopMenuTitle', $menu); // The (default) section is carried in the hash with an empty group id, not in the query string. $url = $menu['Dashboard_TopMenuTitle']['_url']; $this->assertIsString($url); $this->assertStringStartsWith('index.php?', $url); [$queryPart, $hashPart] = explode('#', $url, 2); $this->assertStringContainsString('module=CoreHome', $queryPart); $this->assertStringContainsString('action=index', $queryPart); $this->assertStringNotContainsString('group=', $queryPart); $this->assertStringContainsString('group=', $hashPart); $this->assertStringNotContainsString('group=CoreHome', $hashPart); // the entry is tagged as the default section so the active highlight can be synced client-side $this->assertSame('data-reporting-group=""', $menu['Dashboard_TopMenuTitle']['_attribute']); } }