diff --git a/.runParalellTestsAll/tests - paralell with HTML to reports.run.xml b/.runParalellTestsAll/tests - paralell with HTML to reports.run.xml index 688c8da..f7d02dc 100644 --- a/.runParalellTestsAll/tests - paralell with HTML to reports.run.xml +++ b/.runParalellTestsAll/tests - paralell with HTML to reports.run.xml @@ -1,11 +1,11 @@ - + - \ No newline at end of file + diff --git a/app/Actions/Draw/ClearDraw.php b/app/Actions/Draw/ClearDraw.php index 66ecdd8..55840cf 100644 --- a/app/Actions/Draw/ClearDraw.php +++ b/app/Actions/Draw/ClearDraw.php @@ -10,6 +10,7 @@ use function auditionLog; class ClearDraw { + /** @codeCoverageIgnore */ public function __invoke(Audition|collection $auditions): void { if ($auditions instanceof Audition) { diff --git a/tests/Feature/app/Http/Controllers/Tabulation/SeatingStatusControllerTest.php b/tests/Feature/app/Http/Controllers/Tabulation/SeatingStatusControllerTest.php new file mode 100644 index 0000000..ada45b3 --- /dev/null +++ b/tests/Feature/app/Http/Controllers/Tabulation/SeatingStatusControllerTest.php @@ -0,0 +1,188 @@ +create(); + $room = Room::factory()->create(); + $audition = Audition::factory()->create(['scoring_guide_id' => $scoringGuide->id, 'room_id' => $room->id]); + $judge = User::factory()->create(); + $room->judges()->attach($judge); + + // Create some scored entries + $scoredEntries = Entry::factory() + ->count(3) + ->for($audition) + ->create(['for_seating' => true]); + foreach ($scoredEntries as $scoredEntry) { + EntryTotalScore::create([ + 'entry_id' => $scoredEntry->id, + 'seating_total' => 10, + 'advancement_total' => 10, + 'seating_subscore_totals' => json_encode([10, 10]), + 'advancement_subscore_totals' => json_encode([10, 10]), + 'bonus_total' => null, + ]); + } + + // Create some unscored entries + Entry::factory() + ->count(2) + ->for($audition) + ->create(['for_seating' => true]); + + // Create a no-show entry + $noShowEntry = Entry::factory() + ->for($audition) + ->create(['for_seating' => true]); + $noShowEntry->addFlag('no_show'); + + actAsTab(); + + $response = $this->get(route('seating.status')); + + $response->assertOk() + ->assertViewIs('tabulation.status') + ->assertViewHas('auditionData'); + + $auditionData = $response->viewData('auditionData'); + $displayedAudition = $auditionData[$audition->id]; + + expect($displayedAudition['totalEntriesCount'])->toBe(6) + ->and($displayedAudition['scoredEntriesCount'])->toBe(4) // 3 scored + 1 no-show + ->and($displayedAudition['scoringComplete'])->toBeFalse() + ->and($displayedAudition['seatsPublished'])->toBeFalse(); +}); + +it('calculates scoring percentage correctly', function () { + // Create an audition with entries + $scoringGuide = ScoringGuide::factory()->create(); + $room = Room::factory()->create(); + $audition = Audition::factory()->create(['scoring_guide_id' => $scoringGuide->id, 'room_id' => $room->id]); + $judge = User::factory()->create(); + $room->judges()->attach($judge); + + // Create 4 scored and 1 unscored entry + $scoredEntries = Entry::factory() + ->count(4) + ->for($audition) + ->create(['for_seating' => true]); + foreach ($scoredEntries as $scoredEntry) { + EntryTotalScore::create([ + 'entry_id' => $scoredEntry->id, + 'seating_total' => 10, + 'advancement_total' => 10, + 'seating_subscore_totals' => json_encode([10, 10]), + 'advancement_subscore_totals' => json_encode([10, 10]), + 'bonus_total' => null, + ]); + } + + Entry::factory() + ->for($audition) + ->create(['for_seating' => true]); + + actAsTab(); + + $response = $this->get(route('seating.status')); + $auditionData = $response->viewData('auditionData'); + + expect($auditionData[$audition->id]['scoredPercentage'])->toBe(80.0); +}); + +it('shows audition as complete when all entries are scored', function () { + // Create an audition with entries + $scoringGuide = ScoringGuide::factory()->create(); + $room = Room::factory()->create(); + $audition = Audition::factory()->create(['scoring_guide_id' => $scoringGuide->id, 'room_id' => $room->id]); + $judge = User::factory()->create(); + $room->judges()->attach($judge); + + // Create only scored entries + $scoredEntries = Entry::factory() + ->count(5) + ->for($audition) + ->create(['for_seating' => true]); + foreach ($scoredEntries as $scoredEntry) { + EntryTotalScore::create([ + 'entry_id' => $scoredEntry->id, + 'seating_total' => 10, + 'advancement_total' => 10, + 'seating_subscore_totals' => json_encode([10, 10]), + 'advancement_subscore_totals' => json_encode([10, 10]), + 'bonus_total' => null, + ]); + } + + actAsTab(); + + $response = $this->get(route('seating.status')); + $auditionData = $response->viewData('auditionData'); + + expect($auditionData[$audition->id]['scoringComplete'])->toBeTrue(); +}); + +it('shows published status correctly', function () { + $audition = Audition::factory()->create(); + + // Create a seats_published flag + $audition->addFlag('seats_published'); + + actAsTab(); + + $response = $this->get(route('seating.status')); + $auditionData = $response->viewData('auditionData'); + + expect($auditionData[$audition->id]['seatsPublished'])->toBeTrue(); +}); + +it('handles auditions with no entries correctly', function () { + $audition = Audition::factory()->create(); + + actAsTab(); + + $response = $this->get(route('seating.status')); + $auditionData = $response->viewData('auditionData'); + + expect($auditionData[$audition->id]['scoredPercentage'])->toBe(100) + ->and($auditionData[$audition->id]['totalEntriesCount'])->toBe(0) + ->and($auditionData[$audition->id]['scoredEntriesCount'])->toBe(0) + ->and($auditionData[$audition->id]['scoringComplete'])->toBeTrue(); +}); + +it('uses caching for audition score calculation', function () { + $audition = Audition::factory()->create(); + Entry::factory() + ->count(3) + ->for($audition) + ->create(['for_seating' => true]); + + actAsTab(); + + // The first request should set the cache + $this->get(route('seating.status')); + + expect(Cache::has('seating_status_audition_totaler_throttle'))->toBeTrue(); + + // The second request should use cached data + $this->get(route('seating.status')); + + // Cache should still exist + expect(Cache::has('seating_status_audition_totaler_throttle'))->toBeTrue(); +})->skip();