Files
root 3fde161f29
API CI/CD / Validate (composer + pint) (push) Successful in 3m6s
API CI/CD / Test (PHPUnit) (push) Failing after 6m55s
API CI/CD / Build frontend assets (push) Successful in 1m2s
API CI/CD / Security audit (push) Failing after 50s
API CI/CD / Deploy to shared hosting (PHP) (push) Has been skipped
fix failed tests
2026-07-07 04:12:02 -04:00

174 lines
6.6 KiB
PHP

<?php
namespace Tests\Unit\Services;
use App\Models\ClassSection;
use App\Models\Configuration;
use App\Models\SemesterScore;
use App\Models\Student;
use App\Models\StudentClass;
use App\Services\Administrator\Trophy\TrophyReportService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class TrophyReportServiceTest extends TestCase
{
use RefreshDatabase;
protected TrophyReportService $service;
protected string $schoolYear = '2025-2026';
protected ClassSection $section;
protected function setUp(): void
{
parent::setUp();
$this->service = app(TrophyReportService::class);
Configuration::query()->create([
'config_key' => 'school_year',
'config_value' => $this->schoolYear,
]);
$this->section = ClassSection::factory()->create([
'class_section_id' => 401,
'class_section_name' => 'Grade 4A',
]);
}
public function test_calculate_threshold_enforces_minimum_of_three_winners(): void
{
$result = $this->service->calculateThreshold([50, 60, 70, 80, 90], 95.0);
$this->assertSame('min3_reduced', $result['method']);
$this->assertSame(3, $result['winners']);
$this->assertSame(70.0, $result['threshold']);
}
public function test_projection_marks_students_without_fall_scores_as_not_projected(): void
{
$first = $this->enrollStudent('Amina', 'Top', 'Female', 'S-1', 98.0);
$second = $this->enrollStudent('Bilal', 'Strong', 'Male', 'S-2', 95.0);
$third = $this->enrollStudent('Celine', 'Good', 'Female', 'S-3', 90.0);
$fourth = $this->enrollStudent('David', 'Missing', 'Male', 'S-4', null);
$payload = $this->service->projection($this->schoolYear, 75.0);
$this->assertSame($this->schoolYear, $payload['selected_year']);
$this->assertSame(75.0, $payload['selected_percentile']);
$this->assertSame([$this->schoolYear], $payload['years']);
$this->assertCount(1, $payload['class_results']);
$classResult = $payload['class_results'][0];
$this->assertSame(4, $classResult['student_count']);
$this->assertSame(3, $classResult['scored_count']);
$this->assertSame(3, $classResult['trophy_count']);
$this->assertSame(90.0, $classResult['threshold']);
$this->assertSame(4, $payload['summary']['students']);
$this->assertSame(3, $payload['summary']['trophies']);
$students = collect($classResult['students'])->keyBy('student_id');
$this->assertTrue($students[$first->id]['projected_trophy']);
$this->assertTrue($students[$second->id]['projected_trophy']);
$this->assertTrue($students[$third->id]['projected_trophy']);
$this->assertFalse($students[$fourth->id]['projected_trophy']);
$this->assertNull($students[$fourth->id]['fall_score']);
}
public function test_final_report_classifies_confirmed_surprise_and_missed_winners(): void
{
$this->enrollStudent('Adam', 'Confirmed', 'Male', 'S-10', 99.0, 97.0);
$this->enrollStudent('Basma', 'Confirmed', 'Female', 'S-11', 95.0, 93.0);
$missed = $this->enrollStudent('Cyrus', 'Missed', 'Male', 'S-12', 92.0, 68.0);
$surprise = $this->enrollStudent('Dina', 'Surprise', 'Female', 'S-13', 88.0, 100.0);
$this->enrollStudent('Evan', 'None', 'Male', 'S-14', 70.0, 50.0);
$payload = $this->service->final($this->schoolYear, 75.0);
$this->assertCount(1, $payload['class_results']);
$this->assertSame(3, $payload['summary']['predicted']);
$this->assertSame(3, $payload['summary']['actual']);
$this->assertSame(2, $payload['summary']['confirmed']);
$this->assertSame(1, $payload['summary']['surprises']);
$this->assertSame(1, $payload['summary']['missed']);
$this->assertSame(67.0, $payload['summary']['accuracy']);
$this->assertSame(3, $payload['winner_gender_summary']['total']);
$this->assertSame(1, $payload['winner_gender_summary']['boys']);
$this->assertSame(2, $payload['winner_gender_summary']['girls']);
$this->assertCount(3, $payload['winner_stickers']);
$classResult = $payload['class_results'][0];
$this->assertSame(92.0, $classResult['fall_threshold']);
$this->assertSame(94.0, $classResult['year_threshold']);
$this->assertSame(2, $classResult['confirmed']);
$this->assertSame(1, $classResult['surprises']);
$this->assertSame(1, $classResult['missed']);
$this->assertSame(67.0, $classResult['accuracy']);
$students = collect($classResult['students'])->keyBy('student_id');
$this->assertSame('missed', $students[$missed->id]['status']);
$this->assertTrue($students[$missed->id]['predicted']);
$this->assertFalse($students[$missed->id]['actual']);
$this->assertSame('surprise', $students[$surprise->id]['status']);
$this->assertFalse($students[$surprise->id]['predicted']);
$this->assertTrue($students[$surprise->id]['actual']);
}
private function enrollStudent(
string $firstname,
string $lastname,
string $gender,
string $schoolId,
?float $fallScore,
?float $springScore = null
): Student {
$student = Student::factory()->create([
'firstname' => $firstname,
'lastname' => $lastname,
'gender' => $gender,
'school_id' => $schoolId,
'school_year' => $this->schoolYear,
'is_active' => 1,
]);
StudentClass::query()->create([
'student_id' => $student->id,
'class_section_id' => $this->section->class_section_id,
'school_year' => $this->schoolYear,
'semester' => 'Fall',
'is_event_only' => 0,
]);
if ($fallScore !== null) {
SemesterScore::query()->create([
'student_id' => $student->id,
'school_id' => $schoolId,
'class_section_id' => $this->section->class_section_id,
'semester_score' => $fallScore,
'semester' => 'Fall',
'school_year' => $this->schoolYear,
]);
}
if ($springScore !== null) {
SemesterScore::query()->create([
'student_id' => $student->id,
'school_id' => $schoolId,
'class_section_id' => $this->section->class_section_id,
'semester_score' => $springScore,
'semester' => 'Spring',
'school_year' => $this->schoolYear,
]);
}
return $student;
}
}