permissionMatrix() as $label => $case) { /** @var User $actor */ $actor = $case['actor']; $response = $this->requestAs($actor, $case['method'], $case['path'], $case['payload'] ?? []); $this->assertStatusIn($response, $case['allowed_statuses'], $label); $this->assertNoServerError($response, $label); } } public function test_admin_only_mutations_are_not_available_to_lower_roles(): void { foreach ($this->adminOnlyMutations() as [$method, $path, $payload]) { foreach ([$this->parent, $this->teacher, $this->studentUser] as $actor) { $response = $this->requestAs($actor, $method, $path, $payload); $this->assertStatusIn($response, [302, 401, 403, 404, 405, 419, 422], "$method $path denied to {$actor->id}"); $this->assertNoServerError($response, "$method $path denied to {$actor->id}"); } } } public function test_student_role_cannot_access_parent_teacher_or_admin_portals(): void { foreach ($this->studentForbiddenPaths() as $path) { $response = $this->requestAs($this->studentUser, 'GET', $path); $this->assertStatusIn($response, [302, 401, 403, 404, 405, 419, 422], "student forbidden $path"); $this->assertNoServerError($response, "student forbidden $path"); } } /** @return array,allowed_statuses:list}> */ private function permissionMatrix(): array { return [ 'admin can reach users index' => ['actor' => $this->admin, 'method' => 'GET', 'path' => 'api/v1/users', 'allowed_statuses' => [200, 204, 302, 401, 403, 404, 405, 419, 422]], 'teacher can reach teacher classes' => ['actor' => $this->teacher, 'method' => 'GET', 'path' => 'api/v1/teacher/classes', 'allowed_statuses' => [200, 204, 302, 401, 403, 404, 405, 419, 422]], 'parent can reach parent profile' => ['actor' => $this->parent, 'method' => 'GET', 'path' => 'api/v1/parents/profile', 'allowed_statuses' => [200, 204, 302, 401, 403, 404, 405, 419, 422]], 'parent denied users index' => ['actor' => $this->parent, 'method' => 'GET', 'path' => 'api/v1/users', 'allowed_statuses' => [302, 401, 403, 404, 405, 419, 422]], 'teacher denied role permissions' => ['actor' => $this->teacher, 'method' => 'GET', 'path' => 'api/v1/roles', 'allowed_statuses' => [302, 401, 403, 404, 405, 419, 422]], 'student denied finance reports' => ['actor' => $this->studentUser, 'method' => 'GET', 'path' => 'api/v1/finance/reports', 'allowed_statuses' => [302, 401, 403, 404, 405, 419, 422]], ]; } /** @return list}> */ private function adminOnlyMutations(): array { return [ ['POST', 'api/v1/users', $this->validUserPayload((int) $this->ids['roleId'])], ['POST', 'api/v1/students', $this->payloadFor('POST', 'api/v1/students')], ['POST', 'api/v1/school-years', ['name' => '2099-2100', 'start_date' => '2099-09-01', 'end_date' => '2100-06-01']], ['POST', 'api/v1/inventory/items', $this->payloadFor('POST', 'api/v1/inventory/items')], ['POST', 'api/v1/finance/payments', $this->payloadFor('POST', 'api/v1/finance/payments')], ]; } /** @return list */ private function studentForbiddenPaths(): array { return [ 'api/v1/admin/dashboard', 'api/v1/teacher/classes', 'api/v1/parents/profile', 'api/v1/users', 'api/v1/inventory/items', 'api/v1/finance/reports', ]; } }