create(); $role = Role::firstOrCreate(['name' => 'ROLE_ADMIN'], ['color' => '#111111']); $admin->roles()->attach($role); return $admin; } it('forbids non-admin role access', function (): void { $user = User::factory()->create(); Sanctum::actingAs($user); $response = $this->getJson('/api/roles'); $response->assertStatus(403); }); it('creates normalized roles as admin', function (): void { $admin = makeAdminForRoles(); Sanctum::actingAs($admin); $response = $this->postJson('/api/roles', [ 'name' => 'moderator', 'color' => '#abcdef', ]); $response->assertStatus(201); $response->assertJsonFragment([ 'name' => 'ROLE_MODERATOR', 'color' => '#abcdef', ]); $this->assertDatabaseHas('roles', [ 'name' => 'ROLE_MODERATOR', ]); }); it('prevents renaming core roles', function (): void { $admin = makeAdminForRoles(); $core = Role::firstOrCreate(['name' => 'ROLE_ADMIN'], ['color' => '#111111']); Sanctum::actingAs($admin); $response = $this->patchJson("/api/roles/{$core->id}", [ 'name' => 'ROLE_SUPER', 'color' => '#123456', ]); $response->assertStatus(422); $response->assertJsonFragment(['message' => 'Core roles cannot be renamed.']); }); it('prevents deleting core roles', function (): void { $admin = makeAdminForRoles(); $core = Role::firstOrCreate(['name' => 'ROLE_USER'], ['color' => '#111111']); Sanctum::actingAs($admin); $response = $this->deleteJson("/api/roles/{$core->id}"); $response->assertStatus(422); $response->assertJsonFragment(['message' => 'Core roles cannot be deleted.']); }); it('prevents deleting roles assigned to users', function (): void { $admin = makeAdminForRoles(); $role = Role::create(['name' => 'ROLE_HELPER', 'color' => '#222222']); $user = User::factory()->create(); $user->roles()->attach($role); Sanctum::actingAs($admin); $response = $this->deleteJson("/api/roles/{$role->id}"); $response->assertStatus(422); $response->assertJsonFragment(['message' => 'Role is assigned to users.']); }); it('deletes non-core roles without assignments', function (): void { $admin = makeAdminForRoles(); $role = Role::create(['name' => 'ROLE_CUSTOM', 'color' => '#333333']); Sanctum::actingAs($admin); $response = $this->deleteJson("/api/roles/{$role->id}"); $response->assertStatus(204); $this->assertDatabaseMissing('roles', ['id' => $role->id]); });