Files
wp-bootstrap/tests/Unit/Template/NavWalkerTest.php
magdev e607382e11
Some checks failed
Create Release Package / PHP Lint (push) Successful in 1m6s
Create Release Package / PHPUnit Tests (push) Successful in 1m4s
Create Release Package / Build Release (push) Failing after 1m13s
Add PHPUnit test suite with 64 unit tests (v1.1.1)
PHPUnit 11 + Brain\Monkey for WordPress function mocking. Tests cover
BlockRenderer (28), WidgetRenderer (9), NavWalker (14), and
TemplateController (12). Includes functional WP_HTML_Tag_Processor stub,
CI test job between lint and build-release, prebuild hook gating npm
build on passing tests, and release package exclusions for test files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 00:08:34 +01:00

225 lines
7.0 KiB
PHP

<?php
declare(strict_types=1);
namespace WPBootstrap\Tests\Unit\Template;
use PHPUnit\Framework\TestCase;
use Brain\Monkey;
use Brain\Monkey\Functions;
use WPBootstrap\Template\NavWalker;
class NavWalkerTest extends TestCase
{
private NavWalker $walker;
protected function setUp(): void
{
parent::setUp();
Monkey\setUp();
// Default: no page or category is active.
Functions\when('is_page')->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,
];
}
}