Files
alrahma_sunday_school_api/tests/Feature/Api/V1/AssignmentApiTest.php
T
root baa6fff459
API CI/CD / Validate (composer + pint) (push) Successful in 2m6s
API CI/CD / Test (PHPUnit) (push) Failing after 2m24s
API CI/CD / Build frontend assets (push) Successful in 2m25s
API CI/CD / Security audit (push) Successful in 32s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
fix tests isssues
2026-06-24 00:56:12 -04:00

245 lines
7.6 KiB
PHP

<?php
namespace Tests\Feature\Api;
use App\Models\ClassSection;
use App\Models\Configuration;
use App\Models\Student;
use App\Models\StudentClass;
use App\Models\TeacherClass;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
class AssignmentApiTest extends TestCase
{
use RefreshDatabase;
protected User $user;
protected function setUp(): void
{
parent::setUp();
$this->user = User::factory()->create();
// Seed config values used by AssignmentService
Configuration::query()->updateOrCreate(
['config_key' => 'semester'],
['config_value' => 'Fall']
);
Configuration::query()->updateOrCreate(
['config_key' => 'school_year'],
['config_value' => '2025-2026']
);
}
#[Test]
public function it_returns_assignment_sections_json(): void
{
Sanctum::actingAs($this->user);
$section = ClassSection::factory()->create([
'class_section_name' => 'Grade 5 - A',
]);
$teacher = User::factory()->create([
'firstname' => 'Ahmad',
'lastname' => 'Ali',
]);
TeacherClass::query()->create([
'teacher_id' => $teacher->id,
'class_section_id' => $section->class_section_id,
'position' => 'main',
'semester' => 'Fall',
'school_year' => '2025-2026',
'description' => 'Main teacher assignment',
]);
$student = Student::factory()->create([
'firstname' => 'Sara',
'lastname' => 'Yousef',
'is_active' => 1,
'gender' => 'F',
'registration_grade' => '5',
'photo_consent' => 1,
'tuition_paid' => 1,
'school_id' => 'SCH-1001',
]);
StudentClass::query()->create([
'student_id' => $student->id,
'class_section_id' => $section->class_section_id,
'semester' => 'Fall',
'school_year' => '2025-2026',
'description' => 'Student assigned',
]);
$response = $this->getJson('/api/v1/assignments');
$response->assertOk()
->assertJsonStructure([
'message',
'data' => [
'classSections' => [
'*' => [
'class_section_id',
'class_section_name',
'main_teachers',
'teacher_assistants',
'students',
'semester',
'school_year',
'description',
],
],
'schoolYears',
'selectedYear',
'selectedSemester',
'semester',
'current_school_year',
],
]);
$response->assertJsonPath('data.classSections.0.class_section_id', $section->class_section_id);
$response->assertJsonPath('data.classSections.0.main_teachers.0', 'Ahmad Ali');
$response->assertJsonPath('data.classSections.0.students.0.id', $student->id);
}
#[Test]
public function it_filters_assignments_by_school_year(): void
{
Sanctum::actingAs($this->user);
$section1 = ClassSection::factory()->create(['class_section_name' => 'Grade 4']);
$section2 = ClassSection::factory()->create(['class_section_name' => 'Grade 6']);
$teacher = User::factory()->create(['firstname' => 'Test', 'lastname' => 'Teacher']);
TeacherClass::query()->create([
'teacher_id' => $teacher->id,
'class_section_id' => $section1->class_section_id,
'position' => 'main',
'semester' => 'Fall',
'school_year' => '2024-2025',
]);
TeacherClass::query()->create([
'teacher_id' => $teacher->id,
'class_section_id' => $section2->class_section_id,
'position' => 'main',
'semester' => 'Fall',
'school_year' => '2025-2026',
]);
$response = $this->getJson('/api/v1/assignments?school_year=2025-2026');
$response->assertOk();
$sections = $response->json('data.classSections');
$ids = collect($sections)->pluck('class_section_id')->all();
$this->assertContains($section2->class_section_id, $ids);
$this->assertNotContains($section1->class_section_id, $ids);
$response->assertJsonPath('data.selectedYear', '2025-2026');
}
#[Test]
public function it_creates_or_updates_student_assignment(): void
{
Sanctum::actingAs($this->user);
$student = Student::factory()->create(['is_active' => 1]);
$section = ClassSection::factory()->create();
$payload = [
'student_id' => $student->id,
'class_section_id' => $section->class_section_id,
'semester' => 'Spring',
'school_year' => '2025-2026',
'description' => 'Moved after placement review',
];
$response = $this->postJson('/api/v1/assignments', $payload);
$response->assertCreated()
->assertJsonPath('message', 'Assignment saved successfully.');
$this->assertDatabaseHas('student_class', [
'student_id' => $student->id,
'class_section_id' => $section->class_section_id,
'semester' => 'Spring',
'school_year' => '2025-2026',
]);
}
#[Test]
public function it_validates_required_fields_when_storing_assignment(): void
{
Sanctum::actingAs($this->user);
$response = $this->postJson('/api/v1/assignments', []);
$response->assertStatus(422)
->assertJsonValidationErrors([
'student_id',
'class_section_id',
]);
}
#[Test]
public function store_is_idempotent_for_same_student_semester_and_year(): void
{
Sanctum::actingAs($this->user);
$student = Student::factory()->create(['is_active' => 1]);
$sectionA = ClassSection::factory()->create();
$sectionB = ClassSection::factory()->create();
// First create
$this->postJson('/api/v1/assignments', [
'student_id' => $student->id,
'class_section_id' => $sectionA->class_section_id,
'semester' => 'Fall',
'school_year' => '2025-2026',
])->assertCreated();
// Second call same unique key should update (per service updateOrCreate)
$this->postJson('/api/v1/assignments', [
'student_id' => $student->id,
'class_section_id' => $sectionA->class_section_id,
'semester' => 'Fall',
'school_year' => '2025-2026',
'description' => 'Reassigned',
])->assertCreated();
$this->assertEquals(
1,
StudentClass::query()
->where('student_id', $student->id)
->where('semester', 'Fall')
->where('school_year', '2025-2026')
->count()
);
$this->assertDatabaseHas('student_class', [
'student_id' => $student->id,
'class_section_id' => $sectionA->class_section_id,
'semester' => 'Fall',
'school_year' => '2025-2026',
]);
}
#[Test]
public function guest_cannot_access_assignment_api_when_auth_is_required(): void
{
$response = $this->getJson('/api/v1/assignments');
$response->assertStatus(401);
}
}