seed(\Database\Seeders\RolesSeeder::class); $tenant = Tenant::firstOrCreate( ['name' => 'Test Schule'], ['type' => 'school', 'active' => true] ); $this->user = User::withoutGlobalScopes()->create([ 'name' => 'Settings Nav Tester', 'email' => 'sn@test.example', 'tenant_id' => $tenant->id, 'password' => bcrypt('password'), ]); $role = Role::where('name', 'school-admin')->first(); DB::table('role_user')->insert([ 'user_id' => $this->user->id, 'role_id' => $role->id, 'created_at' => now(), 'updated_at' => now(), ]); $this->actingAs($this->user); }); it('default section is profile, server-rendered (no Alpine flicker)', function () { Livewire::test(SettingsIndex::class) ->assertSet('section', 'profile') ->assertSee('Profil') ->assertSeeHtml('data-section="profile"') ->assertDontSeeHtml('data-section="language"'); }); it('?section=security URL param hydrates initial state', function () { Livewire::withQueryParams(['section' => 'security']) ->test(SettingsIndex::class) ->assertSet('section', 'security') ->assertSeeHtml('data-section="security"'); }); it('invalid section param falls back to profile', function () { Livewire::withQueryParams(['section' => 'evil']) ->test(SettingsIndex::class) ->assertSet('section', 'profile'); }); it('setSection only accepts allowed values', function () { Livewire::test(SettingsIndex::class) ->call('setSection', 'security') ->assertSet('section', 'security') ->call('setSection', 'malicious') ->assertSet('section', 'security'); }); it('only one section card renders at a time (no flicker)', function () { $html = Livewire::test(SettingsIndex::class)->html(); // Profile renders, others do NOT (server-side conditional) expect($html)->toContain('data-section="profile"'); expect($html)->not->toContain('data-section="language"'); expect($html)->not->toContain('data-section="security"'); expect($html)->not->toContain('data-section="notifications"'); expect($html)->not->toContain('data-section="danger"'); }); it('sub-nav uses server-rendered active state (aria-current)', function () { $html = Livewire::test(SettingsIndex::class)->html(); expect($html)->toMatch('/data-testid="settings-nav-profile"[^>]*aria-current="page"|aria-current="page"[^>]*data-testid="settings-nav-profile"/'); }); it('sub-nav buttons NOT using :class Alpine bindings (no client-side flicker)', function () { $tpl = file_get_contents(base_path('resources/views/livewire/settings/index.blade.php')); // Sub-nav must use plain class string (server-side), not :class= for active state expect($tpl)->not->toContain(':class="activeSection ==='); });