'manage access rights', 'guard_name' => 'web']); Permission::firstOrCreate(['name' => 'view access rights', 'guard_name' => 'web']); $user->givePermissionTo($perm); } test('guest cannot access roles index', function () { $this->get('/roles')->assertRedirect('/login'); }); test('authenticated user without permission gets 403 on roles index', function () { $user = User::factory()->create(); $this->actingAs($user)->get('/roles')->assertForbidden(); }); test('user with manage access rights can store a new role', function () { $user = User::factory()->create(); grantManageAccessRights($user); $p = Permission::firstOrCreate(['name' => 'view dashboard', 'guard_name' => 'web']); $response = $this->actingAs($user) ->postJson('/roles', [ 'name' => 'editor-role', 'guard_name' => 'web', 'permissions' => [$p->id], ]); $response->assertOk()->assertJson(['success' => true]); $this->assertDatabaseHas('roles', ['name' => 'editor-role']); $role = Role::where('name', 'editor-role')->first(); expect($role->hasPermissionTo('view dashboard'))->toBeTrue(); }); test('store rejects duplicate role name', function () { $user = User::factory()->create(); grantManageAccessRights($user); $p = Permission::firstOrCreate(['name' => 'view dashboard', 'guard_name' => 'web']); Role::create(['name' => 'dup-role', 'guard_name' => 'web']); $response = $this->actingAs($user) ->postJson('/roles', [ 'name' => 'dup-role', 'guard_name' => 'web', 'permissions' => [$p->id], ]); $response->assertStatus(422); }); test('store rejects empty permissions array', function () { $user = User::factory()->create(); grantManageAccessRights($user); $response = $this->actingAs($user) ->postJson('/roles', [ 'name' => 'no-perm-role', 'guard_name' => 'web', 'permissions' => [], ]); $response->assertStatus(422); }); test('store rejects invalid characters in role name', function () { $user = User::factory()->create(); grantManageAccessRights($user); $p = Permission::firstOrCreate(['name' => 'view dashboard', 'guard_name' => 'web']); $response = $this->actingAs($user) ->postJson('/roles', [ 'name' => 'role with space!', 'guard_name' => 'web', 'permissions' => [$p->id], ]); $response->assertStatus(422); }); test('update replaces role permissions', function () { $user = User::factory()->create(); grantManageAccessRights($user); $p1 = Permission::firstOrCreate(['name' => 'view dashboard', 'guard_name' => 'web']); $p2 = Permission::firstOrCreate(['name' => 'view user directory', 'guard_name' => 'web']); $role = Role::create(['name' => 'original-role', 'guard_name' => 'web']); $role->givePermissionTo('view dashboard'); $response = $this->actingAs($user) ->putJson("/roles/{$role->id}", [ 'name' => 'renamed-role', 'guard_name' => 'web', 'permissions' => [$p2->id], ]); $response->assertOk(); $role->refresh(); expect($role->name)->toBe('renamed-role'); expect($role->hasPermissionTo('view user directory'))->toBeTrue(); expect($role->hasPermissionTo('view dashboard'))->toBeFalse(); }); test('toggleStatus activates and deactivates role', function () { $user = User::factory()->create(); grantManageAccessRights($user); $role = Role::create(['name' => 'toggleable', 'guard_name' => 'web', 'is_active' => true]); $this->actingAs($user) ->postJson('/roles/toggle-status', ['id' => $role->id, 'status' => 'deactivate']) ->assertOk(); expect((bool) $role->fresh()->is_active)->toBeFalse(); $this->actingAs($user) ->postJson('/roles/toggle-status', ['id' => $role->id, 'status' => 'activate']) ->assertOk(); expect((bool) $role->fresh()->is_active)->toBeTrue(); }); test('destroy soft deletes role when no users assigned', function () { $user = User::factory()->create(); grantManageAccessRights($user); $role = Role::create(['name' => 'doomed', 'guard_name' => 'web']); $this->actingAs($user) ->deleteJson("/roles/{$role->id}") ->assertOk(); expect(Role::withTrashed()->find($role->id)->trashed())->toBeTrue(); }); test('destroy blocks deletion when role is still assigned to a user', function () { $admin = User::factory()->create(); grantManageAccessRights($admin); $role = Role::create(['name' => 'in-use', 'guard_name' => 'web']); $victim = User::factory()->create(); $victim->assignRole($role); $this->actingAs($admin) ->deleteJson("/roles/{$role->id}") ->assertStatus(422) ->assertJson(['success' => false]); expect(Role::find($role->id))->not->toBeNull(); }); test('restore brings back a soft-deleted role', function () { $user = User::factory()->create(); grantManageAccessRights($user); $role = Role::create(['name' => 'restorable', 'guard_name' => 'web']); $role->delete(); $this->actingAs($user) ->postJson("/roles/{$role->id}/restore") ->assertOk(); expect(Role::find($role->id)->trashed())->toBeFalse(); }); test('forceDelete permanently removes role', function () { $user = User::factory()->create(); grantManageAccessRights($user); $role = Role::create(['name' => 'gone-forever', 'guard_name' => 'web']); $role->delete(); $this->actingAs($user) ->deleteJson("/roles/{$role->id}/force") ->assertOk(); expect(Role::withTrashed()->find($role->id))->toBeNull(); }); test('forceDelete blocks when role has users assigned', function () { $admin = User::factory()->create(); grantManageAccessRights($admin); $role = Role::create(['name' => 'sticky', 'guard_name' => 'web']); $victim = User::factory()->create(); $victim->assignRole($role); $this->actingAs($admin) ->deleteJson("/roles/{$role->id}/force") ->assertStatus(422); expect(Role::find($role->id))->not->toBeNull(); });