actingAs($user) ->get("/admin/tenants/{$tenant->external_id}/required-permissions"); $response->assertOk(); // Workspace nav items from configureNavigationForRequest() workspace builder $response->assertSee('Operations', false); $response->assertSee('Audit Log', false); }); it('does not render tenant navigation items on the required permissions page', function (): void { [$user, $tenant] = createUserWithTenant(role: 'readonly'); $response = $this->actingAs($user) ->get("/admin/tenants/{$tenant->external_id}/required-permissions"); $response->assertOk(); // Tenant-scoped nav groups/items must NOT appear $response->assertDontSee('>Inventory', false); $response->assertDontSee('>Backups & Restore', false); }); it('shows workspace sidebar when navigating directly via URL', function (): void { [$user, $tenant] = createUserWithTenant(role: 'readonly'); $response = $this->actingAs($user) ->get("/admin/tenants/{$tenant->external_id}/required-permissions"); $response->assertOk(); // Workspace nav present (Operations is always visible in workspace nav) $response->assertSee('Operations', false); $response->assertSee('Audit Log', false); // Tenant nav absent $response->assertDontSee('>Directory', false); $response->assertDontSee('>Governance', false); }); it('returns 404 for non-workspace-members after middleware change (FR-002 regression guard)', function (): void { $user = User::factory()->create(); $workspace = Workspace::factory()->create(); $tenant = Tenant::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), ]); // User is NOT a workspace member — no WorkspaceMembership created $this->actingAs($user) ->withSession([ WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(), ]) ->get("/admin/tenants/{$tenant->external_id}/required-permissions") ->assertNotFound(); }); it('returns 404 for workspace members without tenant entitlement after middleware change (FR-002 regression guard)', function (): void { $user = User::factory()->create(); $workspace = Workspace::factory()->create(); $tenant = Tenant::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), ]); WorkspaceMembership::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'user_id' => (int) $user->getKey(), 'role' => 'owner', ]); // User IS a workspace member but NOT entitled to this tenant $this->actingAs($user) ->withSession([ WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(), ]) ->get("/admin/tenants/{$tenant->external_id}/required-permissions") ->assertNotFound(); }); /* |-------------------------------------------------------------------------- | T002 — Regression: tenant-scoped pages still show tenant sidebar |-------------------------------------------------------------------------- | | Verifies that the middleware change does NOT affect tenant-scoped pages. | Pages under /admin/t/{tenant}/ must continue to show tenant sidebar. | */ it('still renders tenant sidebar on tenant-scoped pages (regression guard)', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); // Use the tenant dashboard — a known tenant-scoped URL $response = $this->actingAs($user) ->get("/admin/t/{$tenant->external_id}"); $response->assertOk(); // Tenant-scoped nav groups MUST be present on tenant pages (Inventory group) $response->assertSee('Inventory', false); }); /* |-------------------------------------------------------------------------- | T007 — Context bar: tenant name is visible on the page |-------------------------------------------------------------------------- | | The page's $scopedTenant is resolved from the route param via | resolveScopedTenant() — NOT from Filament::getTenant(). So the tenant | data is available even though Filament::setTenant() is skipped. | Verify the page renders successfully and that the tenant's data is used. | */ it('resolves scoped tenant correctly with workspace sidebar (context bar / US2)', function (): void { [$user, $tenant] = createUserWithTenant(role: 'readonly'); $response = $this->actingAs($user) ->get("/admin/tenants/{$tenant->external_id}/required-permissions"); $response->assertOk(); // The page resolves $scopedTenant from route param and uses it for data display. // Verify the page title is present (static title: "Required permissions") $response->assertSee('Required permissions', false); // The page uses $scopedTenant for links (e.g., "Re-run verification" links back to TenantResource) // If $scopedTenant were null, the page would abort(404) in mount(). // The fact that we get 200 proves $scopedTenant resolved correctly despite setTenant() being skipped. // Workspace nav present (sidebar fix working) $response->assertSee('Operations', false); // Tenant nav absent (sidebar fix working) $response->assertDontSee('>Inventory', false); });