diff --git a/app/Http/Controllers/Web/OrganizationController.php b/app/Http/Controllers/Web/OrganizationController.php index ed5e8c71..7969eb82 100644 --- a/app/Http/Controllers/Web/OrganizationController.php +++ b/app/Http/Controllers/Web/OrganizationController.php @@ -55,8 +55,8 @@ class OrganizationController extends Controller return $currency->getName(); }, ISOCurrencyProvider::getInstance()->getAvailableCurrencies()), 'permissions' => [ - 'canDeleteTeam' => true, - 'canUpdateTeam' => true, + 'canDeleteTeam' => $this->hasPermission($organization, 'organizations:delete'), + 'canUpdateTeam' => $this->hasPermission($organization, 'organizations:update'), ], ]); } diff --git a/e2e/organization.spec.ts b/e2e/organization.spec.ts index a26ef4c8..7ac9cffe 100644 --- a/e2e/organization.spec.ts +++ b/e2e/organization.spec.ts @@ -526,6 +526,9 @@ test.describe('Admin Organization Settings Access', () => { // Save buttons should be visible (admin can update) await expect(admin.page.getByRole('button', { name: 'Save' }).first()).toBeVisible(); + // The Organization Name input is editable (admin can update) + await expect(admin.page.getByLabel('Organization Name')).toBeEnabled(); + // Delete organization should NOT be visible (owner only) await expect( admin.page.getByRole('heading', { name: 'Delete Organization' }) @@ -546,6 +549,10 @@ test.describe('Employee Organization Settings Restrictions', () => { employee.page.getByRole('heading', { name: 'Organization Name', level: 3 }) ).toBeVisible({ timeout: 10000 }); + // The name and currency inputs are rendered but disabled (employee cannot update) + await expect(employee.page.getByLabel('Organization Name')).toBeDisabled(); + await expect(employee.page.getByLabel('Currency')).toBeDisabled(); + // Editable settings sections should NOT be visible await expect( employee.page.getByRole('heading', { name: 'Billable Rate', level: 3 }) @@ -559,5 +566,10 @@ test.describe('Employee Organization Settings Restrictions', () => { // Save button should not be visible (employee cannot update) await expect(employee.page.getByRole('button', { name: 'Save' })).not.toBeVisible(); + + // Delete organization should NOT be visible (owner only) + await expect( + employee.page.getByRole('heading', { name: 'Delete Organization' }) + ).not.toBeVisible(); }); }); diff --git a/resources/js/Pages/Teams/Show.vue b/resources/js/Pages/Teams/Show.vue index f1a42c86..33535287 100644 --- a/resources/js/Pages/Teams/Show.vue +++ b/resources/js/Pages/Teams/Show.vue @@ -53,7 +53,7 @@ onMounted(async () => { - diff --git a/tests/Unit/Endpoint/Web/OrganizationEndpointTest.php b/tests/Unit/Endpoint/Web/OrganizationEndpointTest.php index a9485f80..24b0750e 100644 --- a/tests/Unit/Endpoint/Web/OrganizationEndpointTest.php +++ b/tests/Unit/Endpoint/Web/OrganizationEndpointTest.php @@ -4,12 +4,14 @@ declare(strict_types=1); namespace Tests\Unit\Endpoint\Web; +use App\Enums\Role; use App\Http\Controllers\Web\OrganizationController; use App\Models\Organization; use App\Models\OrganizationInvitation; use App\Models\User; use Inertia\Testing\AssertableInertia as Assert; use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; #[CoversClass(OrganizationController::class)] class OrganizationEndpointTest extends EndpointTestAbstract @@ -65,8 +67,37 @@ class OrganizationEndpointTest extends EndpointTestAbstract ->where('team.owner.name', $data->owner->name) ->has('team.owner.profile_photo_url') ->has('currencies') - ->where('permissions.canDeleteTeam', true) - ->where('permissions.canUpdateTeam', true) + ); + } + + /** + * @return array + */ + public static function showPermissionsPerRoleProvider(): array + { + return [ + 'owner can update and delete' => ['role' => Role::Owner, 'canUpdateTeam' => true, 'canDeleteTeam' => true], + 'admin can update but not delete' => ['role' => Role::Admin, 'canUpdateTeam' => true, 'canDeleteTeam' => false], + 'employee can neither update nor delete' => ['role' => Role::Employee, 'canUpdateTeam' => false, 'canDeleteTeam' => false], + ]; + } + + #[DataProvider('showPermissionsPerRoleProvider')] + public function test_organization_show_returns_permissions_based_on_role(Role $role, bool $canUpdateTeam, bool $canDeleteTeam): void + { + // Arrange + $data = $this->createUserWithRole($role); + $this->actingAs($data->user); + + // Act + $response = $this->get(route('organizations.show', [$data->organization->getKey()])); + + // Assert + $response->assertOk(); + $response->assertInertia(fn (Assert $page) => $page + ->component('Teams/Show') + ->where('permissions.canUpdateTeam', $canUpdateTeam) + ->where('permissions.canDeleteTeam', $canDeleteTeam) ); }