Add tests for admin/RoomContoller

This commit is contained in:
Matt Young 2025-07-08 02:30:00 -05:00
parent e4a646a4ce
commit 4358201909
2 changed files with 240 additions and 25 deletions

View File

@ -8,18 +8,16 @@ use App\Models\BonusScoreDefinition;
use App\Models\Room; use App\Models\Room;
use App\Models\User; use App\Models\User;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\Rule; use Illuminate\Validation\Rule;
use function auditionLog;
use function redirect; use function redirect;
class RoomController extends Controller class RoomController extends Controller
{ {
public function index() public function index()
{ {
if (! Auth::user()->is_admin) {
abort(403);
}
$rooms = Room::with('auditions.entries', 'entries')->orderBy('name')->get(); $rooms = Room::with('auditions.entries', 'entries')->orderBy('name')->get();
if (! $rooms->contains('id', 0)) { if (! $rooms->contains('id', 0)) {
$unassignedRoom = Room::create([ $unassignedRoom = Room::create([
@ -30,7 +28,7 @@ class RoomController extends Controller
$unassignedRoom->id = 0; $unassignedRoom->id = 0;
$unassignedRoom->save(); $unassignedRoom->save();
$auditionsToUpdate = Audition::where('room_id', null)->get(); $auditionsToUpdate = Audition::whereNull('room_id')->get();
foreach ($auditionsToUpdate as $audition) { foreach ($auditionsToUpdate as $audition) {
$audition->room_id = 0; $audition->room_id = 0;
$audition->save(); $audition->save();
@ -54,9 +52,6 @@ class RoomController extends Controller
public function updateJudgeAssignment(Request $request, Room $room) public function updateJudgeAssignment(Request $request, Room $room)
{ {
if (! Auth::user()->is_admin) {
abort(403);
}
$validData = $request->validate([ $validData = $request->validate([
'judge' => 'exists:users,id', 'judge' => 'exists:users,id',
]); ]);
@ -70,27 +65,21 @@ class RoomController extends Controller
// detach judge on delete // detach judge on delete
$room->removeJudge($judge->id); $room->removeJudge($judge->id);
$message = 'Removed '.$judge->full_name().' from '.$room->name; $message = 'Removed '.$judge->full_name().' from '.$room->name;
} else {
return redirect('/admin/rooms/judging_assignments')->with('error', 'Invalid request method.');
} }
$affected['users'] = [$judge->id];
$affected['rooms'] = [$room->id];
auditionLog($message, $affected);
return redirect('/admin/rooms/judging_assignments')->with('success', $message); return redirect(route('admin.rooms.judgingAssignment'))->with('success', $message);
} }
public function create() public function create()
{ {
if (! Auth::user()->is_admin) {
abort(403);
}
return view('admin.rooms.create'); return view('admin.rooms.create');
} }
public function store(Request $request) public function store(Request $request)
{ {
if (! Auth::user()->is_admin) {
abort(403);
}
$validData = $request->validate([ $validData = $request->validate([
'name' => 'required|unique:rooms,name', 'name' => 'required|unique:rooms,name',
'description' => 'nullable', 'description' => 'nullable',
@ -106,9 +95,6 @@ class RoomController extends Controller
public function update(Request $request, Room $room) public function update(Request $request, Room $room)
{ {
if (! Auth::user()->is_admin) {
abort(403);
}
$validData = $request->validate([ $validData = $request->validate([
'name' => ['required', Rule::unique('rooms', 'name')->ignore($room->id)], 'name' => ['required', Rule::unique('rooms', 'name')->ignore($room->id)],
'description' => 'nullable', 'description' => 'nullable',
@ -123,10 +109,6 @@ class RoomController extends Controller
public function destroy(Room $room) public function destroy(Room $room)
{ {
if (! Auth::user()->is_admin) {
abort(403);
}
if ($room->auditions()->count() > 0) { if ($room->auditions()->count() > 0) {
return redirect()->route('admin.rooms.index')->with('error', return redirect()->route('admin.rooms.index')->with('error',
'Cannot delete room with auditions. First move the auditions to unassigned or another room'); 'Cannot delete room with auditions. First move the auditions to unassigned or another room');

View File

@ -0,0 +1,233 @@
<?php
use App\Models\Audition;
use App\Models\Room;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
describe('RoomController::index', function () {
it('denies access to non-admin users', function () {
$response = $this->get(route('admin.rooms.index'))->assertRedirect(route('home'));
actAsNormal();
$response = $this->get(route('admin.rooms.index'))->assertRedirect(route('dashboard'));
actAsTab();
$response = $this->get(route('admin.rooms.index'))->assertRedirect(route('dashboard'));
});
it('creates room 0 for unassigned entries if it does not exist', function () {
actAsAdmin();
Room::truncate();
$this->get(route('admin.rooms.index'));
expect(Room::find(0))->not()->toBeNull;
});
it('assigns auditions with no room assignment to room 0', function () {
Room::truncate();
actAsAdmin();
$audition = Audition::factory()->create();
expect($audition->room_id)->toBeNull();
$this->get(route('admin.rooms.index'));
$audition->refresh();
expect($audition->room_id)->not()->toBeNull();
});
it('gets the room index', function () {
actAsAdmin();
Room::factory()->count(5)->create();
$response = $this->get(route('admin.rooms.index'));
$response->assertOk()
->assertViewIs('admin.rooms.index')
->assertViewHas('rooms');
expect($response->viewData('rooms')->count())->toEqual(6);
});
});
describe('RoomController::judgingAssignment', function () {
it('denies access to non-admin users', function () {
$response = $this->get(route('admin.rooms.judgingAssignment'))->assertRedirect(route('home'));
actAsNormal();
$response = $this->get(route('admin.rooms.judgingAssignment'))->assertRedirect(route('dashboard'));
actAsTab();
$response = $this->get(route('admin.rooms.judgingAssignment'))->assertRedirect(route('dashboard'));
});
// TODO: Need more exhaustive testing on the content
it('shows a page to manage judges', function () {
actAsAdmin();
$room = Room::factory()->create();
$assignedUser = User::factory()->create();
$unassignedUser = User::factory()->create();
DB::table('room_user')->insert([
'room_id' => $room->id,
'user_id' => $assignedUser->id,
]);
$response = $this->get(route('admin.rooms.judgingAssignment'))->assertOk();
$returnedWithout = $response->viewData('usersWithoutRooms');
$returnedWith = $response->viewData('usersWithRooms');
expect($returnedWith)->count()->toEqual(1);
expect($returnedWithout)->count()->toEqual(2); //actAsAdmin user is the second one
expect($returnedWith[0]->id)->toEqual($assignedUser->id);
expect($returnedWithout->contains('id', $unassignedUser->id))->toBeTrue();
});
});
describe('RoomController::updateJudgeAssignment', function () {
beforeEach(function () {
$this->room = Room::factory()->create();
});
it('denies access to non-admin users', function () {
$response = $this->post(route('admin.rooms.updateJudgeAssignment', $this->room))->assertRedirect(route('home'));
$response = $this->delete(route('admin.rooms.updateJudgeAssignment',
$this->room))->assertRedirect(route('home'));
actAsNormal();
$response = $this->post(route('admin.rooms.updateJudgeAssignment',
$this->room))->assertRedirect(route('dashboard'));
$response = $this->delete(route('admin.rooms.updateJudgeAssignment',
$this->room))->assertRedirect(route('dashboard'));
actAsTab();
$response = $this->post(route('admin.rooms.updateJudgeAssignment',
$this->room))->assertRedirect(route('dashboard'));
$response = $this->delete(route('admin.rooms.updateJudgeAssignment',
$this->room))->assertRedirect(route('dashboard'));
});
it('rejects attempts with an invalid user as a judge', function () {
actAsAdmin();
$fakeUser = User::factory()->make();
$response = $this->post(route('admin.rooms.updateJudgeAssignment', $this->room), [
'judge' => $fakeUser->id,
])->assertSessionHasErrors('judge');
});
it('can assign a judge to a room', function () {
actAsAdmin();
$judge = User::factory()->create();
$response = $this->post(route('admin.rooms.updateJudgeAssignment', $this->room), [
'judge' => $judge->id,
])->assertRedirect(route('admin.rooms.judgingAssignment'))->assertSessionHas('success');
$this->room->refresh();
expect($this->room->judges->contains('id', $judge->id))->toBeTrue();
});
it('can remove a judge from a room', function () {
actAsAdmin();
$judge = User::factory()->create();
$this->room->judges()->attach($judge);
$response = $this->delete(route('admin.rooms.updateJudgeAssignment', $this->room), [
'judge' => $judge->id,
])->assertRedirect(route('admin.rooms.judgingAssignment'))->assertSessionHas('success');
$this->room->refresh();
expect($this->room->judges->contains('id', $judge->id))->toBeFalse();
});
});
describe('RoomController::create', function () {
it('denies access to non-admin users', function () {
$response = $this->get(route('admin.rooms.create'))->assertRedirect(route('home'));
actAsNormal();
$response = $this->get(route('admin.rooms.create'))->assertRedirect(route('dashboard'));
actAsTab();
$response = $this->get(route('admin.rooms.create'))->assertRedirect(route('dashboard'));
});
it('shows a page to create a room', function () {
actAsAdmin();
$response = $this->get(route('admin.rooms.create'))->assertOk()
->assertViewIs('admin.rooms.create');
});
});
describe('RoomController::store', function () {
it('denies access to non-admin users', function () {
$response = $this->post(route('admin.rooms.store'))->assertRedirect(route('home'));
actAsNormal();
$response = $this->post(route('admin.rooms.store'))->assertRedirect(route('dashboard'));
actAsTab();
$response = $this->post(route('admin.rooms.store'))->assertRedirect(route('dashboard'));
});
it('creates a room', function () {
actAsAdmin();
$response = $this->post(route('admin.rooms.store'), ['name' => 'Band Room', 'description' => 'Percussion']);
$response->assertRedirect(route('admin.rooms.index'))->assertSessionHas('success');
expect(Room::where('name', 'Band Room')->first())->not()->toBeNull();
});
it('will not create a room with a duplicate name', function () {
$existingRoom = Room::create(['name' => 'Band Room', 'description' => 'Drums']);
actAsAdmin();
$response = $this->post(route('admin.rooms.store'), ['name' => 'Band Room', 'description' => 'Percussion']);
$response->assertSessionHasErrors('name');
});
});
describe('RoomController::update', function () {
beforeEach(function () {
$this->oldRoom = Room::create(['name' => 'Old Room', 'description' => 'Drums']);
$this->newData = ['name' => 'New Room', 'description' => 'Percussion'];
});
it('denies access to non-admin users', function () {
$response = $this->patch(route('admin.rooms.update', $this->oldRoom),
$this->newData)->assertRedirect(route('home'));
actAsNormal();
$response = $this->patch(route('admin.rooms.update', $this->oldRoom),
$this->newData)->assertRedirect(route('dashboard'));
actAsTab();
$response = $this->patch(route('admin.rooms.update', $this->oldRoom),
$this->newData)->assertRedirect(route('dashboard'));
});
it('updates a room', function () {
actAsAdmin();
$response = $this->patch(route('admin.rooms.update', $this->oldRoom), $this->newData);
$response->assertRedirect(route('admin.rooms.index'))->assertSessionHas('success');
$this->oldRoom->refresh();
expect($this->oldRoom->name)->toEqual('New Room')
->and($this->oldRoom->description)->toEqual('Percussion');
});
it('will not update a room with a duplicate name', function () {
$existingRoom = Room::create(['name' => 'New Room', 'description' => 'Percussion']);
actAsAdmin();
$response = $this->patch(route('admin.rooms.update', $this->oldRoom), $this->newData);
$response->assertSessionHasErrors('name');
});
it('will update a room while keeping old name', function () {
actAsAdmin();
$response = $this->patch(route('admin.rooms.update', $this->oldRoom),
['name' => 'Old Room', 'description' => 'Percussion']);
$response->assertRedirect(route('admin.rooms.index'))->assertSessionHas('success');
$this->oldRoom->refresh();
expect($this->oldRoom->name)->toEqual('Old Room')
->and($this->oldRoom->description)->toEqual('Percussion');
});
});
describe('RoomController::destroy', function () {
beforeEach(function () {
$this->room = Room::factory()->create();
});
it('denies access to non-admin users', function () {
$response = $this->delete(route('admin.rooms.destroy', $this->room))->assertRedirect(route('home'));
actAsNormal();
$response = $this->delete(route('admin.rooms.destroy', $this->room))->assertRedirect(route('dashboard'));
actAsTab();
$response = $this->delete(route('admin.rooms.destroy', $this->room))->assertRedirect(route('dashboard'));
});
it('will not delete a room with auditions assigned to it', function () {
actAsAdmin();
$audition = Audition::factory()->create(['room_id' => $this->room->id]);
$response = $this->delete(route('admin.rooms.destroy', $this->room))
->assertRedirect(route('admin.rooms.index'))->assertSessionHas('error');
expect(Room::count())->toEqual(2);
});
it('will delete a room', function () {
actAsAdmin();
$response = $this->delete(route('admin.rooms.destroy', $this->room))
->assertRedirect(route('admin.rooms.index'))->assertSessionHas('success');
expect(Room::count())->toEqual(1);
});
});