test: Add feature tests for Classification and SubClassification resources to validate CRUD operations and permission handling.
This commit is contained in:
parent
21be2fbb5e
commit
229ba24fef
@ -0,0 +1,199 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\IsActive;
|
||||
use App\Enums\RoleEnum;
|
||||
use App\Filament\Resources\Master\Classifications\Pages\ManageClassifications;
|
||||
use App\Models\Classification;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->user = User::factory()->create(['is_active' => IsActive::ACTIVE]);
|
||||
|
||||
// Setup Permissions
|
||||
Permission::firstOrCreate(['name' => 'ViewAny:Classification', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'Create:Classification', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'Update:Classification', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'Delete:Classification', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'Restore:Classification', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'ForceDelete:Classification', 'guard_name' => 'web']);
|
||||
|
||||
$this->user->givePermissionTo([
|
||||
'ViewAny:Classification',
|
||||
'Create:Classification',
|
||||
'Update:Classification',
|
||||
'Delete:Classification',
|
||||
'Restore:Classification',
|
||||
'ForceDelete:Classification',
|
||||
]);
|
||||
});
|
||||
|
||||
test('can render classification list page', function () {
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->assertSuccessful();
|
||||
});
|
||||
|
||||
test('can list classifications', function () {
|
||||
$classifications = Classification::factory()->count(5)->create();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->call('loadTable')
|
||||
->assertCanSeeTableRecords($classifications);
|
||||
});
|
||||
|
||||
test('can create classification', function () {
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->mountAction('create')
|
||||
->setActionData([
|
||||
'name' => 'Klasifikasi Baru',
|
||||
])
|
||||
->callMountedAction()
|
||||
->assertHasNoActionErrors();
|
||||
|
||||
$this->assertDatabaseHas('classifications', [
|
||||
'name' => 'Klasifikasi Baru',
|
||||
'is_active' => IsActive::ACTIVE->value,
|
||||
]);
|
||||
});
|
||||
|
||||
test('cannot create classification with empty name', function () {
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->mountAction('create')
|
||||
->setActionData(['name' => ''])
|
||||
->callMountedAction()
|
||||
->assertHasActionErrors(['name' => 'required']);
|
||||
});
|
||||
|
||||
test('cannot create classification with name exceeding 50 characters', function () {
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->mountAction('create')
|
||||
->setActionData(['name' => str_repeat('a', 51)])
|
||||
->callMountedAction()
|
||||
->assertHasActionErrors(['name' => 'max']);
|
||||
});
|
||||
|
||||
test('can edit classification', function () {
|
||||
$classification = Classification::factory()->create();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->mountTableAction('edit', $classification)
|
||||
->setActionData([
|
||||
'name' => 'Klasifikasi Updated',
|
||||
])
|
||||
->callMountedTableAction()
|
||||
->assertHasNoActionErrors();
|
||||
|
||||
expect($classification->refresh()->name)->toBe('Klasifikasi Updated');
|
||||
});
|
||||
|
||||
test('can toggle is_active status', function () {
|
||||
$classification = Classification::factory()->create(['is_active' => IsActive::INACTIVE]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->call('updateTableColumnState', 'is_active', $classification->getKey(), true);
|
||||
|
||||
expect($classification->refresh()->is_active)->toBe(IsActive::ACTIVE);
|
||||
});
|
||||
|
||||
test('unauthorized user cannot render classification page', function () {
|
||||
$unauthorizedUser = User::factory()->create(['is_active' => IsActive::ACTIVE]);
|
||||
|
||||
$this->actingAs($unauthorizedUser);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
test('user without create permission cannot see create action', function () {
|
||||
$viewOnlyUser = User::factory()->create(['is_active' => IsActive::ACTIVE]);
|
||||
$viewOnlyUser->givePermissionTo('ViewAny:Classification');
|
||||
$classification = Classification::factory()->create();
|
||||
|
||||
$this->actingAs($viewOnlyUser);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->assertActionHidden('create')
|
||||
->assertTableActionHidden('edit', $classification);
|
||||
});
|
||||
|
||||
test('can delete classification', function () {
|
||||
$classification = Classification::factory()->create();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->callTableAction('delete', $classification);
|
||||
|
||||
$this->assertSoftDeleted($classification);
|
||||
});
|
||||
|
||||
test('can restore deleted classification', function () {
|
||||
// Need Developer role to see trashed records via filter
|
||||
$roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
|
||||
$this->user->assignRole($roleDev);
|
||||
|
||||
$classification = Classification::factory()->create(['deleted_at' => now()]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->filterTable('trashed', 'with')
|
||||
->callTableAction('restore', $classification);
|
||||
|
||||
$this->assertDatabaseHas('classifications', [
|
||||
'id' => $classification->id,
|
||||
'deleted_at' => null,
|
||||
]);
|
||||
});
|
||||
|
||||
test('can force delete classification', function () {
|
||||
$roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
|
||||
$this->user->assignRole($roleDev);
|
||||
|
||||
$classification = Classification::factory()->create(['deleted_at' => now()]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->filterTable('trashed', 'only')
|
||||
->callTableAction('forceDelete', $classification);
|
||||
|
||||
$this->assertDatabaseMissing('classifications', ['id' => $classification->id]);
|
||||
});
|
||||
|
||||
test('trashed filter visibility depends on developer role', function () {
|
||||
// Administrator but not Developer
|
||||
$roleAdmin = Role::firstOrCreate(['name' => RoleEnum::ADMINISTRATOR->value, 'guard_name' => 'web']);
|
||||
$this->user->assignRole($roleAdmin);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->assertTableFilterHidden('trashed');
|
||||
|
||||
// Upgrade to Developer
|
||||
$roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
|
||||
$this->user->assignRole($roleDev);
|
||||
|
||||
Livewire::test(ManageClassifications::class)
|
||||
->assertTableFilterVisible('trashed');
|
||||
});
|
||||
@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\IsActive;
|
||||
use App\Enums\RoleEnum;
|
||||
use App\Filament\Resources\Master\SubClassifications\Pages\ManageSubClassifications;
|
||||
use App\Models\Classification;
|
||||
use App\Models\SubClassification;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Livewire\Livewire;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
$this->user = User::factory()->create(['is_active' => IsActive::ACTIVE]);
|
||||
|
||||
// Setup Permissions
|
||||
Permission::firstOrCreate(['name' => 'ViewAny:SubClassification', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'Create:SubClassification', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'Update:SubClassification', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'Delete:SubClassification', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'Restore:SubClassification', 'guard_name' => 'web']);
|
||||
Permission::firstOrCreate(['name' => 'ForceDelete:SubClassification', 'guard_name' => 'web']);
|
||||
|
||||
$this->user->givePermissionTo([
|
||||
'ViewAny:SubClassification',
|
||||
'Create:SubClassification',
|
||||
'Update:SubClassification',
|
||||
'Delete:SubClassification',
|
||||
'Restore:SubClassification',
|
||||
'ForceDelete:SubClassification',
|
||||
]);
|
||||
});
|
||||
|
||||
test('can render sub-classification list page', function () {
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->assertSuccessful();
|
||||
});
|
||||
|
||||
test('can list sub-classifications', function () {
|
||||
$subClassifications = SubClassification::factory()->count(5)->create();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->call('loadTable')
|
||||
->assertCanSeeTableRecords($subClassifications);
|
||||
});
|
||||
|
||||
test('can create sub-classification', function () {
|
||||
$classification = Classification::factory()->create(['is_active' => IsActive::ACTIVE]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->mountAction('create')
|
||||
->setActionData([
|
||||
'classification_id' => $classification->id,
|
||||
'name' => 'Sub Klasifikasi Baru',
|
||||
])
|
||||
->callMountedAction()
|
||||
->assertHasNoActionErrors();
|
||||
|
||||
$this->assertDatabaseHas('sub_classifications', [
|
||||
'classification_id' => $classification->id,
|
||||
'name' => 'Sub Klasifikasi Baru',
|
||||
]);
|
||||
});
|
||||
|
||||
test('cannot create sub-classification with invalid data', function () {
|
||||
$this->actingAs($this->user);
|
||||
|
||||
// Empty name
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->mountAction('create')
|
||||
->setActionData(['name' => '', 'classification_id' => null])
|
||||
->callMountedAction()
|
||||
->assertHasActionErrors(['name' => 'required', 'classification_id' => 'required']);
|
||||
|
||||
// Non-existent classification
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->mountAction('create')
|
||||
->setActionData(['name' => 'Valid Name', 'classification_id' => 999999])
|
||||
->callMountedAction()
|
||||
->assertHasActionErrors(['classification_id']);
|
||||
});
|
||||
|
||||
test('can edit sub-classification', function () {
|
||||
$subClassification = SubClassification::factory()->create();
|
||||
$newClassification = Classification::factory()->create(['is_active' => IsActive::ACTIVE]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->mountTableAction('edit', $subClassification)
|
||||
->setActionData([
|
||||
'classification_id' => $newClassification->id,
|
||||
'name' => 'Sub Klasifikasi Updated',
|
||||
])
|
||||
->callMountedTableAction()
|
||||
->assertHasNoActionErrors();
|
||||
|
||||
expect($subClassification->refresh()->name)->toBe('Sub Klasifikasi Updated');
|
||||
expect($subClassification->classification_id)->toBe($newClassification->id);
|
||||
});
|
||||
|
||||
test('can toggle is_active status', function () {
|
||||
$subClassification = SubClassification::factory()->create(['is_active' => IsActive::INACTIVE]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->call('updateTableColumnState', 'is_active', $subClassification->getKey(), true);
|
||||
|
||||
expect($subClassification->refresh()->is_active)->toBe(IsActive::ACTIVE);
|
||||
});
|
||||
|
||||
test('unauthorized user cannot render sub-classification page', function () {
|
||||
$unauthorizedUser = User::factory()->create(['is_active' => IsActive::ACTIVE]);
|
||||
|
||||
$this->actingAs($unauthorizedUser);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
test('user without update permission cannot see edit action', function () {
|
||||
$viewOnlyUser = User::factory()->create(['is_active' => IsActive::ACTIVE]);
|
||||
$viewOnlyUser->givePermissionTo('ViewAny:SubClassification');
|
||||
$subClassification = SubClassification::factory()->create();
|
||||
|
||||
$this->actingAs($viewOnlyUser);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->assertTableActionHidden('edit', $subClassification);
|
||||
});
|
||||
|
||||
test('can delete sub-classification', function () {
|
||||
$subClassification = SubClassification::factory()->create();
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->callTableAction('delete', $subClassification);
|
||||
|
||||
$this->assertSoftDeleted($subClassification);
|
||||
});
|
||||
|
||||
test('can restore deleted sub-classification', function () {
|
||||
$roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
|
||||
$this->user->assignRole($roleDev);
|
||||
|
||||
$subClassification = SubClassification::factory()->create(['deleted_at' => now()]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->filterTable('trashed', 'with')
|
||||
->callTableAction('restore', $subClassification);
|
||||
|
||||
$this->assertDatabaseHas('sub_classifications', [
|
||||
'id' => $subClassification->id,
|
||||
'deleted_at' => null,
|
||||
]);
|
||||
});
|
||||
|
||||
test('can force delete sub-classification', function () {
|
||||
$roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
|
||||
$this->user->assignRole($roleDev);
|
||||
|
||||
$subClassification = SubClassification::factory()->create(['deleted_at' => now()]);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->filterTable('trashed', 'only')
|
||||
->callTableAction('forceDelete', $subClassification);
|
||||
|
||||
$this->assertDatabaseMissing('sub_classifications', ['id' => $subClassification->id]);
|
||||
});
|
||||
|
||||
test('trashed filter visibility depends on developer role', function () {
|
||||
$roleAdmin = Role::firstOrCreate(['name' => RoleEnum::ADMINISTRATOR->value, 'guard_name' => 'web']);
|
||||
$this->user->assignRole($roleAdmin);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->assertTableFilterHidden('trashed');
|
||||
|
||||
$roleDev = Role::firstOrCreate(['name' => RoleEnum::DEVELOPER->value, 'guard_name' => 'web']);
|
||||
$this->user->assignRole($roleDev);
|
||||
|
||||
Livewire::test(ManageSubClassifications::class)
|
||||
->assertTableFilterVisible('trashed');
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user