|
266 | 266 | expect($role->hasCapability('another-capability'))->toBeTrue(); |
267 | 267 | }); |
268 | 268 |
|
| 269 | + it('syncs capability-permission relationships from Capability attributes', function () { |
| 270 | + $this->enableCapabilities(); |
| 271 | + config(['mandate.code_first.enabled' => true]); |
| 272 | + config(['mandate.code_first.paths.permissions' => __DIR__.'/../Fixtures/CodeFirst']); |
| 273 | + |
| 274 | + Mandate::sync(permissions: true); |
| 275 | + |
| 276 | + $capabilityClass = config('mandate.models.capability'); |
| 277 | + |
| 278 | + // UserPermissions has class-level #[Capability('user-management')] |
| 279 | + // So user:view, user:edit, user:delete should have user-management capability |
| 280 | + $userManagement = $capabilityClass::where('name', 'user-management')->first(); |
| 281 | + expect($userManagement)->not->toBeNull(); |
| 282 | + expect($userManagement->hasPermission('user:view'))->toBeTrue(); |
| 283 | + expect($userManagement->hasPermission('user:edit'))->toBeTrue(); |
| 284 | + expect($userManagement->hasPermission('user:delete'))->toBeTrue(); |
| 285 | + |
| 286 | + // user:delete also has constant-level #[Capability('admin-only')] |
| 287 | + $adminOnly = $capabilityClass::where('name', 'admin-only')->first(); |
| 288 | + expect($adminOnly)->not->toBeNull(); |
| 289 | + expect($adminOnly->hasPermission('user:delete'))->toBeTrue(); |
| 290 | + |
| 291 | + // Verify pivot table records |
| 292 | + $pivotTable = config('mandate.tables.capability_permission', 'capability_permission'); |
| 293 | + $pivotCount = Illuminate\Support\Facades\DB::table($pivotTable)->count(); |
| 294 | + expect($pivotCount)->toBe(4); // 3 for user-management + 1 for admin-only |
| 295 | + }); |
| 296 | + |
| 297 | + it('syncs all discovered permissions when using seed with code-first enabled', function () { |
| 298 | + config(['mandate.code_first.enabled' => true]); |
| 299 | + config(['mandate.code_first.paths.permissions' => __DIR__.'/../Fixtures/CodeFirst']); |
| 300 | + config(['mandate.code_first.paths.roles' => __DIR__.'/../Fixtures/CodeFirst']); |
| 301 | + |
| 302 | + // Only assign one permission, but all should be synced |
| 303 | + config(['mandate.assignments' => [ |
| 304 | + 'partial-role' => [ |
| 305 | + 'permissions' => ['article:view'], |
| 306 | + ], |
| 307 | + ]]); |
| 308 | + |
| 309 | + Mandate::sync(seed: true); |
| 310 | + |
| 311 | + // All permissions from code-first should be synced, not just those in assignments |
| 312 | + expect(Permission::where('name', 'article:view')->exists())->toBeTrue(); |
| 313 | + expect(Permission::where('name', 'article:create')->exists())->toBeTrue(); |
| 314 | + expect(Permission::where('name', 'article:edit')->exists())->toBeTrue(); |
| 315 | + expect(Permission::where('name', 'article:delete')->exists())->toBeTrue(); |
| 316 | + |
| 317 | + // But only article:view should be assigned to the role |
| 318 | + $role = Role::where('name', 'partial-role')->first(); |
| 319 | + expect($role->hasPermission('article:view'))->toBeTrue(); |
| 320 | + expect($role->hasPermission('article:create'))->toBeFalse(); |
| 321 | + }); |
| 322 | + |
269 | 323 | it('respects guard filter when seeding', function () { |
270 | 324 | config(['mandate.code_first.enabled' => false]); |
271 | 325 |
|
|
0 commit comments