parfum/tests/Feature/Livewire/Studio/Master/User/IndexTest.php
Yoga Pangestu 44b8f2a9d8 refactor(user): memperbaiki dan menyesuaikan user test
- menjadikan address bertipe nullable string
- memasukan key resign_date ke crud
2025-12-07 22:12:50 +07:00

406 lines
12 KiB
PHP

<?php
use App\Enums\UserStatus;
use App\Livewire\Studio\Master\User\Index;
use App\Models\Employee;
use App\Models\Outlet;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Livewire\Livewire;
use Spatie\Permission\Models\Role;
uses(RefreshDatabase::class);
beforeEach(function () {
$roles = collect(['Developer', 'Owner', 'Leader', 'Admin', 'Partner', 'Customer'])
->map(fn ($role) => Role::create(['name' => $role]));
$this->user = User::factory()
->active()
->has(Employee::factory())
->create();
$this->user->roles()->attach($roles->pluck('id'));
});
function createIndexTestUser(array $userAttributes = [], array $employeeAttributes = [])
{
$factory = User::factory();
if (! isset($userAttributes['status'])) {
$factory = $factory->active();
unset($userAttributes['status']);
}
if (! empty($userAttributes)) {
$factory = $factory->state($userAttributes);
}
return $factory
->has(Employee::factory()->state($employeeAttributes))
->create();
}
function mountIndexComponent(User $user)
{
return Livewire::actingAs($user)->test(Index::class);
}
it('renders page successfully', function () {
mountIndexComponent($this->user)
->assertViewIs('livewire.studio.master.user.index')
->assertViewHas('pageTitle', 'Pegawai');
});
it('mounts employees correctly', function () {
$employee = createIndexTestUser();
$employee->assignRole('Admin');
mountIndexComponent($this->user)
->assertViewHas('employees', function ($employees) use ($employee) {
return collect($employees)->contains(
fn ($e) => $e['full_name'] === $employee->employee->full_name &&
$e['code'] === $employee->employee->code
);
});
});
it('loads employee data with all required fields', function () {
$outlet = Outlet::factory()->create();
$user = createIndexTestUser();
$user->assignRole('Admin');
$user->outlets()->attach($outlet->id);
$user->referralCode()->create(['code' => 'REF123']);
$component = mountIndexComponent($this->user);
$employeeData = collect($component->get('employees'))->first(
fn ($e) => $e['full_name'] === $user->employee->full_name
);
expect($employeeData)->toHaveKeys([
'full_name',
'code',
'phone_number',
'address',
'base_salary',
'gender',
'birthdate',
'birth_age',
'hire_date',
'hire_ago',
'resign_date',
'resign_ago',
'user',
'referral_code',
'outlets',
'roles',
]);
expect($employeeData['user'])->toHaveKeys(['id', 'hash', 'email', 'username', 'status']);
expect($employeeData['gender'])->toHaveKeys(['label', 'color']);
expect($employeeData['user']['status'])->toHaveKeys(['gradient']);
});
it('excludes developer users from listing', function () {
$developer = createIndexTestUser();
$developer->assignRole('Developer');
$admin = createIndexTestUser();
$admin->assignRole('Admin');
$component = mountIndexComponent($this->user);
$employeeNames = collect($component->get('employees'))->pluck('full_name')->toArray();
expect($employeeNames)->not->toContain($developer->employee->full_name);
expect($employeeNames)->toContain($admin->employee->full_name);
});
it('displays all employees', function () {
$employees = [];
for ($i = 0; $i < 5; $i++) {
$user = createIndexTestUser();
$user->assignRole('Admin');
$employees[] = $user;
}
$component = mountIndexComponent($this->user);
$employeeCount = count($component->get('employees'));
expect($employeeCount)->toBeGreaterThanOrEqual(5);
});
it('filters employees by search query - full name', function () {
$user1 = createIndexTestUser([], ['full_name' => 'John Doe']);
$user1->assignRole('Admin');
$user2 = createIndexTestUser([], ['full_name' => 'Jane Smith']);
$user2->assignRole('Admin');
$component = mountIndexComponent($this->user);
expect(count($component->get('employees')))->toBeGreaterThanOrEqual(2);
$component->set('search', 'John')
->assertSet('search', 'John');
$employees = $component->get('employees');
expect(count($employees))->toBeGreaterThanOrEqual(1);
expect($employees[0]['full_name'])->toBe('John Doe');
});
it('filters employees by search query - employee code', function () {
$user1 = createIndexTestUser([], ['code' => 'EMP20240001']);
$user1->assignRole('Admin');
$component = mountIndexComponent($this->user);
$component->set('search', 'EMP20240001');
$employees = $component->get('employees');
expect(collect($employees)->pluck('code'))->toContain('EMP20240001');
});
it('filters employees by search query - email', function () {
$user1 = createIndexTestUser(['email' => 'john@example.com']);
$user1->assignRole('Admin');
$component = mountIndexComponent($this->user);
$component->set('search', 'john@example.com');
$employees = $component->get('employees');
expect(collect($employees)->pluck('user.email'))->toContain('john@example.com');
});
it('filters employees by search query - username', function () {
$user1 = createIndexTestUser(['username' => 'johndoe']);
$user1->assignRole('Admin');
$component = mountIndexComponent($this->user);
$component->set('search', 'johndoe');
$employees = $component->get('employees');
expect(collect($employees)->pluck('user.username'))->toContain('johndoe');
});
it('filters employees by status - active', function () {
$activeUser = createIndexTestUser(['status' => UserStatus::ACTIVE]);
$activeUser->assignRole('Admin');
$inactiveUser = createIndexTestUser(['status' => UserStatus::INACTIVE]);
$inactiveUser->assignRole('Admin');
$component = mountIndexComponent($this->user);
expect(count($component->get('employees')))->toBeGreaterThanOrEqual(2);
$component->set('status', [UserStatus::ACTIVE->value]);
$employees = $component->get('employees');
$activeEmployees = collect($employees)->filter(
fn ($e) => $e['user']['status']['gradient'] === (UserStatus::ACTIVE->gradient())
);
expect(count($activeEmployees))->toBeGreaterThanOrEqual(1);
});
it('filters employees by status - inactive', function () {
$activeUser = createIndexTestUser(['status' => UserStatus::ACTIVE]);
$activeUser->assignRole('Admin');
$inactiveUser = createIndexTestUser(['status' => UserStatus::INACTIVE]);
$inactiveUser->assignRole('Admin');
$component = mountIndexComponent($this->user);
$component->set('status', [UserStatus::INACTIVE->value]);
$employees = $component->get('employees');
$inactiveEmployees = collect($employees)->filter(
fn ($e) => $e['user']['status']['gradient'] === (UserStatus::INACTIVE->gradient())
);
expect(count($inactiveEmployees))->toBeGreaterThanOrEqual(1);
});
it('filters employees by multiple statuses', function () {
$activeUser = createIndexTestUser(['status' => UserStatus::ACTIVE]);
$activeUser->assignRole('Admin');
$inactiveUser = createIndexTestUser(['status' => UserStatus::INACTIVE]);
$inactiveUser->assignRole('Admin');
$component = mountIndexComponent($this->user);
$component->set('status', [
UserStatus::ACTIVE->value,
UserStatus::INACTIVE->value,
]);
expect(count($component->get('employees')))->toBeGreaterThanOrEqual(2);
});
it('filters employees by both search and status', function () {
$activeUser = createIndexTestUser(
['status' => UserStatus::ACTIVE],
['full_name' => 'Active User']
);
$activeUser->assignRole('Admin');
$inactiveUser = createIndexTestUser(
['status' => UserStatus::INACTIVE],
['full_name' => 'Inactive User']
);
$inactiveUser->assignRole('Admin');
$component = mountIndexComponent($this->user)
->set('search', 'Active')
->set('status', [UserStatus::ACTIVE->value]);
$employees = $component->get('employees');
expect(count($employees))->toBeGreaterThanOrEqual(1);
expect($employees[0]['full_name'])->toBe('Active User');
});
it('loads employees ordered by latest', function () {
$user1 = createIndexTestUser([], ['full_name' => 'First Employee']);
$user1->assignRole('Admin');
sleep(1);
$user2 = createIndexTestUser([], ['full_name' => 'Second Employee']);
$user2->assignRole('Admin');
$component = mountIndexComponent($this->user);
$employees = $component->get('employees');
$firstEmployee = collect($employees)->first(fn ($e) => $e['full_name'] === 'Second Employee');
$secondEmployee = collect($employees)->first(fn ($e) => $e['full_name'] === 'First Employee');
expect($firstEmployee)->not->toBeNull();
expect($secondEmployee)->not->toBeNull();
// The second employee should appear before the first
$firstIndex = array_search('Second Employee', array_column($employees, 'full_name'));
$secondIndex = array_search('First Employee', array_column($employees, 'full_name'));
expect($firstIndex)->toBeLessThan($secondIndex);
});
it('loads employee with outlets', function () {
$outlet1 = Outlet::factory()->create(['name' => 'Outlet A']);
$outlet2 = Outlet::factory()->create(['name' => 'Outlet B']);
$user = createIndexTestUser();
$user->assignRole('Admin');
$user->outlets()->attach([$outlet1->id, $outlet2->id]);
$component = mountIndexComponent($this->user);
$employeeData = collect($component->get('employees'))->first(
fn ($e) => $e['full_name'] === $user->employee->full_name
);
expect($employeeData['outlets'])->toContain('Outlet A', 'Outlet B');
});
it('loads employee with roles', function () {
$user = createIndexTestUser();
$user->assignRole(['Admin', 'Leader']);
$component = mountIndexComponent($this->user);
$employeeData = collect($component->get('employees'))->first(
fn ($e) => $e['full_name'] === $user->employee->full_name
);
expect($employeeData['roles'])->toContain('Admin', 'Leader');
});
it('loads employee with referral code', function () {
$user = createIndexTestUser();
$user->assignRole('Admin');
$user->referralCode()->create(['code' => 'REF12345']);
$component = mountIndexComponent($this->user);
$employeeData = collect($component->get('employees'))->first(
fn ($e) => $e['full_name'] === $user->employee->full_name
);
expect($employeeData['referral_code'])->toBe('REF12345');
});
it('deletes an employee successfully', function () {
$employeeUser = createIndexTestUser();
$employeeUser->assignRole('Admin');
mountIndexComponent($this->user)
->call('delete', $employeeUser)
->assertHasNoErrors();
$this->assertSoftDeleted('users', ['id' => $employeeUser->id]);
$this->assertSoftDeleted('employees', ['user_id' => $employeeUser->id]);
});
it('reloads employees after deletion', function () {
$employeeUser = createIndexTestUser();
$employeeUser->assignRole('Admin');
$component = mountIndexComponent($this->user);
$initialCount = count($component->get('employees'));
$component->call('delete', $employeeUser);
expect(count($component->get('employees')))->toBeLessThan($initialCount);
});
it('resets password successfully', function () {
$defaultPassword = config('myconfig.password_default');
$employeeUser = createIndexTestUser();
$employeeUser->assignRole('Admin');
$employeeUser->update(['password' => Hash::make('oldpassword')]);
$oldPasswordHash = $employeeUser->password;
mountIndexComponent($this->user)
->call('resetPassword', $employeeUser)
->assertHasNoErrors();
$employeeUser->refresh();
expect($employeeUser->password)->not->toBe($oldPasswordHash);
expect(Hash::check($defaultPassword, $employeeUser->password))->toBeTrue();
});
it('does not display delete and edit buttons for current authenticated user', function () {
$component = mountIndexComponent($this->user);
$component
->assertDontSee('Delete')
->assertDontSee('Edit');
});
it('updates search with debounce', function () {
$user1 = createIndexTestUser([], ['full_name' => 'John Doe']);
$user1->assignRole('Admin');
$component = mountIndexComponent($this->user);
$component->set('search', 'John');
expect($component->get('search'))->toBe('John');
});
it('updates status filter correctly', function () {
$component = mountIndexComponent($this->user);
$component->set('status', ['active']);
expect($component->get('status'))->toBeArray();
});