auditionadmin/tests/Feature/Pages/Admin/EntriesEditTest.php

288 lines
12 KiB
PHP

<?php
use App\Models\Audition;
use App\Models\Entry;
use App\Models\Room;
use App\Models\ScoreSheet;
use App\Models\ScoringGuide;
use App\Models\SubscoreDefinition;
use App\Models\User;
use App\Settings;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Artisan;
use Sinnbeck\DomAssertions\Asserts\AssertElement;
use Sinnbeck\DomAssertions\Asserts\AssertForm;
use Sinnbeck\DomAssertions\Asserts\AssertSelect;
use function Pest\Laravel\delete;
use function Pest\Laravel\get;
use function Pest\Laravel\patch;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->entry = Entry::factory()->create();
});
it('does not respond to an ordinary user', function () {
actAsNormal();
get(route('admin.entries.edit', $this->entry))
->assertRedirect(route('dashboard'));
});
it('does not respond to a guest', function () {
// Act & Assert
get(route('admin.entries.edit', $this->entry))
->assertRedirect(route('home'));
});
it('does not respond if the audition is published', function () {
// Arrange
actAsAdmin();
$this->entry->audition->addFlag('seats_published');
get(route('admin.entries.edit', $this->entry))
->assertRedirect(route('admin.entries.index'))
->assertSessionHas('error', 'Entries in auditions with seats published cannot be modified');
});
it('does not respond if advancement for the audition is published', function () {
// Arrange
actAsAdmin();
$this->entry->audition->addFlag('advancement_published');
get(route('admin.entries.edit', $this->entry))
->assertRedirect(route('admin.entries.index'))
->assertSessionHas('error', 'Entries in auditions with advancement results published cannot be modified');
});
it('has a delete link', function () {
// Arrange
actAsAdmin();
// Act & Assert
get(route('admin.entries.edit', $this->entry))
->assertSee('<input type="hidden" name="_method" value="DELETE">', false);
});
it('has a dropdown for all auditions appropriate to the students grade', function () {
// Arrange
$auditions = Audition::factory()->count(5)->create(['minimum_grade' => 1, 'maximum_grade' => 20]);
/** @noinspection PhpPossiblePolymorphicInvocationInspection */
$oldAudition = Audition::factory()->create(['minimum_grade' => $this->entry->grade + 1]);
/** @noinspection PhpPossiblePolymorphicInvocationInspection */
$youngAudition = Audition::factory()->create(['maximum_grade' => $this->entry->grade - 1]);
actAsAdmin();
$response = get(route('admin.entries.edit', $this->entry));
$response->assertOk();
// Act & Assert
foreach ($auditions as $audition) {
$response->assertOk()
->assertFormExists('#entryEditForm', function (AssertForm $form) use ($audition) {
$form->findSelect('', function (AssertSelect $select) use ($audition) {
$select->containsOption(['value' => $audition->id, 'text' => $audition->name]);
});
});
}
$response->assertDontSee('value='.$oldAudition->id)
->assertDontSee('value='.$youngAudition->id);
});
it('shows checkboxes for entry types only if advancement is enabled', function () {
actAsAdmin();
get(route('admin.entries.edit', $this->entry))
->assertElementExists('#for_seating')
->assertElementExists('#for_advancement');
Settings::set('advanceTo', '');
get(route('admin.entries.edit', $this->entry))
->assertDontSee('Enter for '.auditionSetting('auditionAbbreviation'))
->assertDontSee('Enter for '.auditionSetting('advanceTo'));
});
it('properly checks boxes based on entries settings', function () {
actAsAdmin();
get(route('admin.entries.edit', $this->entry))
->assertElementExists('#for_seating', function (AssertElement $element) {
$element->is('input')
->has('checked');
})
->assertElementExists('#for_advancement', function (AssertElement $element) {
$element->is('input')
->has('checked');
});
$entry2 = Entry::factory()->seatingOnly()->create();
get(route('admin.entries.edit', $entry2))
->assertElementExists('#for_seating', function (AssertElement $element) {
$element->is('input')
->has('checked');
})
->assertElementExists('#for_advancement', function (AssertElement $element) {
$element->is('input')
->doesntHave('checked');
});
$entry3 = Entry::factory()->advanceOnly()->create();
get(route('admin.entries.edit', $entry3))
->assertElementExists('#for_seating', function (AssertElement $element) {
$element->is('input')
->doesntHave('checked');
})
->assertElementExists('#for_advancement', function (AssertElement $element) {
$element->is('input')
->has('checked');
});
});
// Submission tests
it('does not let a normal user update an entry', function () {
// Arrange
$newAudition = Audition::factory()->create();
actAsNormal();
// Act & Assert
/** @noinspection PhpUnhandledExceptionInspection */
patch(route('admin.entries.update', $this->entry), ['audition_id' => $newAudition->id])
->assertSessionHasNoErrors()
->assertSessionHas('error', 'You are not authorized to perform this action')
->assertRedirect(route('dashboard'));
});
it('allows an admin to update an entry', function () {
// Arrange
$newAudition = Audition::factory()->create();
actAsAdmin();
// Act & Assert
/** @noinspection PhpUnhandledExceptionInspection */
patch(route('admin.entries.update', $this->entry), ['audition_id' => $newAudition->id])
->assertSessionHasNoErrors()
->assertSessionHas('success', 'Entry updated successfully')
->assertRedirect(route('admin.entries.index'));
$this->entry->refresh();
expect($this->entry->audition_id)->toBe($newAudition->id)
->and($this->entry->for_seating)->toBe(0)
->and($this->entry->for_advancement)->toBe(0);
});
it('does not allow an administrator to update an entry in a published audition', function () {
// Arrange
$newAudition = Audition::factory()->create();
actAsAdmin();
$this->entry->audition->addFlag('seats_published');
// Act & Assert
/** @noinspection PhpUnhandledExceptionInspection */
patch(route('admin.entries.update', $this->entry), ['audition_id' => $newAudition->id])
->assertSessionHasNoErrors()
->assertSessionHas('error', 'Entries in auditions with seats published cannot be modified')
->assertRedirect(route('admin.entries.index'));
$checkEntry = $this->entry->fresh();
expect($checkEntry->id === $this->entry->id)->toBeTrue()
->and($checkEntry->audition_id === $this->entry->audition_id)->toBeTrue()
->and($checkEntry->student_id === $this->entry->student_id)->toBeTrue()
->and($checkEntry->for_seating === $this->entry->for_seating)->toBeTrue()
->and($checkEntry->for_advancement === $this->entry->for_advancement)->toBeTrue();
});
it('does not allow an administrator to update an entry in an audition with published advancement results', function () {
// Arrange
$newAudition = Audition::factory()->create();
actAsAdmin();
$this->entry->audition->addFlag('advancement_published');
// Act & Assert
/** @noinspection PhpUnhandledExceptionInspection */
patch(route('admin.entries.update', $this->entry), ['audition_id' => $newAudition->id])
->assertSessionHasNoErrors()
->assertSessionHas('error', 'Entries in auditions with advancement results published cannot be modified')
->assertRedirect(route('admin.entries.index'));
$checkEntry = $this->entry->fresh();
expect($checkEntry->id === $this->entry->id)->toBeTrue()
->and($checkEntry->audition_id === $this->entry->audition_id)->toBeTrue()
->and($checkEntry->student_id === $this->entry->student_id)->toBeTrue()
->and($checkEntry->for_seating === $this->entry->for_seating)->toBeTrue()
->and($checkEntry->for_advancement === $this->entry->for_advancement)->toBeTrue();
});
it('always sets for_seating to true if advancement is not enabled', function () {
//arrange
Settings::set('advanceTo', '');
$newAudition = Audition::factory()->create();
actAsAdmin();
// Act & Assert
/** @noinspection PhpUnhandledExceptionInspection */
patch(route('admin.entries.update', $this->entry), ['audition_id' => $newAudition->id])
->assertSessionHasNoErrors()
->assertSessionHas('success', 'Entry updated successfully')
->assertRedirect(route('admin.entries.index'));
$this->entry->refresh();
expect($this->entry->audition_id)->toBe($newAudition->id)
->and($this->entry->for_seating)->toBe(1);
});
it('displays scores', function () {
// Arrange
$sg = ScoringGuide::factory()->create();
SubscoreDefinition::factory()->count(5)->create(['scoring_guide_id' => $sg->id]);
$room = Room::factory()->create();
$judge = User::factory()->create();
$room->addJudge($judge);
$audition = Audition::factory()->create(['room_id' => $room->id, 'scoring_guide_id' => $sg->id]);
$entry = Entry::factory()->create(['audition_id' => $audition->id]);
// Run the ScoreAllAuditions seeder
Artisan::call('db:seed', ['--class' => 'ScoreAllAuditions']);
// Act & Assert
actAsAdmin();
$response = get(route('admin.entries.edit', $entry))
->assertSee($judge->full_name());
foreach ($sg->subscores as $subscore) {
$response->assertSee($subscore->name);
}
});
it('has a link to delete scores', function() {
// Arrange
$sg = ScoringGuide::factory()->create();
SubscoreDefinition::factory()->count(5)->create(['scoring_guide_id' => $sg->id]);
$room = Room::factory()->create();
$judge = User::factory()->create();
$room->addJudge($judge);
$audition = Audition::factory()->create(['room_id' => $room->id, 'scoring_guide_id' => $sg->id]);
$entry = Entry::factory()->create(['audition_id' => $audition->id]);
// Run the ScoreAllAuditions seeder
Artisan::call('db:seed', ['--class' => 'ScoreAllAuditions']);
// Act & Assert
$scoreSheet = ScoreSheet::where('entry_id', $entry->id)->first();
actAsAdmin();
$response = get(route('admin.entries.edit', $entry))
->assertSee(route('scores.destroy', ['score'=>$scoreSheet]));
});
// Delete tests
it('does not allow a normal user to delete an entry', function () {
// Arrange
actAsNormal();
// Act & Assert
/** @noinspection PhpUnhandledExceptionInspection */
delete(route('admin.entries.destroy', $this->entry), ['_method' => 'DELETE'])
->assertSessionHasNoErrors()
->assertSessionHas('error', 'You are not authorized to perform this action')
->assertRedirect(route('dashboard'));
});
it('allows an admin to delete an entry', function () {
// Arrange
actAsAdmin();
// Act & Assert
/** @noinspection PhpUnhandledExceptionInspection */
delete(route('admin.entries.destroy', $this->entry), ['_method' => 'DELETE'])
->assertSessionHasNoErrors()
->assertSessionHas('success', 'Entry Deleted')
->assertRedirect(route('admin.entries.index'));
expect(Entry::find($this->entry->id))->toBeNull();
});
it('does not allow an admin to delete an entry if that entries audition seats are published', function () {
// Arrange
actAsAdmin();
// Act & Assert
$this->entry->audition->addFlag('seats_published');
/** @noinspection PhpUnhandledExceptionInspection */
delete(route('admin.entries.destroy', $this->entry), ['_method' => 'DELETE'])
->assertSessionHasNoErrors()
->assertSessionHas('error', 'Entries in auditions with seats published cannot be deleted')
->assertRedirect(route('admin.entries.index'));
expect(Entry::find($this->entry->id))->not->toBeNull();
});
it('does not allow an admin to delete an entry if that entries advancement is published', function () {
// Arrange
actAsAdmin();
// Act & Assert
$this->entry->audition->addFlag('advancement_published');
/** @noinspection PhpUnhandledExceptionInspection */
delete(route('admin.entries.destroy', $this->entry), ['_method' => 'DELETE'])
->assertSessionHasNoErrors()
->assertSessionHas('error', 'Entries in auditions with advancement results published cannot be deleted')
->assertRedirect(route('admin.entries.index'));
expect(Entry::find($this->entry->id))->not->toBeNull();
});