652 lines
24 KiB
PHP
652 lines
24 KiB
PHP
<?php
|
|
|
|
use App\Enums\Permission as PermissionEnum;
|
|
use App\Models\Employee;
|
|
use App\Models\User;
|
|
use App\Models\UserProfile;
|
|
use Database\Seeders\RolePermissionSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function () {
|
|
$this->seed(RolePermissionSeeder::class);
|
|
$disk = config('filesystems.default') === 's3' ? 's3' : config('filesystems.default', 'public');
|
|
Storage::fake($disk);
|
|
Storage::fake('public');
|
|
});
|
|
|
|
// ─── Helper ───────────────────────────────────────────────
|
|
|
|
function createEmployeeUserWithPermission(PermissionEnum ...$permissions): User
|
|
{
|
|
$user = User::factory()->create();
|
|
|
|
$user->givePermissionTo(
|
|
array_merge(
|
|
[PermissionEnum::DASHBOARD_VIEW->value],
|
|
array_map(fn (PermissionEnum $p) => $p->value, $permissions)
|
|
)
|
|
);
|
|
|
|
$user->forgetCachedPermissions();
|
|
|
|
return $user;
|
|
}
|
|
|
|
function createEmployeeWithProfile(): User
|
|
{
|
|
$user = User::factory()->create();
|
|
UserProfile::factory()->create([
|
|
'user_id' => $user->id,
|
|
'full_name' => fake()->name(),
|
|
'phone_number' => fake()->numerify('08##########'),
|
|
'gender' => fake()->randomElement(['male', 'female']),
|
|
]);
|
|
Employee::factory()->create(['user_id' => $user->id]);
|
|
$user->assignRole('marketing-offline');
|
|
|
|
return $user;
|
|
}
|
|
|
|
function createDeveloperUser(): User
|
|
{
|
|
$user = User::factory()->create();
|
|
UserProfile::factory()->create([
|
|
'user_id' => $user->id,
|
|
'full_name' => fake()->name(),
|
|
'phone_number' => fake()->numerify('08##########'),
|
|
'gender' => fake()->randomElement(['male', 'female']),
|
|
]);
|
|
$user->assignRole('developer');
|
|
|
|
return $user;
|
|
}
|
|
|
|
function validEmployeePayload(): array
|
|
{
|
|
return [
|
|
'email' => 'pegawai@example.com',
|
|
'username' => 'pegawai_baru',
|
|
'full_name' => 'Pegawai Baru',
|
|
'phone_number' => '081234567890',
|
|
'gender' => 'male',
|
|
'birth_date' => '1995-01-15',
|
|
'address' => 'Jl. Merdeka No. 1',
|
|
'role' => 'marketing-offline',
|
|
'join_date' => '2024-01-01',
|
|
'employment_status' => 'full_time',
|
|
'base_salary' => 5000000,
|
|
];
|
|
}
|
|
|
|
// ─── Index ────────────────────────────────────────────────
|
|
|
|
describe('Employee Index', function () {
|
|
test('authenticated user with permission can view employee index', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.index'))
|
|
->assertOk();
|
|
});
|
|
|
|
test('guest is redirected to login', function () {
|
|
$this->get(route('admin.hr.employees.index'))
|
|
->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('user without permission is forbidden', function () {
|
|
$user = User::factory()->create();
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.index'))
|
|
->assertForbidden();
|
|
});
|
|
|
|
test('index displays employees', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
createEmployeeWithProfile();
|
|
createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.index'))
|
|
->assertOk();
|
|
});
|
|
|
|
test('index can search by name', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
$employee->profile->update(['full_name' => 'Budi Santoso']);
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.index', ['search' => 'Budi']))
|
|
->assertOk();
|
|
});
|
|
|
|
test('index can filter by role', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.index', ['role' => 'marketing-offline']))
|
|
->assertOk();
|
|
});
|
|
|
|
test('index can filter by is_active status', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.index', ['is_active' => '1']))
|
|
->assertOk();
|
|
});
|
|
|
|
test('index does not display developer role users', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
$developer = createDeveloperUser();
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.index'))
|
|
->assertOk()
|
|
->assertDontSee($developer->email)
|
|
->assertSee($employee->email);
|
|
});
|
|
});
|
|
|
|
// ─── Create ───────────────────────────────────────────────
|
|
|
|
describe('Employee Create', function () {
|
|
test('authenticated user with permission can view create form', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.create'))
|
|
->assertOk();
|
|
});
|
|
|
|
test('guest is redirected to login', function () {
|
|
$this->get(route('admin.hr.employees.create'))
|
|
->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('user without create permission is forbidden', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.create'))
|
|
->assertForbidden();
|
|
});
|
|
});
|
|
|
|
// ─── Store ────────────────────────────────────────────────
|
|
|
|
describe('Employee Store', function () {
|
|
test('authenticated user with permission can create an employee', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), validEmployeePayload())
|
|
->assertRedirect(route('admin.hr.employees.index'));
|
|
|
|
$this->assertDatabaseHas('users', [
|
|
'email' => 'pegawai@example.com',
|
|
'username' => 'pegawai_baru',
|
|
]);
|
|
});
|
|
|
|
test('guest cannot create an employee', function () {
|
|
$this->post(route('admin.hr.employees.store'), validEmployeePayload())
|
|
->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('user without create permission is forbidden', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), validEmployeePayload())
|
|
->assertForbidden();
|
|
});
|
|
|
|
test('email is required', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['email'] = '';
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('email');
|
|
});
|
|
|
|
test('email must be unique', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$existing = User::factory()->create();
|
|
$payload = validEmployeePayload();
|
|
$payload['email'] = $existing->email;
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('email');
|
|
});
|
|
|
|
test('username is required', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['username'] = '';
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('username');
|
|
});
|
|
|
|
test('username must be unique', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$existing = User::factory()->create();
|
|
$payload = validEmployeePayload();
|
|
$payload['username'] = $existing->username;
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('username');
|
|
});
|
|
|
|
test('full_name is required', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['full_name'] = '';
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('full_name');
|
|
});
|
|
|
|
test('role is required', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['role'] = '';
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('role');
|
|
});
|
|
|
|
test('role must be assignable', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['role'] = 'developer';
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('role');
|
|
});
|
|
|
|
test('join_date is required for non-owner roles', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['join_date'] = '';
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('join_date');
|
|
});
|
|
|
|
test('employment_status is required for non-owner roles', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['employment_status'] = '';
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('employment_status');
|
|
});
|
|
|
|
test('base_salary is required for non-owner roles', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['base_salary'] = '';
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('base_salary');
|
|
});
|
|
|
|
test('phone_number must be valid format', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['phone_number'] = '123invalid';
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload)
|
|
->assertSessionHasErrors('phone_number');
|
|
});
|
|
|
|
test('creating employee also creates profile and employee record', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), validEmployeePayload());
|
|
|
|
$newUser = User::where('email', 'pegawai@example.com')->first();
|
|
expect($newUser)->not->toBeNull();
|
|
expect($newUser->profile)->not->toBeNull();
|
|
expect($newUser->employee)->not->toBeNull();
|
|
expect($newUser->profile->full_name)->toBe('Pegawai Baru');
|
|
expect($newUser->employee->base_salary)->toBe(5000000);
|
|
});
|
|
|
|
test('creating employee with profile photo s3 key links the photo', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_CREATE);
|
|
|
|
$disk = config('filesystems.default') === 's3' ? 's3' : config('filesystems.default', 'public');
|
|
$imageContent = UploadedFile::fake()->image('avatar.jpg')->get();
|
|
Storage::disk($disk)->put('fake-s3-key.jpg', $imageContent);
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['profile_s3_key'] = 'fake-s3-key.jpg';
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.store'), $payload);
|
|
|
|
$newUser = User::where('email', 'pegawai@example.com')->first();
|
|
expect($newUser)->not->toBeNull();
|
|
expect($newUser->profile->getMedia('profile_photo')->count())->toBe(1);
|
|
});
|
|
});
|
|
|
|
// ─── Edit ─────────────────────────────────────────────────
|
|
|
|
describe('Employee Edit', function () {
|
|
test('authenticated user with permission can view edit form', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_UPDATE);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.edit', $employee))
|
|
->assertOk();
|
|
});
|
|
|
|
test('guest is redirected to login', function () {
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->get(route('admin.hr.employees.edit', $employee))
|
|
->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('user without update permission is forbidden', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->get(route('admin.hr.employees.edit', $employee))
|
|
->assertForbidden();
|
|
});
|
|
});
|
|
|
|
// ─── Update ───────────────────────────────────────────────
|
|
|
|
describe('Employee Update', function () {
|
|
test('authenticated user with permission can update an employee', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_UPDATE);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['email'] = $employee->email;
|
|
$payload['username'] = $employee->username;
|
|
$payload['full_name'] = 'Nama Diubah';
|
|
|
|
$this->actingAs($user)
|
|
->put(route('admin.hr.employees.update', $employee), $payload)
|
|
->assertRedirect(route('admin.hr.employees.index'));
|
|
|
|
expect($employee->fresh()->profile->full_name)->toBe('Nama Diubah');
|
|
});
|
|
|
|
test('guest cannot update an employee', function () {
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->put(route('admin.hr.employees.update', $employee), validEmployeePayload())
|
|
->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('user without update permission is forbidden', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->put(route('admin.hr.employees.update', $employee), validEmployeePayload())
|
|
->assertForbidden();
|
|
});
|
|
|
|
test('email must be unique on update (ignoring self)', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_UPDATE);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$payload = validEmployeePayload();
|
|
$payload['email'] = $employee->email;
|
|
$payload['username'] = $employee->username;
|
|
|
|
$this->actingAs($user)
|
|
->put(route('admin.hr.employees.update', $employee), $payload)
|
|
->assertRedirect(route('admin.hr.employees.index'));
|
|
});
|
|
|
|
test('updating employee can upload new photo and delete existing photo', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_UPDATE);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$imageContent = UploadedFile::fake()->image('initial.jpg')->get();
|
|
Storage::disk('public')->put('initial.jpg', $imageContent);
|
|
$employee->profile->addMediaFromDisk('initial.jpg', 'public')->toMediaCollection('profile_photo');
|
|
expect($employee->profile->fresh()->getMedia('profile_photo')->count())->toBe(1);
|
|
$mediaId = $employee->profile->fresh()->getFirstMedia('profile_photo')->id;
|
|
|
|
$disk = config('filesystems.default') === 's3' ? 's3' : config('filesystems.default', 'public');
|
|
$imageContent2 = UploadedFile::fake()->image('updated.jpg')->get();
|
|
Storage::disk($disk)->put('updated.jpg', $imageContent2);
|
|
$payload = validEmployeePayload();
|
|
$payload['email'] = $employee->email;
|
|
$payload['username'] = $employee->username;
|
|
$payload['profile_s3_key'] = 'updated.jpg';
|
|
$payload['remove_profile_photo_ids'] = [$mediaId];
|
|
|
|
$this->actingAs($user)
|
|
->put(route('admin.hr.employees.update', $employee), $payload);
|
|
|
|
$freshProfile = $employee->fresh()->profile;
|
|
expect($freshProfile->getMedia('profile_photo')->count())->toBe(1);
|
|
expect($freshProfile->getFirstMedia('profile_photo')->id)->not->toBe($mediaId);
|
|
});
|
|
});
|
|
|
|
// ─── Toggle Status ────────────────────────────────────────
|
|
|
|
describe('Employee Toggle Status', function () {
|
|
test('authenticated user with permission can toggle status', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_TOGGLE_STATUS);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
$originalStatus = $employee->is_active;
|
|
|
|
$this->actingAs($user)
|
|
->patch(route('admin.hr.employees.toggle_status', $employee), [
|
|
'is_active' => ! $originalStatus,
|
|
])
|
|
->assertRedirect(route('admin.hr.employees.index'));
|
|
|
|
expect($employee->fresh()->is_active)->toBe(! $originalStatus);
|
|
});
|
|
|
|
test('guest cannot toggle status', function () {
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->patch(route('admin.hr.employees.toggle_status', $employee), [
|
|
'is_active' => false,
|
|
])->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('user without toggle permission is forbidden', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->patch(route('admin.hr.employees.toggle_status', $employee), [
|
|
'is_active' => false,
|
|
])
|
|
->assertForbidden();
|
|
});
|
|
|
|
test('is_active field is required', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_TOGGLE_STATUS);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->patch(route('admin.hr.employees.toggle_status', $employee), [
|
|
'is_active' => null,
|
|
])
|
|
->assertSessionHasErrors('is_active');
|
|
});
|
|
});
|
|
|
|
// ─── Reset Password ───────────────────────────────────────
|
|
|
|
describe('Employee Reset Password', function () {
|
|
test('authenticated user with permission can reset password', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_RESET_PASSWORD);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.reset_password', $employee))
|
|
->assertRedirect(route('admin.hr.employees.index'));
|
|
});
|
|
|
|
test('guest cannot reset password', function () {
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->post(route('admin.hr.employees.reset_password', $employee))
|
|
->assertRedirect(route('login'));
|
|
});
|
|
|
|
test('user without reset password permission is forbidden', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->post(route('admin.hr.employees.reset_password', $employee))
|
|
->assertForbidden();
|
|
});
|
|
});
|
|
|
|
// ─── Destroy ──────────────────────────────────────────────
|
|
|
|
describe('Employee Destroy', function () {
|
|
test('authenticated user with permission can delete an employee', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_DELETE);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->delete(route('admin.hr.employees.destroy', $employee))
|
|
->assertRedirect(route('admin.hr.employees.index'));
|
|
|
|
$this->assertSoftDeleted('users', ['id' => $employee->id]);
|
|
});
|
|
|
|
test('guest cannot delete an employee', function () {
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->delete(route('admin.hr.employees.destroy', $employee))
|
|
->assertRedirect(route('login'));
|
|
|
|
$this->assertNotSoftDeleted('users', ['id' => $employee->id]);
|
|
});
|
|
|
|
test('user without delete permission is forbidden', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
|
|
$this->actingAs($user)
|
|
->delete(route('admin.hr.employees.destroy', $employee))
|
|
->assertForbidden();
|
|
|
|
$this->assertNotSoftDeleted('users', ['id' => $employee->id]);
|
|
});
|
|
|
|
test('deleting employee also soft deletes profile and employee record', function () {
|
|
$user = createEmployeeUserWithPermission(PermissionEnum::EMPLOYEES_VIEW, PermissionEnum::EMPLOYEES_DELETE);
|
|
|
|
$employee = createEmployeeWithProfile();
|
|
$profileId = $employee->profile->id;
|
|
$employeeId = $employee->employee->id;
|
|
|
|
$this->actingAs($user)
|
|
->delete(route('admin.hr.employees.destroy', $employee));
|
|
|
|
$this->assertSoftDeleted('users', ['id' => $employee->id]);
|
|
$this->assertSoftDeleted('user_profiles', ['id' => $profileId]);
|
|
$this->assertSoftDeleted('employees', ['id' => $employeeId]);
|
|
});
|
|
});
|
|
|
|
// ─── Employee Model ───────────────────────────────────────
|
|
|
|
describe('Employee Model Attributes', function () {
|
|
test('join_date_formatted returns translated formatted date or fallback', function () {
|
|
$employee = Employee::factory()->create(['join_date' => '2024-01-15']);
|
|
expect($employee->join_date_formatted)->toBe('Senin, 15 Januari 2024');
|
|
|
|
$employeeNull = Employee::factory()->make(['join_date' => null]);
|
|
expect($employeeNull->join_date_formatted)->toBe('-');
|
|
});
|
|
|
|
test('resign_date_formatted returns translated formatted date or null', function () {
|
|
$employee = Employee::factory()->create(['resign_date' => '2024-06-20']);
|
|
expect($employee->resign_date_formatted)->toBe('Kamis, 20 Juni 2024');
|
|
|
|
$employeeNull = Employee::factory()->make(['resign_date' => null]);
|
|
expect($employeeNull->resign_date_formatted)->toBeNull();
|
|
});
|
|
|
|
test('join_date_input returns date formatted as Y-m-d', function () {
|
|
$employee = Employee::factory()->create(['join_date' => '2024-01-15']);
|
|
expect($employee->join_date_input)->toBe('2024-01-15');
|
|
});
|
|
|
|
test('base_salary_formatted returns formatted rupiah or fallback', function () {
|
|
$employee = Employee::factory()->create(['base_salary' => 5000000]);
|
|
expect($employee->base_salary_formatted)->toBe('Rp 5.000.000');
|
|
|
|
$employeeNull = Employee::factory()->make(['base_salary' => null]);
|
|
expect($employeeNull->base_salary_formatted)->toBe('-');
|
|
});
|
|
});
|