Files
2026-10-09 08:21:06 +02:00

341 lines
10 KiB
PHP

<?php
use App\Events\Permission\Created;
use App\Events\Permission\Deleted;
use App\Events\Permission\Updated;
use App\Events\Role\PermissionsUpdated;
use App\Models\Permission;
use App\Models\Role;
use Facades\Tests\Setup\RoleFactory;
use Facades\Tests\Setup\UserFactory;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Inertia\Testing\AssertableInertia as Assert;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->artisan('db:seed');
$this->be(UserFactory::admin()->create());
});
test('permissions list', function () {
$permission = Permission::factory()->create();
$this->get('permissions')
->assertSee($permission->display_name);
});
test('only users with appropriate permissions can access the permissions list page', function () {
$roleA = RoleFactory::create();
$roleB = RoleFactory::withPermissions('permissions.manage')->create();
$userA = UserFactory::role($roleA)->create();
$userB = UserFactory::role($roleB)->create();
$this->actingAs($userA)->get('/permissions')->assertStatus(403);
$this->actingAs($userB)->get('/permissions')->assertOk();
});
test('permission list with roles', function () {
$permission = Permission::factory()->create();
$role = Role::first();
$role->permissions()->attach($permission->id);
$this->get('permissions')
->assertInertia(function (Assert $page) use ($permission, $role) {
$page->component('permissions/Index');
$props = $page->toArray()['props'];
$this->assertContains(
$permission->display_name,
collect($props['permissions'])->pluck('display_name')->all()
);
// The granted matrix replaces the roles[{id}][] checkbox names.
$this->assertContains($permission->id, $props['granted'][$role->id]);
});
});
test('save role permissions', function () {
$this->withoutExceptionHandling();
Event::fake([
PermissionsUpdated::class,
]);
$permission = Permission::factory()->create();
$role = Role::factory()->create();
$this->post('permissions/save', [
'roles' => [
$role->id => [$permission->id],
],
]);
$this->assertSessionHasSuccess('Permissions saved successfully.');
$this->assertDatabaseHas('permission_role', [
'role_id' => $role->id,
'permission_id' => $permission->id,
]);
Event::assertDispatched(PermissionsUpdated::class);
});
test('only users with appropriate permissions can save role permissions', function () {
$roleA = RoleFactory::create();
$roleB = RoleFactory::withPermissions('permissions.manage')->create();
$userA = UserFactory::role($roleA)->create();
$userB = UserFactory::role($roleB)->create();
$permission = Permission::factory()->create();
$role = Role::factory()->create();
$data = [$role->id => [$permission->id]];
$this->actingAs($userA)
->post('permissions/save', ['roles' => $data])
->assertStatus(403);
$this->assertDatabaseMissing('permission_role', [
'role_id' => $role->id,
'permission_id' => $permission->id,
]);
$this->actingAs($userB)
->post('permissions/save', ['roles' => $data]);
$this->assertDatabaseHas('permission_role', [
'role_id' => $role->id,
'permission_id' => $permission->id,
]);
});
test('save role permissions if no permission is selected for specific role', function () {
Event::fake([
PermissionsUpdated::class,
]);
$role1 = Role::factory()->create();
$permission1 = Permission::factory()->create();
$role1->permissions()->attach($permission1->id);
$role2 = Role::factory()->create();
$permission2 = Permission::factory()->create();
$role2->permissions()->attach($permission2->id);
$this->post('/permissions/save', [
'roles' => [
$role1->id => [$permission1->id],
],
]);
$this->assertSessionHasSuccess('Permissions saved successfully.');
$this->assertDatabaseHas('permission_role', [
'role_id' => $role1->id,
'permission_id' => $permission1->id,
]);
$this->assertDatabaseMissing('permission_role', [
'role_id' => $role2->id,
'permission_id' => $permission2->id,
]);
Event::assertDispatched(PermissionsUpdated::class);
});
test('create permission', function () {
$this->app->instance('middleware.disable', false);
Event::fake([
Created::class,
]);
$data = validPermissionParams();
$this->post('permissions', $data)
->assertRedirect('/permissions');
$this->assertSessionHasSuccess('Permission created successfully.');
$this->assertDatabaseHas('permissions', $data);
Event::assertDispatched(Created::class);
});
test('only users with appropriate permission can create new permissions', function () {
$roleA = RoleFactory::create();
$roleB = RoleFactory::withPermissions('permissions.manage')->create();
$userA = UserFactory::role($roleA)->create();
$userB = UserFactory::role($roleB)->create();
$data = validPermissionParams();
$this->actingAs($userA)
->post('permissions', $data)
->assertStatus(403);
$this->assertDatabaseMissing('permissions', $data);
$this->actingAs($userB)
->post('permissions', $data)
->assertRedirect('/permissions');
$this->assertDatabaseHas('permissions', $data);
});
test('permission name must have valid format', function () {
$this->app->instance('middleware.disable', false);
$data = validPermissionParams();
$response = $this->post('permissions', validPermissionParams(['name' => 'invalid name']));
$response->assertSessionHasErrors('name');
$this->assertDatabaseMissing('permissions', $data);
$response = $this->post('permissions', validPermissionParams(['name' => 'invalid*name']));
$response->assertSessionHasErrors('name');
$this->assertDatabaseMissing('permissions', $data);
});
test('update permission', function () {
$this->withoutExceptionHandling();
Event::fake([
Updated::class,
]);
$permission = Permission::factory()->create();
$this->get("permissions/{$permission->id}/edit")
->assertOk()
->assertSee($permission->id)
->assertSee($permission->name)
->assertSee($permission->display_name);
$data = validPermissionParams();
$this->put("permissions/{$permission->id}", $data);
$this->assertSessionHasSuccess('Permission updated successfully.');
$this->assertDatabaseHas('permissions', $data + ['id' => $permission->id]);
Event::assertDispatched(Updated::class);
});
test('only users with appropriate permission can update existing permissions', function () {
$roleA = RoleFactory::create();
$roleB = RoleFactory::withPermissions('permissions.manage')->create();
$userA = UserFactory::role($roleA)->create();
$userB = UserFactory::role($roleB)->create();
$permission = Permission::factory()->create();
$data = validPermissionParams();
$this->actingAs($userA)
->put("permissions/{$permission->id}", $data)
->assertStatus(403);
$this->assertEquals($permission->toArray(), $permission->fresh()->toArray());
$this->actingAs($userB)
->put("permissions/{$permission->id}", $data)
->assertRedirect('/permissions');
$permission->refresh();
$this->assertEquals($permission->name, $data['name']);
$this->assertEquals($permission->display_name, $data['display_name']);
$this->assertEquals($permission->description, $data['description']);
});
test('removable attribute cannot be changed on update', function () {
$permission = Permission::factory()->create(['removable' => false]);
$data = validPermissionParams(['removable' => true]);
$this->put("permissions/{$permission->id}", $data);
$permission->refresh();
$this->assertEquals($permission->name, $data['name']);
$this->assertEquals($permission->display_name, $data['display_name']);
$this->assertEquals($permission->description, $data['description']);
$this->assertFalse($permission->removable);
});
test('permission name must have valid format while updating the permission', function () {
$permission = Permission::factory()->create(['name' => 'foo']);
$response = $this->put('permissions/'.$permission->id, validPermissionParams(['name' => 'invalid name']));
$response->assertSessionHasErrors('name');
$this->assertEquals('foo', $permission->fresh()->name);
$response = $this->put('permissions/'.$permission->id, validPermissionParams(['name' => 'invalid*name']));
$response->assertSessionHasErrors('name');
$this->assertEquals('foo', $permission->fresh()->name);
});
test('delete permission', function () {
Event::fake([
Deleted::class,
]);
$permission = Permission::factory()->create();
$this->delete(route('permissions.destroy', $permission->id))
->assertRedirect('/permissions');
$this->assertSessionHasSuccess('Permission deleted successfully.');
$this->assertDatabaseMissing('permissions', ['id' => $permission->id]);
Event::assertDispatched(Deleted::class);
});
test('only users with appropriate permission can delete permissions', function () {
$roleA = RoleFactory::create();
$roleB = RoleFactory::withPermissions('permissions.manage')->create();
$userA = UserFactory::role($roleA)->create();
$userB = UserFactory::role($roleB)->create();
$permission = Permission::factory()->create();
$this->actingAs($userA)
->delete("permissions/{$permission->id}")
->assertStatus(403);
$this->assertNotNull($permission->fresh());
$this->actingAs($userB)
->delete("permissions/{$permission->id}")
->assertRedirect('/permissions');
$this->assertNull($permission->fresh());
});
test('non removable permissions cannot be removed', function () {
$permission = Permission::factory()->create(['removable' => false]);
$this->delete(route('permissions.destroy', $permission->id))
->assertStatus(404);
$this->assertNotNull($permission->fresh());
});
function validPermissionParams(array $override = []): array
{
return array_merge([
'name' => 'foo_permission',
'display_name' => 'Foo Permission',
'description' => 'the description',
], $override);
}