create(); [$user] = createUserWithTenant(); $action = Action::make('test')->action(fn () => null); UiEnforcement::forAction($action) ->requireCapability(Capabilities::TENANT_VIEW) ->apply(); $this->actingAs($user); $action->record($tenant); expect($action->isHidden())->toBeTrue(); }); it('disables actions with the standard tooltip for members without the capability', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'readonly'); $action = Action::make('test')->action(fn () => null); UiEnforcement::forAction($action) ->requireCapability(Capabilities::TENANT_SYNC) ->apply(); $this->actingAs($user); $action->record($tenant); expect($action->isHidden())->toBeFalse(); expect($action->isDisabled())->toBeTrue(); expect($action->getTooltip())->toBe(UiTooltips::insufficientPermission()); }); it('enables actions for members with the capability', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'owner'); $action = Action::make('test')->action(fn () => null); UiEnforcement::forAction($action) ->requireCapability(Capabilities::TENANT_SYNC) ->apply(); $this->actingAs($user); $action->record($tenant); expect($action->isHidden())->toBeFalse(); expect($action->isDisabled())->toBeFalse(); expect($action->getTooltip())->toBeNull(); }); it('preserveVisibility combines existing visibility with membership checks', function () { $tenant = Tenant::factory()->create(); [$user] = createUserWithTenant($tenant, role: 'owner'); $action = Action::make('test') ->action(fn () => null) ->visible(fn (): bool => false); UiEnforcement::forAction($action) ->preserveVisibility() ->requireCapability(Capabilities::TENANT_VIEW) ->apply(); $this->actingAs($user); $action->record($tenant); expect($action->isHidden())->toBeTrue(); }); it('disables bulk actions for mixed-authorization selections (capability preflight)', function () { $tenantA = Tenant::factory()->create(); $tenantB = Tenant::factory()->create(); [$user] = createUserWithTenant($tenantA, role: 'owner'); $user->tenants()->syncWithoutDetaching([ $tenantB->getKey() => ['role' => 'readonly'], ]); $action = Action::make('test')->action(fn () => null); $enforcement = UiEnforcement::forAction($action) ->requireCapability(Capabilities::TENANT_SYNC); expect($enforcement->bulkSelectionIsAuthorized($user, collect([$tenantA, $tenantB])))->toBeFalse(); $user->tenants()->syncWithoutDetaching([ $tenantB->getKey() => ['role' => 'owner'], ]); expect($enforcement->bulkSelectionIsAuthorized($user, collect([$tenantA, $tenantB])))->toBeTrue(); });