AccessServiceTest.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. <?php
  2. namespace Tests\Unit\Services;
  3. use App\Models\Permission;
  4. use App\Models\Role;
  5. use App\Models\User;
  6. use App\Services\Access\AccessService;
  7. use Database\Seeders\RbacSeeder;
  8. use Illuminate\Foundation\Testing\RefreshDatabase;
  9. use Tests\TestCase;
  10. class AccessServiceTest extends TestCase
  11. {
  12. use RefreshDatabase;
  13. public function test_rbac_seeder_backfills_user_role_id(): void
  14. {
  15. $user = User::factory()->create(['role' => Role::MANAGER]);
  16. $this->seed(RbacSeeder::class);
  17. $user->refresh();
  18. $this->assertNotNull($user->role_id);
  19. $this->assertSame(Role::MANAGER, $user->roleModel->slug);
  20. }
  21. public function test_direct_admin_has_all_permissions(): void
  22. {
  23. $admin = User::factory()->create(['role' => Role::ADMIN]);
  24. $this->seed(RbacSeeder::class);
  25. $admin->refresh();
  26. $this->assertTrue(app(AccessService::class)->can($admin, 'catalog.delete'));
  27. $this->assertTrue(app(AccessService::class)->can($admin, 'catalog.fields.product_price.update'));
  28. }
  29. public function test_manager_has_seeded_permissions_but_not_admin_only_permissions(): void
  30. {
  31. $manager = User::factory()->create(['role' => Role::MANAGER]);
  32. $this->seed(RbacSeeder::class);
  33. $manager->refresh();
  34. $this->assertTrue(app(AccessService::class)->can($manager, 'catalog.view'));
  35. $this->assertTrue(app(AccessService::class)->can($manager, 'catalog.fields.product_price.view'));
  36. $this->assertFalse(app(AccessService::class)->can($manager, 'catalog.import'));
  37. $this->assertFalse(app(AccessService::class)->can($manager, 'catalog.update'));
  38. }
  39. public function test_role_deny_overrides_user_allow(): void
  40. {
  41. $this->seed(RbacSeeder::class);
  42. $permission = Permission::query()->where('slug', 'catalog.view')->firstOrFail();
  43. $role = Role::query()->create([
  44. 'slug' => 'deny_catalog',
  45. 'name' => 'Deny catalog',
  46. 'is_system' => false,
  47. 'is_active' => true,
  48. ]);
  49. $role->permissions()->sync([
  50. $permission->id => ['effect' => 'deny'],
  51. ]);
  52. $user = User::factory()->create(['role' => $role->slug, 'role_id' => $role->id]);
  53. $user->permissions()->sync([
  54. $permission->id => ['effect' => 'allow'],
  55. ]);
  56. app(AccessService::class)->bumpCacheVersion();
  57. $this->assertFalse(app(AccessService::class)->can($user, 'catalog.view'));
  58. }
  59. public function test_exact_route_permission_lookup_supports_dotted_route_names(): void
  60. {
  61. $this->assertSame(
  62. 'catalog.search',
  63. app(AccessService::class)->routePermission('product.search')
  64. );
  65. }
  66. public function test_user_deny_overrides_role_allow(): void
  67. {
  68. $manager = User::factory()->create(['role' => Role::MANAGER]);
  69. $this->seed(RbacSeeder::class);
  70. $manager->refresh();
  71. $permission = Permission::query()->where('slug', 'catalog.view')->firstOrFail();
  72. $manager->permissions()->syncWithoutDetaching([
  73. $permission->id => ['effect' => 'deny'],
  74. ]);
  75. app(AccessService::class)->bumpCacheVersion();
  76. $this->assertFalse(app(AccessService::class)->can($manager, 'catalog.view'));
  77. }
  78. public function test_assistant_head_has_materialized_admin_permissions_without_runtime_inheritance(): void
  79. {
  80. $assistantHead = User::factory()->create(['role' => Role::ASSISTANT_HEAD]);
  81. $this->seed(RbacSeeder::class);
  82. $assistantHead->refresh();
  83. $this->assertTrue($assistantHead->hasRole(Role::ADMIN));
  84. $this->assertTrue(app(AccessService::class)->can($assistantHead, 'maf_orders.delete'));
  85. }
  86. }