auditionadmin/tests/Feature/app/Actions/Entries/DoublerDecisionTest.php

192 lines
7.7 KiB
PHP

<?php
/** @noinspection PhpUnhandledExceptionInspection */
use App\Actions\Development\FakeScoresForEntry;
use App\Actions\Entries\CreateEntry;
use App\Actions\Entries\DoublerDecision;
use App\Exceptions\AuditionAdminException;
use App\Models\Audition;
use App\Models\Doubler;
use App\Models\Room;
use App\Models\ScoringGuide;
use App\Models\Student;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->decider = app(DoublerDecision::class);
$this->entryScribe = app(CreateEntry::class);
$this->scoreFaker = app(FakeScoresForEntry::class);
// Setup doubler
$this->scoringGuide = ScoringGuide::factory()->create();
$this->judge1 = User::factory()->create();
$this->judge2 = User::factory()->create();
$this->room = Room::factory()->create();
$this->room->addJudge($this->judge1);
$this->room->addJudge($this->judge2);
$this->audition1 = Audition::factory()->create(
[
'minimum_grade' => 9, 'maximum_grade' => 12,
'scoring_guide_id' => $this->scoringGuide->id,
'room_id' => $this->room->id,
'order_in_room' => 1,
'name' => 'Flute',
]);
$this->audition2 = Audition::factory()->create(
[
'minimum_grade' => 9, 'maximum_grade' => 12,
'scoring_guide_id' => $this->scoringGuide->id,
'room_id' => $this->room->id,
'order_in_room' => 2,
'event_id' => $this->audition1->event_id,
'name' => 'Trumpet',
]);
$this->audition3 = Audition::factory()->create(
[
'minimum_grade' => 9, 'maximum_grade' => 12,
'scoring_guide_id' => $this->scoringGuide->id,
'room_id' => $this->room->id,
'order_in_room' => 3,
'event_id' => $this->audition1->event_id,
'name' => 'Trombone',
]);
$this->otherEventAudition = Audition::factory()->create([
'minimum_grade' => 9, 'maximum_grade' => 12,
'scoring_guide_id' => $this->scoringGuide->id,
'room_id' => $this->room->id,
'order_in_room' => 4,
'name' => 'Jazz Trumpet',
]);
$this->student = Student::factory()->create([
'grade' => 9, 'first_name' => 'Percy',
'last_name' => 'Grainger',
]);
$this->entry1 = $this->entryScribe->createEntry($this->student, $this->audition1);
$this->entry2 = $this->entryScribe->createEntry($this->student, $this->audition2);
$this->entry3 = $this->entryScribe->createEntry($this->student, $this->audition3);
$this->otherEventEntry = $this->entryScribe->createEntry($this->student, $this->otherEventAudition);
});
it('is invokable', function () {
($this->scoreFaker)($this->entry1);
($this->scoreFaker)($this->entry2);
($this->scoreFaker)($this->entry3);
($this->decider)($this->entry2, 'decline');
expect($this->entry2->hasFlag('declined'))->toBeTruthy();
});
it('cannot be called with an invalid decision', function () {
($this->scoreFaker)($this->entry1);
($this->scoreFaker)($this->entry2);
($this->scoreFaker)($this->entry3);
($this->decider)($this->entry2, 'idunno');
})->throws(AuditionAdminException::class, 'Invalid decision specified');
it('can decline an entry', function () {
($this->scoreFaker)($this->entry1);
($this->scoreFaker)($this->entry2);
($this->scoreFaker)($this->entry3);
$this->decider->decline($this->entry2);
expect($this->entry2->hasFlag('declined'))->toBeTruthy();
});
it('will not decline an entry with no scores', function () {
$this->decider->decline($this->entry2);
})->throws(AuditionAdminException::class, 'Cannot decline an unscored entry');
it('will not decline an entry that is already declined', function () {
($this->scoreFaker)($this->entry2);
$this->entry2->addFlag('declined');
$this->decider->decline($this->entry2);
})->throws(AuditionAdminException::class, 'Entry 2 is already declined');
it('will not decline an entry in a published event', function () {
($this->scoreFaker)($this->entry2);
$this->audition2->addFlag('seats_published');
$this->entry2->refresh();
$this->decider->decline($this->entry2);
})->throws(AuditionAdminException::class, 'Cannot decline an entry in an audition where seats are published');
it('accepts an entry and declines others in the same event', function () {
($this->scoreFaker)($this->entry1);
($this->scoreFaker)($this->entry2);
($this->scoreFaker)($this->entry3);
$this->decider->accept($this->entry2);
$this->entry1->refresh();
$this->entry2->refresh();
$this->entry3->refresh();
expect($this->entry1->hasFlag('declined'))->toBeTruthy()
->and($this->entry3->hasFlag('declined'))->toBeTruthy();
$doubler = Doubler::findDoubler($this->entry2->student_id, $this->audition2->event_id);
expect($doubler->accepted_entry)->toBe($this->entry2->id);
});
it('will not accept an entry into an event with seats published', function () {
($this->scoreFaker)($this->entry1);
($this->scoreFaker)($this->entry2);
($this->scoreFaker)($this->entry3);
$this->audition2->addFlag('seats_published');
$this->audition2->refresh();
$this->entry2->refresh();
$this->decider->accept($this->entry2);
$this->entry1->refresh();
$this->entry2->refresh();
$this->entry3->refresh();
expect($this->entry1->hasFlag('declined'))->toBeTruthy()
->and($this->entry3->hasFlag('declined'))->toBeTruthy();
$doubler = Doubler::findDoubler($this->entry2->student_id, $this->audition2->event_id);
expect($doubler->accepted_entry)->toBe($this->entry2->id);
})->throws(AuditionAdminException::class, 'Cannot accept an entry in an audition where seats are published');
it('will not accept an entry that has already been declined', function () {
($this->scoreFaker)($this->entry1);
($this->scoreFaker)($this->entry2);
($this->scoreFaker)($this->entry3);
$this->entry2->addFlag('declined');
$this->decider->accept($this->entry2);
$this->entry1->refresh();
$this->entry2->refresh();
$this->entry3->refresh();
expect($this->entry1->hasFlag('declined'))->toBeTruthy()
->and($this->entry3->hasFlag('declined'))->toBeTruthy();
$doubler = Doubler::findDoubler($this->entry2->student_id, $this->audition2->event_id);
expect($doubler->accepted_entry)->toBe($this->entry2->id);
})->throws(AuditionAdminException::class, 'Entry 2 is already declined');
it('when accepting a seat, does not decline no_show or failed_prelim entries', function () {
($this->scoreFaker)($this->entry2);
$this->entry1->addFlag('no_show');
$this->entry3->addFlag('failed_prelim');
$this->decider->accept($this->entry2);
$this->entry1->refresh();
$this->entry2->refresh();
$this->entry3->refresh();
expect($this->entry1->hasFlag('declined'))->toBeFalsy()
->and($this->entry3->hasFlag('declined'))->toBeFalsy();
$doubler = Doubler::findDoubler($this->entry2->student_id, $this->audition2->event_id);
expect($doubler->accepted_entry)->toBe($this->entry2->id);
});
it('when accepting an entry, does not decline seats in other events', function () {
($this->scoreFaker)($this->entry1);
($this->scoreFaker)($this->entry2);
($this->scoreFaker)($this->entry3);
$this->decider->accept($this->entry2);
$this->entry1->refresh();
$this->entry2->refresh();
$this->entry3->refresh();
expect($this->otherEventEntry->hasFlag('declined'))->toBeFalsy();
});
it('will not accept an entry if the student has unscored entries', function () {
$this->decider->accept($this->entry2);
})->throws(AuditionAdminException::class,
'Cannot accept seating for Percy Grainger because student has unscored entries');