toContain("'active' => \$activeMenu === 'proxy'") ->toContain("'active' => \$activeSubMenu === 'dynamic-confs'") ->not->toContain("'active' => request()->routeIs('server.proxy.dynamic-confs')") ->and($dynamicConfigurations)->toContain('activeSubMenu="dynamic-confs"') ->and($proxyConfiguration)->toContain('activeSubMenu="configuration"') ->and($proxyLogs)->toContain('activeSubMenu="logs"'); }); it('keeps the server resources menu active during Livewire updates', function () { $sidebar = file_get_contents(resource_path('views/components/server/sidebar.blade.php')); expect($sidebar) ->toContain("'label' => 'Resources',\n 'route' => 'server.resources',\n 'active' => \$activeMenu === 'resources'") ->not->toContain("'active' => request()->routeIs('server.resources')"); }); it('initializes persisted sidebar state before enabling layout transitions', function () { $layout = file_get_contents(resource_path('views/layouts/app.blade.php')); expect($layout) ->toContain("collapsed: localStorage.getItem('sidebarCollapsed') === 'true'") ->toContain('sidebarReady: false') ->toContain(":class=\"[collapsed ? 'lg:w-16' : 'lg:w-56', sidebarReady ? 'transition-[width] duration-200' : '']\"") ->toContain(":class=\"[collapsed ? 'lg:ml-16' : 'lg:ml-56', sidebarReady ? 'transition-[margin] duration-200' : '']\""); }); it('shows the coolify icon in the collapsed desktop brand slot', function () { $layout = file_get_contents(resource_path('views/layouts/app.blade.php')); expect($layout) ->toContain('x-show="collapsed" x-cloak src="/coolify-logo.svg" alt="Coolify"') ->not->toContain('>C'); }); it('does not animate navbar padding when restoring collapsed state', function () { $navbar = file_get_contents(resource_path('views/components/navbar.blade.php')); expect($navbar) ->not->toContain('items-start gap-3 motion-safe:transition-all') ->not->toContain('overflow-hidden motion-safe:transition-all'); }); it('draws a single border between the desktop sidebar and main content', function () { $layout = file_get_contents(resource_path('views/layouts/app.blade.php')); $navbar = file_get_contents(resource_path('views/components/navbar.blade.php')); expect($navbar)->toContain('border-r border-neutral-200') ->and($layout)->not->toContain('lg:border-l border-neutral-200'); }); it('does not separate the desktop sidebar controls with a top border', function () { $navbar = file_get_contents(resource_path('views/components/navbar.blade.php')); expect($navbar) ->toContain('sticky bottom-0 mt-auto -mx-2 hidden items-center gap-1 bg-white') ->not->toContain('sticky bottom-0 mt-auto -mx-2 hidden items-center gap-1 border-t'); }); it('draws the desktop header border only above the main content', function () { $layout = file_get_contents(resource_path('views/layouts/app.blade.php')); expect($layout) ->toContain('flex items-center gap-2 h-full shrink-0 border-r border-neutral-200') ->toContain('flex h-full items-center gap-0.5 min-w-0 flex-1 border-b border-neutral-200 pl-3 pr-4 dark:border-white/[0.06]') ->not->toContain('backdrop-blur border-b border-neutral-200 dark:border-white/[0.06]'); }); it('separates the mobile sidebar from the page with a visible border', function () { $layout = file_get_contents(resource_path('views/layouts/app.blade.php')); expect($layout)->toContain('max-w-56 min-w-0 flex-col border-l border-neutral-200 bg-white shadow-xl dark:border-white/[0.12] dark:bg-panel'); }); it('keeps the mobile navbar above floating configuration warnings', function () { $layout = file_get_contents(resource_path('views/layouts/app.blade.php')); $popup = file_get_contents(resource_path('views/components/popup-small.blade.php')); expect($layout) ->toContain('class="relative z-[1000] lg:hidden"') ->and($popup)->toContain('z-999'); }); it('keeps compact configuration warnings the same width as their expanded state', function () { $popup = file_get_contents(resource_path('views/components/popup-small.blade.php')); expect($popup) ->toContain("? 'w-[calc(100vw-2rem)] max-w-sm cursor-pointer'") ->toContain(": 'w-[calc(100vw-2rem)] max-w-sm'") ->not->toContain('sm:w-auto'); }); it('provides configuration warning slots in both desktop and mobile navbars', function () { $layout = file_get_contents(resource_path('views/layouts/app.blade.php')); expect($layout) ->toContain('id="configuration-warning-hud-slot"') ->toContain('id="configuration-warning-hud-slot-mobile"'); }); it('shows the full team name in the header', function () { $layout = file_get_contents(resource_path('views/layouts/app.blade.php')); $switcher = file_get_contents(resource_path('views/livewire/switch-team.blade.php')); expect($layout) ->toContain('flex min-w-0 flex-1 items-center gap-2.5') ->toContain('size-8 shrink-0 items-center justify-center rounded-lg') ->toContain('flex shrink-0 items-center gap-1') ->and($switcher) ->toContain('group/team flex h-8 items-center') ->toContain('whitespace-nowrap text-[13px]') ->not->toContain('max-w-56 truncate text-[13px]'); }); it('allows more of the team name to display in the desktop breadcrumb', function () { $breadcrumb = file_get_contents(resource_path('views/components/top-breadcrumb.blade.php')); expect($breadcrumb) ->toContain('class="shrink-0" x-data="{ collapsed: false }"') ->toContain('
{$description}
") ->toContain('