From 4358201909da40f88d6c12dcfd6146e76be775be Mon Sep 17 00:00:00 2001 From: Matt Young Date: Tue, 8 Jul 2025 02:30:00 -0500 Subject: [PATCH] Add tests for admin/RoomContoller --- app/Http/Controllers/Admin/RoomController.php | 32 +-- .../Controllers/Admin/RoomControllerTest.php | 233 ++++++++++++++++++ 2 files changed, 240 insertions(+), 25 deletions(-) create mode 100644 tests/Feature/app/Http/Controllers/Admin/RoomControllerTest.php diff --git a/app/Http/Controllers/Admin/RoomController.php b/app/Http/Controllers/Admin/RoomController.php index e079de0..df5f31a 100644 --- a/app/Http/Controllers/Admin/RoomController.php +++ b/app/Http/Controllers/Admin/RoomController.php @@ -8,18 +8,16 @@ use App\Models\BonusScoreDefinition; use App\Models\Room; use App\Models\User; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; use Illuminate\Validation\Rule; +use function auditionLog; use function redirect; class RoomController extends Controller { public function index() { - if (! Auth::user()->is_admin) { - abort(403); - } + $rooms = Room::with('auditions.entries', 'entries')->orderBy('name')->get(); if (! $rooms->contains('id', 0)) { $unassignedRoom = Room::create([ @@ -30,7 +28,7 @@ class RoomController extends Controller $unassignedRoom->id = 0; $unassignedRoom->save(); - $auditionsToUpdate = Audition::where('room_id', null)->get(); + $auditionsToUpdate = Audition::whereNull('room_id')->get(); foreach ($auditionsToUpdate as $audition) { $audition->room_id = 0; $audition->save(); @@ -54,9 +52,6 @@ class RoomController extends Controller public function updateJudgeAssignment(Request $request, Room $room) { - if (! Auth::user()->is_admin) { - abort(403); - } $validData = $request->validate([ 'judge' => 'exists:users,id', ]); @@ -70,27 +65,21 @@ class RoomController extends Controller // detach judge on delete $room->removeJudge($judge->id); $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() { - if (! Auth::user()->is_admin) { - abort(403); - } - return view('admin.rooms.create'); } public function store(Request $request) { - if (! Auth::user()->is_admin) { - abort(403); - } $validData = $request->validate([ 'name' => 'required|unique:rooms,name', 'description' => 'nullable', @@ -106,9 +95,6 @@ class RoomController extends Controller public function update(Request $request, Room $room) { - if (! Auth::user()->is_admin) { - abort(403); - } $validData = $request->validate([ 'name' => ['required', Rule::unique('rooms', 'name')->ignore($room->id)], 'description' => 'nullable', @@ -123,10 +109,6 @@ class RoomController extends Controller public function destroy(Room $room) { - if (! Auth::user()->is_admin) { - abort(403); - } - if ($room->auditions()->count() > 0) { return redirect()->route('admin.rooms.index')->with('error', 'Cannot delete room with auditions. First move the auditions to unassigned or another room'); diff --git a/tests/Feature/app/Http/Controllers/Admin/RoomControllerTest.php b/tests/Feature/app/Http/Controllers/Admin/RoomControllerTest.php new file mode 100644 index 0000000..81c01e4 --- /dev/null +++ b/tests/Feature/app/Http/Controllers/Admin/RoomControllerTest.php @@ -0,0 +1,233 @@ +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); + }); +});