Write tests - Write tests for what was done to this point that will be kept #11
|
|
@ -56,10 +56,6 @@ class SchoolController extends Controller
|
||||||
|
|
||||||
public function update(School $school)
|
public function update(School $school)
|
||||||
{
|
{
|
||||||
if (! Auth::user()->is_admin) {
|
|
||||||
abort(403);
|
|
||||||
}
|
|
||||||
|
|
||||||
request()->validate([
|
request()->validate([
|
||||||
'name' => ['required'],
|
'name' => ['required'],
|
||||||
'address' => ['required'],
|
'address' => ['required'],
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Factories;
|
||||||
|
|
||||||
|
use App\Models\School;
|
||||||
|
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\SchoolEmailDomain>
|
||||||
|
*/
|
||||||
|
class SchoolEmailDomainFactory extends Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Define the model's default state.
|
||||||
|
*
|
||||||
|
* @return array<string, mixed>
|
||||||
|
*/
|
||||||
|
public function definition(): array
|
||||||
|
{
|
||||||
|
$school = School::factory()->create();
|
||||||
|
return [
|
||||||
|
'school_id' => $school->id,
|
||||||
|
'domain' => $this->faker->domainName,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,45 @@
|
||||||
<x-layout.app>
|
<x-layout.app>
|
||||||
|
|
||||||
<x-school.school-edit-form :form_action="'admin/schools/' . $school->id " :school="$school" />
|
<x-card.card class="mx-auto max-w-xl">
|
||||||
|
<x-card.heading>Edit School</x-card.heading>
|
||||||
|
<x-form.form method="PATCH" action="{{ route('admin.schools.update',$school) }}">
|
||||||
|
<x-form.body-grid>
|
||||||
|
<x-form.field name="name" label_text="Name" colspan="6" value="{{ $school->name }}" />
|
||||||
|
<x-form.field name="address" label_text="Address" colspan="6" value="{{ $school->address }}" />
|
||||||
|
<x-form.field name="city" label_text="City" colspan="3" value="{{ $school->city }}" />
|
||||||
|
<x-form.field name="state" label_text="State" colspan="2" value="{{ $school->state }}" />
|
||||||
|
<x-form.field name="zip" label_text="Zip" colspan="1" value="{{ $school->zip }}" />
|
||||||
|
</x-form.body-grid>
|
||||||
|
<x-form.footer>
|
||||||
|
<x-form.button class="mb-5">Update School</x-form.button>
|
||||||
|
</x-form.footer>
|
||||||
|
</x-form.form>
|
||||||
|
</x-card.card>
|
||||||
|
|
||||||
<x-school.school-domain-form :school="$school" />
|
<x-card.card class="mx-auto max-w-sm mt-8">
|
||||||
|
<x-card.heading>Associated Domains</x-card.heading>
|
||||||
|
<x-card.list.body>
|
||||||
|
@foreach($school->emailDomains as $domain)
|
||||||
|
<x-card.list.row class="!py-1.5 align-middle">
|
||||||
|
<form method="POST" action="{{ route('admin.schools.destroy_domain',$domain) }}" id="deleteDomain{{$domain->id}}">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit">
|
||||||
|
<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path fill-rule="evenodd" d="M2 12C2 6.477 6.477 2 12 2s10 4.477 10 10-4.477 10-10 10S2 17.523 2 12Zm7.707-3.707a1 1 0 0 0-1.414 1.414L10.586 12l-2.293 2.293a1 1 0 1 0 1.414 1.414L12 13.414l2.293 2.293a1 1 0 0 0 1.414-1.414L13.414 12l2.293-2.293a1 1 0 0 0-1.414-1.414L12 10.586 9.707 8.293Z" clip-rule="evenodd"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
</button><span class="px-3">{{ $domain->domain }}</span>
|
||||||
|
</form>
|
||||||
|
</x-card.list.row>
|
||||||
|
@endforeach
|
||||||
|
<x-card.list.row class="!py-1.5">
|
||||||
|
<form method="POST" action="{{ route('admin.schools.add_domain',$school) }}" class="grid sm:grid-cols-2 gap-4">
|
||||||
|
@csrf
|
||||||
|
<x-form.field name="domain" label_text="Add Domain" /><x-form.button class="sm:mt-6">Add Domain</x-form.button>
|
||||||
|
</form>
|
||||||
|
</x-card.list.row>
|
||||||
|
</x-card.list.body>
|
||||||
|
</x-card.card>
|
||||||
|
|
||||||
</x-layout.app>
|
</x-layout.app>
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,11 @@ beforeEach(function () {
|
||||||
it('only shows for an admin user', function () {
|
it('only shows for an admin user', function () {
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
$checkRoute = 'admin.schools.create';
|
$checkRoute = 'admin.schools.create';
|
||||||
get(route($checkRoute, $this->school))->assertRedirect(route('home'));
|
get(route($checkRoute))->assertRedirect(route('home'));
|
||||||
actingAs($this->adminUser);
|
actingAs($this->adminUser);
|
||||||
get(route($checkRoute, $this->school))->assertOk();
|
get(route($checkRoute))->assertOk();
|
||||||
actingAs($this->nonAdminUser);
|
actingAs($this->nonAdminUser);
|
||||||
get(route($checkRoute, $this->school))->assertRedirect(route('dashboard'));
|
get(route($checkRoute))->assertRedirect(route('dashboard'));
|
||||||
});
|
});
|
||||||
it('submits a post request', function () {
|
it('submits a post request', function () {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,192 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use App\Models\School;
|
||||||
|
use App\Models\User;
|
||||||
|
use Database\Factories\SchoolEmailDomainFactory;
|
||||||
|
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;
|
||||||
|
use function Pest\Laravel\post;
|
||||||
|
|
||||||
|
uses(RefreshDatabase::class);
|
||||||
|
beforeEach(function () {
|
||||||
|
$this->adminUser = User::factory()->admin()->create();
|
||||||
|
$this->nonAdminUser = User::factory()->create();
|
||||||
|
$this->tabUser = User::factory()->tab()->create();
|
||||||
|
$this->school = School::factory()->create();
|
||||||
|
});
|
||||||
|
it('only shows for an admin user', function () {
|
||||||
|
// Act & Assert
|
||||||
|
$checkRoute = 'admin.schools.edit';
|
||||||
|
get(route($checkRoute, $this->school))->assertRedirect(route('home'));
|
||||||
|
actingAs($this->adminUser);
|
||||||
|
get(route($checkRoute, $this->school))->assertOk();
|
||||||
|
actingAs($this->nonAdminUser);
|
||||||
|
get(route($checkRoute, $this->school))->assertRedirect(route('dashboard'));
|
||||||
|
});
|
||||||
|
it('submits a patch request', function () {
|
||||||
|
// Arrange
|
||||||
|
actingAs($this->adminUser);
|
||||||
|
// Act & Assert
|
||||||
|
$response = get(route('admin.schools.edit', $this->school));
|
||||||
|
$response->assertOk();
|
||||||
|
$response->assertSeeInOrder([
|
||||||
|
'form',
|
||||||
|
'method',
|
||||||
|
'POST',
|
||||||
|
'action=',
|
||||||
|
route('admin.schools.update', $this->school),
|
||||||
|
'/form',
|
||||||
|
]);
|
||||||
|
$response->assertSee('<input type="hidden" name="_method" value="PATCH">', false);
|
||||||
|
});
|
||||||
|
it('has all needed fields', function () {
|
||||||
|
// Arrange
|
||||||
|
actingAs($this->adminUser);
|
||||||
|
$fieldNames = [
|
||||||
|
'name',
|
||||||
|
'address',
|
||||||
|
'city',
|
||||||
|
'state',
|
||||||
|
'zip',
|
||||||
|
];
|
||||||
|
// Act & Assert
|
||||||
|
$response = get(route('admin.schools.edit', $this->school));
|
||||||
|
$response->assertOk();
|
||||||
|
foreach ($fieldNames as $fieldName) {
|
||||||
|
$response->assertSeeInOrder([
|
||||||
|
'input',
|
||||||
|
'name=',
|
||||||
|
$fieldName,
|
||||||
|
'/',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it('rejects a submission by a non administrator', function () {
|
||||||
|
// Arrange
|
||||||
|
actingAs($this->nonAdminUser);
|
||||||
|
// Act & Assert
|
||||||
|
$response = patch(route('admin.schools.update', $this->school), [
|
||||||
|
'name' => 'Hacker High',
|
||||||
|
'address' => 'Lost Highway',
|
||||||
|
]);
|
||||||
|
$response->assertRedirect(route('dashboard'));
|
||||||
|
});
|
||||||
|
it('allows an administrator to update a school', function () {
|
||||||
|
// Arrange
|
||||||
|
actingAs($this->adminUser);
|
||||||
|
$newData = [
|
||||||
|
'name' => fake()->city(),
|
||||||
|
'address' => fake()->streetAddress(),
|
||||||
|
'city' => fake()->city(),
|
||||||
|
'state' => 'OK',
|
||||||
|
'zip' => fake()->postcode(),
|
||||||
|
];
|
||||||
|
// Act
|
||||||
|
$response = patch(route('admin.schools.update', $this->school), $newData);
|
||||||
|
/** @noinspection PhpUnhandledExceptionInspection */
|
||||||
|
$response
|
||||||
|
->assertSessionHasNoErrors()
|
||||||
|
->assertRedirect(route('admin.schools.show', $this->school));
|
||||||
|
|
||||||
|
$this->school->refresh();
|
||||||
|
|
||||||
|
expect($this->school->name)->toBe($newData['name'])
|
||||||
|
->and($this->school->address)->toBe($newData['address'])
|
||||||
|
->and($this->school->city)->toBe($newData['city'])
|
||||||
|
->and($this->school->state)->toBe($newData['state'])
|
||||||
|
->and($this->school->zip)->toEqual($newData['zip']);
|
||||||
|
|
||||||
|
get(route('admin.schools.index'))
|
||||||
|
->assertOk()
|
||||||
|
->assertSee($newData['name']);
|
||||||
|
});
|
||||||
|
it('has a domain add form', function () {
|
||||||
|
// Arrange
|
||||||
|
actingAs($this->adminUser);
|
||||||
|
// Act & Assert
|
||||||
|
get(route('admin.schools.edit', $this->school))
|
||||||
|
->assertOk()
|
||||||
|
->assertSeeInOrder([
|
||||||
|
'form',
|
||||||
|
'method',
|
||||||
|
'POST',
|
||||||
|
'action=',
|
||||||
|
route('admin.schools.add_domain', $this->school),
|
||||||
|
'/form',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('as a field to submit a new domain', function () {
|
||||||
|
// Arrange
|
||||||
|
actingAs($this->adminUser);
|
||||||
|
// Act & Assert
|
||||||
|
get(route('admin.schools.edit', $this->school))
|
||||||
|
->assertOk()
|
||||||
|
->assertSeeInOrder([
|
||||||
|
'input',
|
||||||
|
'name=',
|
||||||
|
'domain',
|
||||||
|
'/',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('allows an administrator to add a domain and shows it on the school edit page', function () {
|
||||||
|
// Arrange
|
||||||
|
actingAs($this->adminUser);
|
||||||
|
$newDomain = 'example.com';
|
||||||
|
// Act
|
||||||
|
$response = post(route('admin.schools.add_domain', $this->school), ['domain' => $newDomain]);
|
||||||
|
/** @noinspection PhpUnhandledExceptionInspection */
|
||||||
|
$response
|
||||||
|
->assertSessionHasNoErrors()
|
||||||
|
->assertRedirect(route('admin.schools.edit', $this->school));
|
||||||
|
|
||||||
|
$this->school->refresh();
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('school_email_domains', ['school_id' => $this->school->id, 'domain' => $newDomain]);
|
||||||
|
|
||||||
|
get(route('admin.schools.edit', $this->school))
|
||||||
|
->assertOk()
|
||||||
|
->assertSee($newDomain);
|
||||||
|
});
|
||||||
|
it('rejects a domain submission by a non administrator', function () {
|
||||||
|
// Arrange
|
||||||
|
actingAs($this->nonAdminUser);
|
||||||
|
// Act & Assert
|
||||||
|
$response = post(route('admin.schools.add_domain', $this->school), ['domain' => 'example.com']);
|
||||||
|
$response->assertRedirect(route('dashboard'));
|
||||||
|
});
|
||||||
|
it('shows a delete button for each domain', function () {
|
||||||
|
// Arrange
|
||||||
|
actingAs($this->adminUser);
|
||||||
|
$domain = $this->school->emailDomains()->create(['domain' => 'example.com']);
|
||||||
|
// Act & Assert
|
||||||
|
get(route('admin.schools.edit', $this->school))
|
||||||
|
->assertOk()
|
||||||
|
->assertSee(route('admin.schools.destroy_domain', $domain));
|
||||||
|
});
|
||||||
|
it('allows an admin to delete a domain', function () {
|
||||||
|
// Arrange
|
||||||
|
session()->setPreviousUrl(route('admin.schools.edit', $this->school));
|
||||||
|
actingAs($this->adminUser);
|
||||||
|
$domain = $this->school->emailDomains()->create(['domain' => 'example.com']);
|
||||||
|
// Act
|
||||||
|
$response = delete(route('admin.schools.destroy_domain', $domain));
|
||||||
|
/** @noinspection PhpUnhandledExceptionInspection */
|
||||||
|
$response
|
||||||
|
->assertSessionHasNoErrors()
|
||||||
|
->assertRedirect(route('admin.schools.edit', $this->school));
|
||||||
|
|
||||||
|
$this->assertDatabaseMissing('school_email_domains', ['id' => $domain->id]);
|
||||||
|
|
||||||
|
});
|
||||||
|
it('does not allow a non admin user to delete a domain', function () {
|
||||||
|
// Arrange
|
||||||
|
actingAs($this->nonAdminUser);
|
||||||
|
$domain = SchoolEmailDomainFactory::new()->create();
|
||||||
|
// Act & Assert
|
||||||
|
$response = delete(route('admin.schools.destroy_domain', $domain));
|
||||||
|
$response->assertRedirect(route('dashboard'));
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue