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

240 lines
8.5 KiB
PHP

<?php
use App\Models\Audition;
use App\Models\Entry;
use App\Models\School;
use App\Models\Student;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use function Pest\Laravel\actingAs;
use function Pest\Laravel\delete;
use function Pest\Laravel\get;
use function Pest\Laravel\patch;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->adminUser = User::factory()->admin()->create();
$this->schools = School::factory()->count(5)->create();
$this->student = Student::factory()->create();
});
it('only shows for an admin user', function () {
// Act & Assert
$checkRoute = 'admin.students.edit';
get(route($checkRoute, $this->student))->assertRedirect(route('home'));
actingAs($this->adminUser);
get(route($checkRoute, $this->student))->assertOk();
actingAs(User::factory()->create());
get(route($checkRoute, $this->student))->assertRedirect(route('dashboard'));
});
it('submits a patch request', function () {
// Arrange
actingAs($this->adminUser);
// Act & Assert
$response = get(route('admin.students.edit', $this->student));
$response->assertOk();
$response->assertSeeInOrder([
'form',
'method',
'POST',
'action=',
route('admin.students.update', $this->student),
'/form',
], false);
$response->assertSee('<input type="hidden" name="_method" value="PATCH">', false);
});
it('has an Edit Student submit button', function () {
// Arrange
actingAs($this->adminUser);
// Act & Assert
$response = get(route('admin.students.edit', $this->student));
$response->assertOk();
$response->assertSeeInOrder([
'button',
'type',
'submit',
'Edit Student',
'/button',
], false);
});
it('has all needed fields', function () {
// Arrange
actingAs($this->adminUser);
$fieldNames = [
'first_name',
'last_name',
];
// Act & Assert
$response = get(route('admin.students.edit', $this->student));
$response->assertOk();
foreach ($fieldNames as $fieldName) {
$response->assertSeeInOrder([
'input',
'name=',
$fieldName,
'/',
]);
}
$response->assertSeeInOrder([
'select',
'name=',
'school_id',
'/select',
]);
$response->assertSeeInOrder([
'select',
'name=',
'grade',
'/select',
]);
});
it('has all schools in a dropdown', function () {
// Arrange
actingAs($this->adminUser);
// Act & Assert
$response = get(route('admin.students.edit', $this->student));
$response->assertOk();
foreach ($this->schools as $school) {
$response->assertSeeInOrder([
'option',
'value=',
$school->id,
$school->name,
'/option',
]);
}
});
it('is populated with existing data', function () {
// Arrange
Audition::factory()->create(['minimum_grade' => 1, 'maximum_grade' => 18]); // Needed for the grade select
actingAs($this->adminUser);
// Act & Assert
$response = get(route('admin.students.edit', $this->student));
$response->assertOk();
$response->assertSeeInOrder(['name=', 'first_name', 'value=', $this->student->first_name]);
$response->assertSeeInOrder(['name=', 'last_name', 'value=', $this->student->last_name]);
$response->assertSeeInOrder(['grade', 'option', 'value=', $this->student->grade], 'selected');
$response->assertSeeInOrder(['name=', 'school_id', 'value=', $this->student->school_id], 'selected');
});
it('rejects a submission by a non administrator', function () {
// Arrange
actingAs(User::factory()->create());
// Act & Assert
$response = patch(route('admin.students.update', $this->student), [
'first_name' => 'New First Name',
'last_name' => 'New Last Name',
]);
$response->assertRedirect(route('dashboard'));
});
it('allows an administrator to edit a student', function () {
// Arrange
$newSchool = School::factory()->create(['name' => 'New School']);
actingAs($this->adminUser);
$newData = [
'first_name' => 'New First Name',
'last_name' => 'New Last Name',
'grade' => '9',
'school_id' => $newSchool->id,
];
// Act
$response = patch(route('admin.students.update', $this->student), $newData);
/** @noinspection PhpUnhandledExceptionInspection */
$response
->assertSessionHasNoErrors()
->assertRedirect(route('admin.students.index'));
// Get the changed student
$this->student->refresh();
expect($this->student->first_name)->toBe($newData['first_name'])
->and($this->student->last_name)->toBe($newData['last_name'])
->and($this->student->grade)->toEqual($newData['grade'])
->and($this->student->school->name)->toBe($newSchool->name);
get(route('admin.students.index'))
->assertOk()
->assertSee($newData['first_name'])
->assertSee($newData['last_name'])
->assertSee($newData['grade'])
->assertSee($newSchool->name);
});
it('includes a form to destroy the student IF they have no entries', function () {
// Arrange
$condemnedStudent = Student::factory()->create();
actingAs($this->adminUser);
// Act & Assert
get(route('admin.students.edit', $condemnedStudent))
->assertOk()
->assertSeeInOrder([
'form',
'method',
'POST',
'action=',
route('admin.students.destroy', $condemnedStudent),
'/form',
], false)
->assertSee('<input type="hidden" name="_method" value="DELETE">', false);
});
it('does not include the destruction form if the student has entries', function () {
// Arrange
$condemnedStudent = Student::factory()->create();
Entry::factory()->create(['student_id' => $condemnedStudent->id]);
actingAs($this->adminUser);
// Act & Assert
get(route('admin.students.edit', $condemnedStudent))
->assertOk()
->assertDontSee('<input type="hidden" name="_method" value="DELETE">', false);
});
it('allows an administrator to destroy a student without entries', function () {
// Arrange
$condemnedStudent = Student::factory()->create();
// Act & Assert
expect($condemnedStudent->exists())->toBeTrue();
actingAs($this->adminUser);
/** @noinspection PhpUnhandledExceptionInspection */
delete(route('admin.students.destroy', $condemnedStudent))
->assertSessionHasNoErrors()
->assertRedirect(route('admin.students.index'));
expect(Student::find($condemnedStudent->id))->toBeNull();
});
it('does not allow an administrator to destroy a student with entries', function () {
// Arrange
$condemnedStudent = Student::factory()->create();
Entry::factory()->create(['student_id' => $condemnedStudent->id]);
// Act & Assert
expect($condemnedStudent->exists())->toBeTrue();
actingAs($this->adminUser);
/** @noinspection PhpUnhandledExceptionInspection */
delete(route('admin.students.destroy', $condemnedStudent))
->assertSessionHas('error', 'You cannot delete a student with entries.')
->assertRedirect(route('admin.students.index'))
->assertSessionHasNoErrors();
expect(Student::find($condemnedStudent->id))->toBeInstanceOf(Student::class);
});
it('does not allow a non administrator to delete a student', function () {
// Arrange
$condemnedStudent = Student::factory()->create();
// Act & Assert
expect($condemnedStudent->exists())->toBeTrue();
actingAs(User::factory()->create());
/** @noinspection PhpUnhandledExceptionInspection */
delete(route('admin.students.destroy', $condemnedStudent))
->assertSessionHasNoErrors()
->assertSessionHas('error', 'You are not authorized to perform this action')
->assertRedirect(route('dashboard'));
expect(Student::find($condemnedStudent->id))->toBeInstanceOf(Student::class);
});
it('will not duplicate a name at a school', function () {
$student1 = Student::factory()->create();
$student2 = Student::factory()->create(['school_id' => $student1->school_id]);
actingAs($this->adminUser);
$response = patch(route('admin.students.update', $student2), [
'first_name' => $student1->first_name,
'last_name' => $student1->last_name,
'grade' => $student2->grade,
'school_id' => $student2->school_id,
]);
$response->assertRedirect(route('admin.students.edit', $student2))
->assertSessionHas('error', 'A student with that name already exists at that school');
});