Files
michaelschiemer/tests/Application/Admin/Service/AdminLayoutProcessorTest.php
Michael Schiemer 5050c7d73a docs: consolidate documentation into organized structure
- Move 12 markdown files from root to docs/ subdirectories
- Organize documentation by category:
  • docs/troubleshooting/ (1 file)  - Technical troubleshooting guides
  • docs/deployment/      (4 files) - Deployment and security documentation
  • docs/guides/          (3 files) - Feature-specific guides
  • docs/planning/        (4 files) - Planning and improvement proposals

Root directory cleanup:
- Reduced from 16 to 4 markdown files in root
- Only essential project files remain:
  • CLAUDE.md (AI instructions)
  • README.md (Main project readme)
  • CLEANUP_PLAN.md (Current cleanup plan)
  • SRC_STRUCTURE_IMPROVEMENTS.md (Structure improvements)

This improves:
 Documentation discoverability
 Logical organization by purpose
 Clean root directory
 Better maintainability
2025-10-05 11:05:04 +02:00

253 lines
8.1 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Application\Admin\Service;
use App\Application\Admin\Service\AdminLayoutProcessor;
use App\Application\Admin\Service\AdminNavigationService;
use App\Application\Admin\ValueObjects\AdminLayoutData;
use App\Application\Admin\ValueObjects\BreadcrumbCollection;
use App\Application\Admin\ValueObjects\NavigationMenu;
use App\Framework\Http\HttpRequest;
// Test stub for AdminNavigationService since it's final
class TestAdminNavigationService
{
private array $menuData = [];
private array $breadcrumbsData = [];
private bool $shouldFailMenu = false;
private bool $shouldFailBreadcrumbs = false;
public function setMenuData(array $menuData): void
{
$this->menuData = $menuData;
}
public function setBreadcrumbsData(array $breadcrumbsData): void
{
$this->breadcrumbsData = $breadcrumbsData;
}
public function setShouldFailMenu(bool $shouldFail): void
{
$this->shouldFailMenu = $shouldFail;
}
public function setShouldFailBreadcrumbs(bool $shouldFail): void
{
$this->shouldFailBreadcrumbs = $shouldFail;
}
public function getNavigationMenu(): array
{
if ($this->shouldFailMenu) {
throw new \Exception('Navigation service failed');
}
return $this->menuData;
}
public function getBreadcrumbs(string $currentPath): array
{
if ($this->shouldFailBreadcrumbs) {
throw new \Exception('Breadcrumbs service failed');
}
return $this->breadcrumbsData;
}
}
// Test stub for HttpRequest since it's readonly
class TestHttpRequest
{
public string $path = '/admin';
}
describe('AdminLayoutProcessor', function () {
beforeEach(function () {
$this->navigationService = new TestAdminNavigationService();
$this->request = new TestHttpRequest();
// Use reflection to create AdminLayoutProcessor with our test doubles
$reflection = new \ReflectionClass(AdminLayoutProcessor::class);
$constructor = $reflection->getConstructor();
// Create instance using reflection to bypass readonly constraints
$this->processor = $reflection->newInstanceWithoutConstructor();
// Set the private properties
$navProperty = $reflection->getProperty('navigationService');
$navProperty->setAccessible(true);
$navProperty->setValue($this->processor, $this->navigationService);
$requestProperty = $reflection->getProperty('request');
$requestProperty->setAccessible(true);
$requestProperty->setValue($this->processor, $this->request);
});
it('processes admin layout data with navigation and breadcrumbs', function () {
$this->request->path = '/admin/dashboard';
$menuData = [
'System' => [
'icon' => 'server',
'items' => [
'Dashboard' => '/admin',
'Health Check' => '/admin/system/health',
],
],
];
$breadcrumbsData = [
['name' => 'Admin', 'url' => '/admin'],
['name' => 'Dashboard', 'url' => '/admin/dashboard'],
];
$this->navigationService->setMenuData($menuData);
$this->navigationService->setBreadcrumbsData($breadcrumbsData);
$inputData = new AdminLayoutData(
title: 'Test Page',
navigationMenu: new NavigationMenu([]),
breadcrumbs: new BreadcrumbCollection([]),
currentPath: '/admin'
);
$result = $this->processor->processAdminLayout($inputData);
expect($result)->toBeInstanceOf(AdminLayoutData::class);
expect($result->navigationMenu->sections)->toHaveCount(1);
expect($result->navigationMenu->sections[0]->name)->toBe('System');
expect($result->navigationMenu->sections[0]->items)->toHaveCount(2);
expect($result->breadcrumbs->breadcrumbs)->toHaveCount(2);
});
it('handles navigation service failure gracefully', function () {
$this->request->path = '/admin/test';
$this->navigationService
->shouldReceive('getNavigationMenu')
->once()
->andThrow(new \Exception('Navigation service failed'));
$this->navigationService
->shouldReceive('getBreadcrumbs')
->with('/admin/test')
->once()
->andReturn([['name' => 'Admin', 'url' => '/admin']]);
$inputData = new AdminLayoutData(
title: 'Test Page',
navigationMenu: new NavigationMenu([]),
breadcrumbs: new BreadcrumbCollection([]),
currentPath: '/admin'
);
$result = $this->processor->processAdminLayout($inputData);
// Should have fallback menu
expect($result->navigationMenu->sections)->toHaveCount(1);
expect($result->navigationMenu->sections[0]->name)->toBe('System');
expect($result->navigationMenu->sections[0]->items)->toHaveCount(2);
expect($result->navigationMenu->sections[0]->items[0]->name)->toBe('Dashboard');
});
it('handles breadcrumbs service failure gracefully', function () {
$this->request->path = '/admin/test';
$this->navigationService
->shouldReceive('getNavigationMenu')
->once()
->andReturn([]);
$this->navigationService
->shouldReceive('getBreadcrumbs')
->with('/admin/test')
->once()
->andThrow(new \Exception('Breadcrumbs service failed'));
$inputData = new AdminLayoutData(
title: 'Test Page',
navigationMenu: new NavigationMenu([]),
breadcrumbs: new BreadcrumbCollection([]),
currentPath: '/admin'
);
$result = $this->processor->processAdminLayout($inputData);
// Should have fallback breadcrumbs
expect($result->breadcrumbs->breadcrumbs)->toHaveCount(1);
expect($result->breadcrumbs->breadcrumbs[0]->name)->toBe('Admin');
expect($result->breadcrumbs->breadcrumbs[0]->url)->toBe('/admin');
});
it('sets active state for navigation items based on current path', function () {
$this->request->path = '/admin/system/health';
$menuData = [
'System' => [
'items' => [
'Dashboard' => '/admin',
'Health Check' => '/admin/system/health',
],
],
];
$this->navigationService
->shouldReceive('getNavigationMenu')
->once()
->andReturn($menuData);
$this->navigationService
->shouldReceive('getBreadcrumbs')
->once()
->andReturn([]);
$inputData = new AdminLayoutData(
title: 'Health Check',
navigationMenu: new NavigationMenu([]),
breadcrumbs: new BreadcrumbCollection([]),
currentPath: '/admin'
);
$result = $this->processor->processAdminLayout($inputData);
$items = $result->navigationMenu->sections[0]->items;
expect($items[0]->isActive)->toBeFalse(); // Dashboard
expect($items[1]->isActive)->toBeTrue(); // Health Check (current path)
});
it('preserves original layout data properties', function () {
$this->request->path = '/admin';
$this->navigationService
->shouldReceive('getNavigationMenu')
->once()
->andReturn([]);
$this->navigationService
->shouldReceive('getBreadcrumbs')
->once()
->andReturn([]);
$inputData = new AdminLayoutData(
title: 'Original Title',
navigationMenu: new NavigationMenu([]),
breadcrumbs: new BreadcrumbCollection([]),
currentPath: '/admin',
metaDescription: 'Original description',
pageClass: 'original-class'
);
$result = $this->processor->processAdminLayout($inputData);
expect($result->title)->toBe('Original Title');
expect($result->metaDescription)->toBe('Original description');
expect($result->pageClass)->toBe('original-class');
});
});