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(); });