justReturn(false); Functions\when('is_category')->justReturn(false); $this->walker = new NavWalker(); } protected function tearDown(): void { Monkey\tearDown(); parent::tearDown(); } // ── Tree structure ────────────────────────────────────────── public function testBuildTreeWithEmptyArray(): void { $this->assertSame([], $this->walker->buildTree([])); } public function testBuildTreeWithSingleItem(): void { $items = [$this->makeItem(10, 'Home', '/')]; $tree = $this->walker->buildTree($items); $this->assertCount(1, $tree); $this->assertSame('Home', $tree[0]['title']); $this->assertSame('/', $tree[0]['url']); } public function testBuildTreeFlatItemsAllTopLevel(): void { $items = [ $this->makeItem(1, 'A', '/a'), $this->makeItem(2, 'B', '/b'), $this->makeItem(3, 'C', '/c'), ]; $tree = $this->walker->buildTree($items); $this->assertCount(3, $tree); foreach ($tree as $node) { $this->assertEmpty($node['children']); } } public function testBuildTreeWithChildren(): void { $items = [ $this->makeItem(10, 'Home', '/'), $this->makeItem(20, 'About', '/about'), $this->makeItem(30, 'Team', '/about/team', parent: 20), $this->makeItem(40, 'Jobs', '/about/jobs', parent: 20), ]; $tree = $this->walker->buildTree($items); $this->assertCount(2, $tree); $this->assertSame('About', $tree[1]['title']); $this->assertCount(2, $tree[1]['children']); $this->assertSame('Team', $tree[1]['children'][0]['title']); $this->assertSame('Jobs', $tree[1]['children'][1]['title']); } public function testBuildTreeWithMultipleParents(): void { $items = [ $this->makeItem(1, 'A', '/a'), $this->makeItem(2, 'B', '/b'), $this->makeItem(3, 'A1', '/a/1', parent: 1), $this->makeItem(4, 'B1', '/b/1', parent: 2), ]; $tree = $this->walker->buildTree($items); $this->assertCount(2, $tree); $this->assertCount(1, $tree[0]['children']); $this->assertCount(1, $tree[1]['children']); $this->assertSame('A1', $tree[0]['children'][0]['title']); $this->assertSame('B1', $tree[1]['children'][0]['title']); } public function testBuildTreeOrphansAreDropped(): void { $items = [ $this->makeItem(1, 'Root', '/'), $this->makeItem(2, 'Orphan', '/orphan', parent: 999), ]; $tree = $this->walker->buildTree($items); $this->assertCount(1, $tree); $this->assertSame('Root', $tree[0]['title']); } public function testBuildTreeNodeStructure(): void { $items = [$this->makeItem(42, 'Page', '/page', target: '_blank', classes: ['menu-item', 'custom'])]; $tree = $this->walker->buildTree($items); $node = $tree[0]; $this->assertSame(42, $node['id']); $this->assertSame('Page', $node['title']); $this->assertSame('/page', $node['url']); $this->assertSame('_blank', $node['target']); $this->assertSame('menu-item custom', $node['classes']); $this->assertIsBool($node['active']); $this->assertIsArray($node['children']); } public function testBuildTreeClassesJoined(): void { $items = [$this->makeItem(1, 'X', '/x', classes: ['nav-item', '', 'menu-item'])]; $tree = $this->walker->buildTree($items); // Empty strings are filtered out by array_filter. $this->assertSame('nav-item menu-item', $tree[0]['classes']); } public function testBuildTreeIndexIsReset(): void { $items = [ $this->makeItem(50, 'A', '/a'), $this->makeItem(100, 'B', '/b'), ]; $tree = $this->walker->buildTree($items); // array_values resets keys to 0-indexed. $this->assertArrayHasKey(0, $tree); $this->assertArrayHasKey(1, $tree); $this->assertArrayNotHasKey(50, $tree); } // ── Active detection ──────────────────────────────────────── public function testBuildTreeSetsActiveViaCurrentMenuItem(): void { $items = [$this->makeItem(1, 'Active', '/active', classes: ['current-menu-item'])]; $tree = $this->walker->buildTree($items); $this->assertTrue($tree[0]['active']); } public function testBuildTreeSetsActiveViaAncestor(): void { $items = [$this->makeItem(1, 'Parent', '/parent', classes: ['current-menu-ancestor'])]; $tree = $this->walker->buildTree($items); $this->assertTrue($tree[0]['active']); } public function testBuildTreeSetsActiveViaIsPage(): void { Functions\when('is_page')->alias(fn(int $id): bool => $id === 42); $items = [$this->makeItem(1, 'Contact', '/contact', object: 'page', objectId: 42)]; $tree = $this->walker->buildTree($items); $this->assertTrue($tree[0]['active']); } public function testBuildTreeSetsActiveViaIsCategory(): void { Functions\when('is_category')->alias(fn(int $id): bool => $id === 7); $items = [$this->makeItem(1, 'News', '/news', object: 'category', objectId: 7)]; $tree = $this->walker->buildTree($items); $this->assertTrue($tree[0]['active']); } public function testBuildTreeNotActive(): void { $items = [$this->makeItem(1, 'Inactive', '/inactive')]; $tree = $this->walker->buildTree($items); $this->assertFalse($tree[0]['active']); } // ── Helper ────────────────────────────────────────────────── private function makeItem( int $id, string $title, string $url, int $parent = 0, string $target = '', array $classes = [], string $object = 'page', int $objectId = 0, ): object { return (object) [ 'ID' => $id, 'title' => $title, 'url' => $url, 'target' => $target, 'classes' => $classes, 'menu_item_parent' => $parent, 'object' => $object, 'object_id' => $objectId ?: $id, ]; } }