You've already forked wp-bootstrap
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>
225 lines
7.0 KiB
PHP
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,
|
|
];
|
|
}
|
|
}
|