instance()->getTable()->getEmptyStateActions() as $action) { if ($action instanceof Action && $action->getName() === $name) { return $action; } } return null; } test('non-members are denied access to RestoreRun tenant routes (404)', function () { $tenant = Tenant::factory()->create(); $otherTenant = Tenant::factory()->create(); [$user] = createUserWithTenant($otherTenant, role: 'owner'); $this->actingAs($user) ->get(RestoreRunResource::getUrl('index', tenant: $tenant)) ->assertStatus(404); }); test('members without capability see RestoreRun actions disabled with standard tooltip and cannot execute', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'readonly'); $backupSet = BackupSet::factory()->create([ 'tenant_id' => $tenant->getKey(), 'status' => 'completed', ]); $restoreRun = RestoreRun::factory()->create([ 'tenant_id' => $tenant->getKey(), 'backup_set_id' => $backupSet->getKey(), 'status' => 'completed', 'deleted_at' => null, ]); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListRestoreRuns::class) ->assertTableActionDisabled('archive', $restoreRun) ->assertTableActionExists('archive', fn ($action): bool => $action->getTooltip() === UiTooltips::insufficientPermission(), $restoreRun) ->callTableAction('archive', $restoreRun); expect($restoreRun->fresh()->trashed())->toBeFalse(); }); test('members with capability can execute RestoreRun actions', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'owner'); $backupSet = BackupSet::factory()->create([ 'tenant_id' => $tenant->getKey(), 'status' => 'completed', ]); $restoreRun = RestoreRun::factory()->create([ 'tenant_id' => $tenant->getKey(), 'backup_set_id' => $backupSet->getKey(), 'status' => 'completed', 'deleted_at' => null, ]); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListRestoreRuns::class) ->assertTableActionEnabled('archive', $restoreRun) ->callTableAction('archive', $restoreRun); expect($restoreRun->fresh()->trashed())->toBeTrue(); }); test('restore runs list shows empty state create action enabled for members with manage capability', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'owner'); Filament::setTenant($tenant, true); $component = Livewire::actingAs($user) ->test(ListRestoreRuns::class) ->assertTableEmptyStateActionsExistInOrder(['create']); $action = getRestoreRunEmptyStateAction($component, 'create'); expect($action)->not->toBeNull(); expect($action->isVisible())->toBeTrue(); expect($action->isDisabled())->toBeFalse(); expect($action->getLabel())->toBe('New restore run'); }); test('restore runs list shows empty state create action disabled for members without manage capability', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'readonly'); Filament::setTenant($tenant, true); $component = Livewire::actingAs($user) ->test(ListRestoreRuns::class) ->assertTableEmptyStateActionsExistInOrder(['create']); $action = getRestoreRunEmptyStateAction($component, 'create'); expect($action)->not->toBeNull(); expect($action->isVisible())->toBeTrue(); expect($action->isDisabled())->toBeTrue(); expect($action->getTooltip())->toBe(UiTooltips::insufficientPermission()); }); test('readonly members can inspect restore-run history while mutations remain disabled', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'readonly'); $backupSet = BackupSet::factory()->create([ 'tenant_id' => $tenant->getKey(), 'status' => 'completed', ]); $restoreRun = RestoreRun::factory()->for($tenant)->for($backupSet)->completedOutcome()->create(); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListRestoreRuns::class) ->assertCanSeeTableRecords([$restoreRun]) ->assertTableActionDisabled('archive', $restoreRun); $this->actingAs($user) ->get(RestoreRunResource::getUrl('view', [ 'record' => (int) $restoreRun->getKey(), ], panel: 'tenant', tenant: $tenant)) ->assertOk(); }); test('in-scope members without restore-history view capability receive 403 on restore-run list and detail drillthroughs', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'owner'); $backupSet = BackupSet::factory()->create([ 'tenant_id' => $tenant->getKey(), 'status' => 'completed', ]); $restoreRun = RestoreRun::factory()->for($tenant)->for($backupSet)->failedOutcome()->create(); mock(CapabilityResolver::class, function ($mock) use ($tenant): void { $mock->shouldReceive('primeMemberships')->andReturnNull(); $mock->shouldReceive('isMember') ->andReturnUsing(static fn ($user, Tenant $resolvedTenant): bool => (int) $resolvedTenant->getKey() === (int) $tenant->getKey()); $mock->shouldReceive('can') ->andReturnUsing(static function ($user, Tenant $resolvedTenant, string $capability) use ($tenant): bool { expect((int) $resolvedTenant->getKey())->toBe((int) $tenant->getKey()); return match ($capability) { Capabilities::TENANT_VIEW => false, default => true, }; }); }); Filament::setTenant($tenant, true); $this->actingAs($user) ->get(RestoreRunResource::getUrl('index', tenant: $tenant)) ->assertForbidden(); $this->get(RestoreRunResource::getUrl('view', [ 'record' => (int) $restoreRun->getKey(), ], panel: 'tenant', tenant: $tenant)) ->assertForbidden(); });