create(); $workspaceA = Workspace::factory()->create(['name' => 'Workspace A']); $workspaceB = Workspace::factory()->create(['name' => 'Workspace B']); WorkspaceMembership::factory()->create([ 'workspace_id' => $workspaceA->getKey(), 'user_id' => $user->getKey(), 'role' => 'owner', ]); WorkspaceMembership::factory()->create([ 'workspace_id' => $workspaceB->getKey(), 'user_id' => $user->getKey(), 'role' => 'owner', ]); $tenantA = Tenant::factory()->create([ 'workspace_id' => $workspaceA->getKey(), 'external_id' => '11111111-1111-1111-1111-111111111111', 'tenant_id' => '11111111-1111-1111-1111-111111111111', 'name' => 'Tenant A', 'status' => 'active', ]); $tenantB = Tenant::factory()->create([ 'workspace_id' => $workspaceB->getKey(), 'external_id' => '22222222-2222-2222-2222-222222222222', 'tenant_id' => '22222222-2222-2222-2222-222222222222', 'name' => 'Tenant B', 'status' => 'active', ]); TenantMembership::query()->create([ 'tenant_id' => $tenantA->getKey(), 'user_id' => $user->getKey(), 'role' => 'owner', 'source' => 'manual', 'source_ref' => null, 'created_by_user_id' => null, ]); TenantMembership::query()->create([ 'tenant_id' => $tenantB->getKey(), 'user_id' => $user->getKey(), 'role' => 'owner', 'source' => 'manual', 'source_ref' => null, 'created_by_user_id' => null, ]); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $workspaceA->getKey()]) ->get(route('filament.admin.resources.tenants.index', filamentTenantRouteParams($tenantA))) ->assertOk() ->assertSee('Tenant A') ->assertDontSee('Tenant B'); }); it('keeps tenant list defaults calm and persists list state in-session', function (): void { [$user] = createUserWithTenant(role: 'owner'); $this->actingAs($user); Filament::setTenant(null, true); $component = Livewire::actingAs($user) ->test(\App\Filament\Resources\TenantResource\Pages\ListTenants::class) ->assertTableEmptyStateActionsExistInOrder(['add_tenant']) ->searchTable('Tenant') ->call('sortTable', 'name', 'desc') ->set('tableFilters.environment.value', 'prod'); $table = $component->instance()->getTable(); expect($table->getPaginationPageOptions())->toBe(\App\Support\Filament\TablePaginationProfiles::resource()); expect($table->getEmptyStateHeading())->toBe('No tenants connected'); expect($table->getColumn('name')?->isSearchable())->toBeTrue(); expect($table->getColumn('name')?->isSortable())->toBeTrue(); expect($table->getColumn('tenant_id')?->isToggledHiddenByDefault())->toBeTrue(); expect($table->getColumn('domain')?->isToggledHiddenByDefault())->toBeTrue(); expect(count($table->getVisibleColumns()))->toBeLessThanOrEqual(7); expect(session()->get($component->instance()->getTableSearchSessionKey()))->toBe('Tenant'); expect(session()->get($component->instance()->getTableSortSessionKey()))->toBe('name:desc'); Livewire::actingAs($user) ->test(\App\Filament\Resources\TenantResource\Pages\ListTenants::class) ->assertSet('tableSearch', 'Tenant') ->assertSet('tableSort', 'name:desc') ->assertSet('tableFilters.environment.value', 'prod'); }); it('keeps posture filters scoped to visible workspace tenants only', function (): void { $visibleTenant = Tenant::factory()->create(['status' => 'active']); [$user, $visibleTenant] = createUserWithTenant($visibleTenant, role: 'owner', workspaceRole: 'readonly'); workspaceOverviewSeedQuietTenantTruth($visibleTenant); workspaceOverviewSeedHealthyBackup($visibleTenant, [ 'completed_at' => now()->subMinutes(10), ]); $hiddenRecoveryTenant = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $visibleTenant->workspace_id, 'name' => 'Hidden Recovery Tenant', ]); workspaceOverviewSeedQuietTenantTruth($hiddenRecoveryTenant); workspaceOverviewSeedHealthyBackup($hiddenRecoveryTenant, [ 'completed_at' => now()->subMinutes(9), ]); $hiddenBackupTenant = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $visibleTenant->workspace_id, 'name' => 'Hidden Degraded Tenant', ]); workspaceOverviewSeedQuietTenantTruth($hiddenBackupTenant); workspaceOverviewSeedHealthyBackup($hiddenBackupTenant, [ 'completed_at' => now()->subMinutes(8), ], [ 'payload' => [], 'metadata' => [ 'source' => 'metadata_only', 'assignments_fetch_failed' => true, ], 'assignments' => [], ]); $this->actingAs($user); session()->put(WorkspaceContext::SESSION_KEY, (int) $visibleTenant->workspace_id); Filament::setTenant(null, true); $recoveryFiltered = Livewire::actingAs($user) ->test(ListTenants::class) ->filterTable('recovery_evidence', ['unvalidated']); expect($recoveryFiltered->instance()->getFilteredTableQuery()?->pluck('tenants.name')->all()) ->toBe([(string) $visibleTenant->name]); $backupFiltered = Livewire::actingAs($user) ->test(ListTenants::class) ->filterTable('backup_posture', [TenantBackupHealthAssessment::POSTURE_DEGRADED]); expect($backupFiltered->instance()->getFilteredTableQuery()?->pluck('tenants.name')->all()) ->toBe([]); });