add test for admin EnsembleController
This commit is contained in:
parent
fa25e76c5b
commit
e1d72ee040
|
|
@ -1,10 +1,10 @@
|
|||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="tests - paralell" type="PestRunConfigurationType">
|
||||
<configuration default="false" name="tests - paralell with HTML to reports" type="PestRunConfigurationType">
|
||||
<option name="pestRunnerSettings">
|
||||
<PestRunner directory="$PROJECT_DIR$/tests" method="" options="--parallel --recreate-databases" />
|
||||
<PestRunner directory="$PROJECT_DIR$/tests" method="" options="--parallel --recreate-databases --coverage-html reports" />
|
||||
</option>
|
||||
<option name="runnerSettings">
|
||||
<PhpTestRunnerSettings directory="$PROJECT_DIR$/tests" method="" options="--parallel --recreate-databases" />
|
||||
<PhpTestRunnerSettings directory="$PROJECT_DIR$/tests" method="" options="--parallel --recreate-databases --coverage-html reports" />
|
||||
</option>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
|
|
@ -3,12 +3,13 @@
|
|||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\EnsembleStoreOrUpdateRequest;
|
||||
use App\Models\Ensemble;
|
||||
use App\Models\Event;
|
||||
use App\Models\SeatingLimit;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use function redirect;
|
||||
|
||||
|
|
@ -21,30 +22,24 @@ class EnsembleController extends Controller
|
|||
return view('admin.ensembles.index', compact('events'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
public function store(EnsembleStoreOrUpdateRequest $request)
|
||||
{
|
||||
if (! Auth::user()->is_admin) {
|
||||
abort(403);
|
||||
}
|
||||
request()->validate([
|
||||
'name' => 'required',
|
||||
'code' => ['required', 'max:6'],
|
||||
'event_id' => ['required', 'exists:events,id'],
|
||||
]);
|
||||
// get the maximum value of rank from the ensembles table where event_id is equal to the request event_id
|
||||
Log::channel('file')->warning('hello');
|
||||
$validated = $request->validated();
|
||||
// get the maximum value of rank from the ensemble table where event_id is equal to the request event_id
|
||||
$maxCode = Ensemble::where('event_id', request('event_id'))->max('rank');
|
||||
|
||||
Ensemble::create([
|
||||
'name' => request('name'),
|
||||
'code' => request('code'),
|
||||
'event_id' => request('event_id'),
|
||||
'name' => $validated['name'],
|
||||
'code' => $validated['code'],
|
||||
'event_id' => $validated['event_id'],
|
||||
'rank' => $maxCode + 1,
|
||||
]);
|
||||
|
||||
return redirect()->route('admin.ensembles.index')->with('success', 'Ensemble created successfully');
|
||||
}
|
||||
|
||||
public function destroy(Request $request, Ensemble $ensemble)
|
||||
public function destroy(Ensemble $ensemble)
|
||||
{
|
||||
if ($ensemble->seats->count() > 0) {
|
||||
return redirect()->route('admin.ensembles.index')->with('error',
|
||||
|
|
@ -55,25 +50,32 @@ class EnsembleController extends Controller
|
|||
return redirect()->route('admin.ensembles.index')->with('success', 'Ensemble deleted successfully');
|
||||
}
|
||||
|
||||
public function updateEnsemble(Request $request, Ensemble $ensemble)
|
||||
public function update(EnsembleStoreOrUpdateRequest $request, Ensemble $ensemble)
|
||||
{
|
||||
request()->validate([
|
||||
'name' => 'required',
|
||||
'code' => 'required|max:6',
|
||||
]);
|
||||
$valid = $request->validated();
|
||||
|
||||
$ensemble->update([
|
||||
'name' => request('name'),
|
||||
'code' => request('code'),
|
||||
'name' => $valid['name'],
|
||||
'code' => $valid['code'],
|
||||
]);
|
||||
|
||||
return redirect()->route('admin.ensembles.index')->with('success', 'Ensemble updated successfully');
|
||||
}
|
||||
|
||||
//TODO Consider moving seating limit related functions to their own controller with index, edit, and update methods
|
||||
public function seatingLimits(Ensemble $ensemble)
|
||||
{
|
||||
$limits = [];
|
||||
$ensembles = Ensemble::with(['event'])->orderBy('event_id')->get();
|
||||
/**
|
||||
* If we weren't called with an ensemble, we're going to use an array of ensembles to fill a drop-down and
|
||||
* choose one. The user will be sent back here, this time with the chosen audition.
|
||||
*/
|
||||
$ensembles = Ensemble::with(['event'])->orderBy('event_id')->orderBy('rank')->get();
|
||||
|
||||
/**
|
||||
* If we were called with an ensemble, we need to load existing seating limits. We will put them in an array
|
||||
* indexed by audition_id for easy use in the form to set seating limits.
|
||||
*/
|
||||
if ($ensemble->exists()) {
|
||||
$ensemble->load('seatingLimits');
|
||||
foreach ($ensemble->seatingLimits as $lim) {
|
||||
|
|
@ -112,10 +114,6 @@ class EnsembleController extends Controller
|
|||
|
||||
public function updateEnsembleRank(Request $request)
|
||||
{
|
||||
if (! Auth::user()->is_admin) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
$order = $request->input('order');
|
||||
$eventId = $request->input('event_id');
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class EnsembleStoreOrUpdateRequest extends FormRequest
|
||||
{
|
||||
public function authorize(): true
|
||||
{
|
||||
// Adjust authorization logic as needed
|
||||
return true;
|
||||
}
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
// Get the ID of the ensemble being updated, if any
|
||||
$ensembleId = $this->route('ensemble')?->id;
|
||||
|
||||
return [
|
||||
'name' => [
|
||||
'required',
|
||||
// Composite unique rule on (event_id, name)
|
||||
Rule::unique('ensembles')->where(function ($query) {
|
||||
return $query->where('event_id', $this->input('event_id'));
|
||||
})->ignore($ensembleId),
|
||||
],
|
||||
'code' => ['required', 'max:6'],
|
||||
'event_id' => ['required', 'exists:events,id'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ Route::middleware(['auth', 'verified', CheckIfAdmin::class])->prefix('admin/')->
|
|||
Route::post('/', 'store')->name('admin.ensembles.store');
|
||||
Route::delete('/{ensemble}', 'destroy')->name('admin.ensembles.destroy');
|
||||
Route::post('/updateEnsembleRank', 'updateEnsembleRank')->name('admin.ensembles.updateEnsembleRank');
|
||||
Route::patch('/{ensemble}', 'updateEnsemble')->name('admin.ensembles.update');
|
||||
Route::patch('/{ensemble}', 'update')->name('admin.ensembles.update');
|
||||
Route::get('/seating-limits', 'seatingLimits')->name('admin.ensembles.seatingLimits');
|
||||
Route::get('/seating-limits/{ensemble}', 'seatingLimits')->name('admin.ensembles.seatingLimits.ensemble');
|
||||
Route::post('/seating-limits/{ensemble}',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,209 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Audition;
|
||||
use App\Models\Ensemble;
|
||||
use App\Models\Entry;
|
||||
use App\Models\Event;
|
||||
use App\Models\Seat;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
beforeEach(function () {
|
||||
$this->ensemble = Ensemble::create([
|
||||
'name' => 'Wind Ensemble',
|
||||
'rank' => 1,
|
||||
'code' => 'we',
|
||||
'event_id' => Event::factory()->create()->id,
|
||||
]);
|
||||
});
|
||||
|
||||
describe('EnsembleController::index', function () {
|
||||
it('denies access to non-admin users', function () {
|
||||
$this->get(route('admin.ensembles.index'))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->get(route('admin.ensembles.index'))->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->get(route('admin.ensembles.index'))->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('shows an index of events', function () {
|
||||
actAsAdmin();
|
||||
$this->get(route('admin.ensembles.index'))->assertOk()
|
||||
->assertSee($this->ensemble->name);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EnsembleController::store', function () {
|
||||
it('denies access to non-admin users', function () {
|
||||
$this->post(route('admin.ensembles.store'))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->post(route('admin.ensembles.store'))->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->post(route('admin.ensembles.store'))->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('creates an ensemble', function () {
|
||||
actAsAdmin();
|
||||
$this->post(route('admin.ensembles.store'), [
|
||||
'name' => 'New Ensemble',
|
||||
'code' => 'ne',
|
||||
'event_id' => Event::factory()->create()->id,
|
||||
])->assertRedirect(route('admin.ensembles.index'))->assertSessionHas('success');
|
||||
});
|
||||
});
|
||||
|
||||
describe('EnsembleController::destroy', function () {
|
||||
it('denies access to non-admin users', function () {
|
||||
$this->delete(route('admin.ensembles.destroy', $this->ensemble))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->delete(route('admin.ensembles.destroy', $this->ensemble))->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->delete(route('admin.ensembles.destroy', $this->ensemble))->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('will not destroy an ensemble with seated students', function () {
|
||||
actAsAdmin();
|
||||
$audition = Audition::factory()->create();
|
||||
$entry = Entry::factory()->create();
|
||||
Seat::create([
|
||||
'ensemble_id' => $this->ensemble->id,
|
||||
'audition_id' => $audition->id,
|
||||
'seat' => 3,
|
||||
'entry_id' => $entry->id,
|
||||
]);
|
||||
$this->delete(route('admin.ensembles.destroy', $this->ensemble))->assertRedirect(route('admin.ensembles.index'))
|
||||
->assertSessionHas('error', 'Ensemble has students seated and cannot be deleted');
|
||||
});
|
||||
it('can delete an ensemble', function () {
|
||||
$startCount = Ensemble::count();
|
||||
actAsAdmin();
|
||||
$this->delete(route('admin.ensembles.destroy', $this->ensemble))->assertRedirect(route('admin.ensembles.index'))
|
||||
->assertSessionHas('success', 'Ensemble deleted successfully');
|
||||
expect(Ensemble::count())->toEqual($startCount - 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EnsembleController::update', function () {
|
||||
it('denies access to non-admin users', function () {
|
||||
$this->patch(route('admin.ensembles.update', $this->ensemble))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->patch(route('admin.ensembles.update', $this->ensemble))->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->patch(route('admin.ensembles.update', $this->ensemble))->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('can update an event', function () {
|
||||
$event = Event::factory()->create();
|
||||
actAsAdmin();
|
||||
$response = $this->patch(route('admin.ensembles.update', $this->ensemble), [
|
||||
'name' => 'Wind Ensemble Restart',
|
||||
'code' => 'we2',
|
||||
'event_id' => $event->id,
|
||||
]);
|
||||
$response->assertRedirect(route('admin.ensembles.index'))
|
||||
->assertSessionHas('success', 'Ensemble updated successfully');
|
||||
});
|
||||
});
|
||||
|
||||
describe('EnsembleController::seatingLimits with no ensemble', function () {
|
||||
|
||||
it('denies access to non-admin users', function () {
|
||||
$this->get(route('admin.ensembles.seatingLimits'))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->get(route('admin.ensembles.seatingLimits'))->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->get(route('admin.ensembles.seatingLimits'))->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('returns a page to choose and ensemble for which to set limits', function () {
|
||||
actAsAdmin();
|
||||
$response = $this->get(route('admin.ensembles.seatingLimits'))->assertOk()
|
||||
->assertViewIs('admin.ensembles.seatingLimits')
|
||||
->assertViewHas('ensembles');
|
||||
expect($response->viewData('ensemble')->exists)->toBeFalse()
|
||||
->and($response->viewData('ensembles')->first()->id)->toEqual($this->ensemble->id)
|
||||
->and($response->viewData('limits'))->toBe([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EnsembleController::seatingLimits get with ensemble', function () {
|
||||
it('denies access to non-admin users', function () {
|
||||
$this->get(route('admin.ensembles.seatingLimits', $this->ensemble))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->get(route('admin.ensembles.seatingLimits', $this->ensemble))->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->get(route('admin.ensembles.seatingLimits', $this->ensemble))->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('displays a form with fields for every audition to set the max for this ensemble', function () {
|
||||
actAsAdmin();
|
||||
$auditions = Audition::factory()->count(5)->create(['event_id' => $this->ensemble->event_id]);
|
||||
DB::table('seating_limits')->insert([
|
||||
'ensemble_id' => $this->ensemble->id,
|
||||
'audition_id' => $auditions[0]->id,
|
||||
'maximum_accepted' => 6,
|
||||
]);
|
||||
$response = $this->get(route('admin.ensembles.seatingLimits.ensemble.set', $this->ensemble))->assertOk();
|
||||
foreach (Audition::all() as $audition) {
|
||||
$response->assertSee('audition['.$audition->id.']');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('EnsembleController::seatingLimitsSet', function () {
|
||||
it('denies access to non-admin users', function () {
|
||||
$this->post(route('admin.ensembles.seatingLimits.ensemble.set',
|
||||
$this->ensemble))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->post(route('admin.ensembles.seatingLimits.ensemble.set',
|
||||
$this->ensemble))->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->post(route('admin.ensembles.seatingLimits.ensemble.set',
|
||||
$this->ensemble))->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('sets seating limits', function () {
|
||||
actAsAdmin();
|
||||
$auditions = Audition::factory()->count(3)->create(['event_id' => $this->ensemble->event_id]);
|
||||
$response = $this->post(route('admin.ensembles.seatingLimits.ensemble.set', $this->ensemble), [
|
||||
'audition' => [
|
||||
$auditions[0]->id => 5,
|
||||
$auditions[1]->id => 10,
|
||||
$auditions[2]->id => 20,
|
||||
],
|
||||
]);
|
||||
$response->assertRedirect(route('admin.ensembles.seatingLimits.ensemble', $this->ensemble))
|
||||
->assertSessionHas('success', 'Seating limits set for '.$this->ensemble->name);
|
||||
});
|
||||
});
|
||||
|
||||
describe('EnsembleController::updateEnsembleRank', function () {
|
||||
it('denies access to non-admin users', function () {
|
||||
$this->post(route('admin.ensembles.updateEnsembleRank'))->assertRedirect(route('home'));
|
||||
actAsNormal();
|
||||
$this->post(route('admin.ensembles.updateEnsembleRank'))->assertRedirect(route('dashboard'));
|
||||
actAsTab();
|
||||
$this->post(route('admin.ensembles.updateEnsembleRank'))->assertRedirect(route('dashboard'));
|
||||
});
|
||||
it('reorders ensembles', function () {
|
||||
actAsAdmin();
|
||||
$newEnsemble = Ensemble::create([
|
||||
'name' => 'Alternates',
|
||||
'code' => 'Alt',
|
||||
'rank' => 2,
|
||||
'event_id' => $this->ensemble->event_id,
|
||||
]);
|
||||
expect($this->ensemble->rank)->toBe(1);
|
||||
expect($newEnsemble->rank)->toBe(2);
|
||||
$response = $this->post(route('admin.ensembles.updateEnsembleRank'), [
|
||||
'event_id' => $this->ensemble->event_id,
|
||||
'order' => [
|
||||
[
|
||||
'id' => $this->ensemble->id,
|
||||
'rank' => 2,
|
||||
],
|
||||
[
|
||||
'id' => $newEnsemble->id,
|
||||
'rank' => 1,
|
||||
],
|
||||
],
|
||||
])->assertJson(['status' => 'success']);
|
||||
$this->ensemble->refresh();
|
||||
$newEnsemble->refresh();
|
||||
expect($this->ensemble->rank)->toBe(2);
|
||||
expect($newEnsemble->rank)->toBe(1);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue