add api tests
This commit is contained in:
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\V1\PrintRequests;
|
||||
|
||||
use App\Models\PrintRequest;
|
||||
use App\Models\Role;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Tests\TestCase;
|
||||
|
||||
class PrintRequestsWorkflowTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_teacher_can_create_hand_copy_request_and_admin_can_advance_statuses(): void
|
||||
{
|
||||
$teacher = $this->createUserWithRole('teacher');
|
||||
$admin = $this->createUserWithRole('administrator');
|
||||
$classSectionId = $this->seedClassSection();
|
||||
|
||||
$this->actingAs($teacher, 'api');
|
||||
$createResponse = $this->postJson('/api/v1/print-requests/hand-copy', [
|
||||
'class_id' => $classSectionId,
|
||||
'num_copies' => 3,
|
||||
'required_by' => '2026-09-13 11:00:00',
|
||||
'pickup_method' => 'Self Pickup',
|
||||
]);
|
||||
|
||||
$createResponse
|
||||
->assertCreated()
|
||||
->assertJsonPath('status', true)
|
||||
->assertJsonPath('data.print_request.status', 'not_assigned');
|
||||
|
||||
$requestId = (int) $createResponse->json('data.print_request.id');
|
||||
$this->assertDatabaseHas('print_requests', [
|
||||
'id' => $requestId,
|
||||
'teacher_id' => $teacher->id,
|
||||
'class_id' => $classSectionId,
|
||||
'file_path' => '',
|
||||
'num_copies' => 3,
|
||||
'status' => 'not_assigned',
|
||||
]);
|
||||
|
||||
$this->actingAs($admin, 'api');
|
||||
foreach (['assigned', 'done', 'delivered'] as $status) {
|
||||
$this->patchJson("/api/v1/print-requests/{$requestId}/status", [
|
||||
'status' => $status,
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonPath('status', true)
|
||||
->assertJsonPath('data.print_request.status', $status);
|
||||
}
|
||||
|
||||
$this->assertDatabaseHas('print_requests', [
|
||||
'id' => $requestId,
|
||||
'admin_id' => $admin->id,
|
||||
'status' => 'delivered',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_admin_status_rejects_invalid_transition(): void
|
||||
{
|
||||
$teacher = $this->createUserWithRole('teacher');
|
||||
$admin = $this->createUserWithRole('administrator');
|
||||
$request = $this->seedPrintRequest($teacher, ['status' => 'delivered']);
|
||||
|
||||
$this->actingAs($admin, 'api');
|
||||
$this->patchJson("/api/v1/print-requests/{$request->id}/status", [
|
||||
'status' => 'assigned',
|
||||
])
|
||||
->assertUnprocessable()
|
||||
->assertJsonPath('status', false);
|
||||
|
||||
$this->assertDatabaseHas('print_requests', [
|
||||
'id' => $request->id,
|
||||
'status' => 'delivered',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_teacher_routes_reject_non_teacher_roles_and_admin_routes_reject_teacher_roles(): void
|
||||
{
|
||||
$parent = $this->createUserWithRole('parent');
|
||||
$teacher = $this->createUserWithRole('teacher');
|
||||
|
||||
$this->actingAs($parent, 'api');
|
||||
$this->getJson('/api/v1/print-requests/teacher')
|
||||
->assertForbidden();
|
||||
|
||||
$this->actingAs($teacher, 'api');
|
||||
$this->getJson('/api/v1/print-requests/admin')
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_teacher_cannot_update_delete_or_download_another_teachers_request(): void
|
||||
{
|
||||
$owner = $this->createUserWithRole('teacher');
|
||||
$intruder = $this->createUserWithRole('teacher');
|
||||
$request = $this->seedPrintRequest($owner, [
|
||||
'status' => 'not_assigned',
|
||||
'file_path' => 'missing-file.pdf',
|
||||
]);
|
||||
|
||||
$this->actingAs($intruder, 'api');
|
||||
|
||||
$this->patchJson("/api/v1/print-requests/{$request->id}", [
|
||||
'num_copies' => 8,
|
||||
'required_by' => '2026-09-20 11:00:00',
|
||||
'pickup_method' => 'Self Pickup',
|
||||
])->assertForbidden();
|
||||
|
||||
$this->deleteJson("/api/v1/print-requests/{$request->id}")
|
||||
->assertForbidden();
|
||||
|
||||
$this->getJson("/api/v1/print-requests/{$request->id}/file")
|
||||
->assertForbidden();
|
||||
|
||||
$this->assertDatabaseHas('print_requests', [
|
||||
'id' => $request->id,
|
||||
'teacher_id' => $owner->id,
|
||||
'num_copies' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_teacher_cannot_delete_request_after_processing_has_started(): void
|
||||
{
|
||||
$teacher = $this->createUserWithRole('teacher');
|
||||
$request = $this->seedPrintRequest($teacher, ['status' => 'done']);
|
||||
|
||||
$this->actingAs($teacher, 'api');
|
||||
$this->deleteJson("/api/v1/print-requests/{$request->id}")
|
||||
->assertBadRequest()
|
||||
->assertJsonPath('status', false);
|
||||
|
||||
$this->assertDatabaseHas('print_requests', [
|
||||
'id' => $request->id,
|
||||
'status' => 'done',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_upload_requires_valid_file_and_page_selection_format(): void
|
||||
{
|
||||
$teacher = $this->createUserWithRole('teacher');
|
||||
$classSectionId = $this->seedClassSection();
|
||||
|
||||
$this->actingAs($teacher, 'api');
|
||||
$response = $this->post('/api/v1/print-requests', [
|
||||
'file' => UploadedFile::fake()->create('lesson.pdf', 12, 'application/pdf'),
|
||||
'class_id' => $classSectionId,
|
||||
'num_copies' => 1,
|
||||
'required_by' => '2026-09-13 11:00:00',
|
||||
'pickup_method' => 'Self Pickup',
|
||||
'page_selection' => 'one through five',
|
||||
]);
|
||||
|
||||
$response
|
||||
->assertUnprocessable()
|
||||
->assertJsonPath('status', false)
|
||||
->assertJsonStructure(['errors' => ['page_selection']]);
|
||||
}
|
||||
|
||||
public function test_teacher_can_upload_and_download_own_file_and_admin_can_download_any_request_file(): void
|
||||
{
|
||||
$teacher = $this->createUserWithRole('teacher');
|
||||
$admin = $this->createUserWithRole('administrator');
|
||||
$classSectionId = $this->seedClassSection();
|
||||
|
||||
$this->actingAs($teacher, 'api');
|
||||
$createResponse = $this->post('/api/v1/print-requests', [
|
||||
'file' => UploadedFile::fake()->create('lesson.pdf', 12, 'application/pdf'),
|
||||
'class_id' => $classSectionId,
|
||||
'num_copies' => 2,
|
||||
'required_by' => '2026-09-13 11:00:00',
|
||||
'pickup_method' => 'Self Pickup',
|
||||
'page_selection' => '1-3,5',
|
||||
]);
|
||||
|
||||
$createResponse
|
||||
->assertCreated()
|
||||
->assertJsonPath('status', true);
|
||||
|
||||
$requestId = (int) $createResponse->json('data.print_request.id');
|
||||
|
||||
$this->actingAs($teacher, 'api');
|
||||
$this->get("/api/v1/print-requests/{$requestId}/file")
|
||||
->assertOk();
|
||||
|
||||
$this->actingAs($admin, 'api');
|
||||
$this->get("/api/v1/print-requests/{$requestId}/file")
|
||||
->assertOk();
|
||||
}
|
||||
|
||||
private function createUserWithRole(string $roleName): User
|
||||
{
|
||||
$role = Role::query()->firstOrCreate(
|
||||
['name' => $roleName],
|
||||
[
|
||||
'slug' => $roleName,
|
||||
'description' => ucfirst(str_replace('_', ' ', $roleName)),
|
||||
'dashboard_route' => $roleName === 'teacher' ? 'teacher/classes' : 'administrator/administratordashboard',
|
||||
'priority' => 1,
|
||||
'is_active' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
$user = User::factory()->create([
|
||||
'status' => 'Active',
|
||||
'is_verified' => 1,
|
||||
'is_suspended' => 0,
|
||||
'email' => $roleName . '-print-request-' . str_replace('.', '', uniqid('', true)) . '@example.test',
|
||||
]);
|
||||
|
||||
$user->roles()->syncWithoutDetaching([$role->id]);
|
||||
|
||||
return $user->fresh() ?? $user;
|
||||
}
|
||||
|
||||
private function seedClassSection(): int
|
||||
{
|
||||
DB::table('classSection')->insert([
|
||||
'class_id' => 1,
|
||||
'class_section_id' => 9901,
|
||||
'class_section_name' => 'Print Request Test Class',
|
||||
'semester' => 'Fall',
|
||||
'school_year' => '2026-2027',
|
||||
]);
|
||||
|
||||
return 9901;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $overrides
|
||||
*/
|
||||
private function seedPrintRequest(User $teacher, array $overrides = []): PrintRequest
|
||||
{
|
||||
return PrintRequest::query()->create(array_merge([
|
||||
'teacher_id' => $teacher->id,
|
||||
'admin_id' => null,
|
||||
'class_id' => $this->seedClassSection(),
|
||||
'file_path' => '',
|
||||
'page_selection' => null,
|
||||
'num_copies' => 1,
|
||||
'required_by' => '2026-09-13 11:00:00',
|
||||
'pickup_method' => 'Self Pickup',
|
||||
'status' => 'not_assigned',
|
||||
], $overrides));
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,13 @@ class RoleSwitcherControllerTest extends TestCase
|
||||
public function test_switch_sets_role(): void
|
||||
{
|
||||
$user = $this->seedUser();
|
||||
$this->seedRole();
|
||||
$roleId = $this->seedRole();
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $roleId,
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->postJson('/api/v1/role-switcher/switch', [
|
||||
@@ -52,6 +58,55 @@ class RoleSwitcherControllerTest extends TestCase
|
||||
$response->assertStatus(401);
|
||||
}
|
||||
|
||||
|
||||
public function test_switch_rejects_role_that_user_does_not_have(): void
|
||||
{
|
||||
$user = $this->seedUser();
|
||||
$this->seedRole();
|
||||
$teacherRoleId = DB::table('roles')->insertGetId([
|
||||
'name' => 'teacher',
|
||||
'slug' => 'teacher',
|
||||
'description' => 'Teacher',
|
||||
'dashboard_route' => 'teacher/classes',
|
||||
'priority' => 2,
|
||||
'is_active' => 1,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
|
||||
DB::table('user_roles')->insert([
|
||||
'user_id' => $user->id,
|
||||
'role_id' => $teacherRoleId,
|
||||
]);
|
||||
|
||||
Sanctum::actingAs($user);
|
||||
$this->postJson('/api/v1/role-switcher/switch', [
|
||||
'role' => 'admin',
|
||||
])
|
||||
->assertForbidden()
|
||||
->assertJsonPath('status', false);
|
||||
}
|
||||
|
||||
public function test_switch_validates_empty_role_payload(): void
|
||||
{
|
||||
$user = $this->seedUser();
|
||||
$this->seedRole();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->postJson('/api/v1/role-switcher/switch', [])
|
||||
->assertUnprocessable();
|
||||
}
|
||||
|
||||
public function test_index_returns_not_found_when_authenticated_user_has_no_roles(): void
|
||||
{
|
||||
$user = $this->seedUser();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->getJson('/api/v1/role-switcher')
|
||||
->assertNotFound()
|
||||
->assertJsonPath('status', false);
|
||||
}
|
||||
|
||||
private function seedUser(): User
|
||||
{
|
||||
$userId = DB::table('users')->insertGetId([
|
||||
|
||||
Reference in New Issue
Block a user