225 lines
7.6 KiB
PHP
225 lines
7.6 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 Livewire\Features\SupportTesting\Testable;
|
|
use Livewire\Livewire;
|
|
|
|
uses(RefreshDatabase::class);
|
|
|
|
beforeEach(function () {
|
|
// Create roles for testing
|
|
collect(['Developer', 'Owner', 'Leader', 'Admin', 'Partner', 'Customer'])
|
|
->each(fn ($role) => \Spatie\Permission\Models\Role::create(['name' => $role]));
|
|
|
|
$this->user = User::factory()
|
|
->active()
|
|
->has(Employee::factory())
|
|
->create();
|
|
|
|
$this->user->assignRole('Admin'); // Give admin role to test user
|
|
});
|
|
|
|
function createUser(array $attributes = []): User
|
|
{
|
|
return User::factory()
|
|
->active()
|
|
->has(Employee::factory())
|
|
->state(fn () => array_merge([
|
|
'status' => fake()->randomElement(UserStatus::cases()),
|
|
], $attributes))
|
|
->create();
|
|
}
|
|
|
|
function mountIndexComponent(User $user): Testable
|
|
{
|
|
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('loads employees as Eloquent collection', function () {
|
|
$user = createUser();
|
|
|
|
$component = mountIndexComponent($this->user);
|
|
|
|
expect(
|
|
$component->get('employees')->pluck('id')
|
|
)->toContain($user->id);
|
|
});
|
|
|
|
it('loads employees with relationships', function () {
|
|
$user = createUser();
|
|
$user->assignRole('Admin'); // Assign role so user appears in list
|
|
$outlet = Outlet::factory()->create();
|
|
$user->outlets()->attach($outlet->id);
|
|
|
|
$component = mountIndexComponent($this->user);
|
|
$loadedEmployee = $component->get('employees')->first(fn ($emp) => $emp->user_id === $user->id);
|
|
|
|
expect($loadedEmployee)->not->toBeNull()
|
|
->and($loadedEmployee->relationLoaded('user'))->toBeTrue()
|
|
->and($loadedEmployee->user->relationLoaded('outlets'))->toBeTrue()
|
|
->and($loadedEmployee->user->outlets)->toHaveCount(1);
|
|
});
|
|
|
|
it('excludes developer users from listing', function () {
|
|
$developer = createUser();
|
|
$developer->assignRole('Developer');
|
|
|
|
$admin = createUser();
|
|
$admin->assignRole('Admin');
|
|
|
|
$component = mountIndexComponent($this->user);
|
|
$employeeNames = $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 () {
|
|
$initialCount = Employee::count();
|
|
|
|
for ($i = 0; $i < 5; $i++) {
|
|
createUser();
|
|
}
|
|
|
|
$component = mountIndexComponent($this->user);
|
|
|
|
expect($component->get('employees'))->toHaveCount($initialCount + 5);
|
|
expect($component->get('employees')->first())->toBeInstanceOf(Employee::class);
|
|
});
|
|
|
|
it('filters employees by search query', function () {
|
|
$user1 = createUser(['username' => 'john_doe']);
|
|
$user2 = createUser(['username' => 'jane_smith']);
|
|
|
|
$component = mountIndexComponent($this->user);
|
|
|
|
expect(count($component->get('employees')))->toBeGreaterThan(2); // 2 new users + logged in user
|
|
|
|
// Test filtering by username
|
|
$filteredComponent = mountIndexComponent($this->user)->set('search', 'john_doe');
|
|
|
|
expect($filteredComponent->get('employees'))->toHaveCount(1);
|
|
expect($filteredComponent->get('employees')->first()->user->username)->toBe('john_doe');
|
|
});
|
|
|
|
it('filters employees by status', function () {
|
|
$activeUser = createUser(['status' => UserStatus::ACTIVE]);
|
|
$inactiveUser = createUser(['status' => UserStatus::INACTIVE]);
|
|
|
|
$component = mountIndexComponent($this->user);
|
|
|
|
expect(count($component->get('employees')))->toBeGreaterThan(2); // 2 new users + logged in user
|
|
|
|
$filteredComponent = mountIndexComponent($this->user)->set('status', [UserStatus::ACTIVE->value]);
|
|
|
|
expect(count($filteredComponent->get('employees')))->toBeGreaterThanOrEqual(1); // At least the active user
|
|
expect($filteredComponent->get('employees')->contains(fn ($emp) => $emp->user->status->value === UserStatus::ACTIVE->value))->toBeTrue();
|
|
});
|
|
|
|
it('filters employees by multiple statuses', function () {
|
|
$activeUser = createUser(['status' => UserStatus::ACTIVE]);
|
|
$inactiveUser = createUser(['status' => UserStatus::INACTIVE]);
|
|
|
|
$component = mountIndexComponent($this->user);
|
|
|
|
expect(count($component->get('employees')))->toBeGreaterThan(2); // 2 new users + logged in user
|
|
|
|
$filteredComponent = mountIndexComponent($this->user)->set('status', [
|
|
UserStatus::ACTIVE->value,
|
|
UserStatus::INACTIVE->value,
|
|
]);
|
|
|
|
expect(count($filteredComponent->get('employees')))->toBeGreaterThan(2); // All users with these statuses
|
|
});
|
|
|
|
it('loads employees ordered by latest', function () {
|
|
$user1 = createUser();
|
|
sleep(1);
|
|
$user2 = createUser();
|
|
|
|
$component = mountIndexComponent($this->user);
|
|
|
|
expect($component->get('employees')->first()->id)->toBe($user2->id);
|
|
expect($component->get('employees')->last()->id)->toBe($user1->id);
|
|
});
|
|
|
|
it('loads employees with all required relationships', function () {
|
|
$user = createUser();
|
|
$user->assignRole('Admin'); // Ensure user appears in list
|
|
$outlet = Outlet::factory()->create();
|
|
$user->outlets()->attach($outlet->id);
|
|
|
|
$component = mountIndexComponent($this->user);
|
|
$loadedEmployee = $component->get('employees')->first(fn ($emp) => $emp->user_id === $user->id);
|
|
|
|
expect($loadedEmployee)->not->toBeNull()
|
|
->and($loadedEmployee->user->outlets)->toHaveCount(1)
|
|
->and($loadedEmployee->user->roles)->toHaveCount(1) // Admin role assigned
|
|
->and($loadedEmployee->full_name)->toBe($user->employee->full_name);
|
|
});
|
|
|
|
it('deletes an employee successfully', function () {
|
|
$user = createUser();
|
|
|
|
mountIndexComponent($this->user)
|
|
->call('delete', $user)
|
|
->assertHasNoErrors();
|
|
|
|
$this->assertSoftDeleted('users', ['id' => $user->id]);
|
|
$this->assertSoftDeleted('employees', ['user_id' => $user->id]);
|
|
});
|
|
|
|
it('handles empty search results gracefully', function () {
|
|
createUser(['username' => 'existing_user']);
|
|
|
|
$component = mountIndexComponent($this->user)->set('search', 'NonExistentUser');
|
|
|
|
expect($component->get('employees'))->toHaveCount(0);
|
|
});
|
|
|
|
it('maintains search state across component lifecycle', function () {
|
|
$user1 = createUser(['username' => 'test_user']);
|
|
$user2 = createUser(['username' => 'another_user']);
|
|
|
|
$component = mountIndexComponent($this->user)->set('search', 'test');
|
|
|
|
expect($component->get('employees'))->toHaveCount(1);
|
|
expect($component->get('search'))->toBe('test');
|
|
});
|
|
|
|
it('handles status filter with empty array', function () {
|
|
createUser(['status' => UserStatus::ACTIVE]);
|
|
createUser(['status' => UserStatus::INACTIVE]);
|
|
|
|
$component = mountIndexComponent($this->user)->set('status', []);
|
|
|
|
expect(count($component->get('employees')))->toBeGreaterThan(2); // 2 new users + logged in user
|
|
});
|
|
|
|
it('loads employees efficiently with eager loading', function () {
|
|
$users = collect();
|
|
for ($i = 0; $i < 10; $i++) {
|
|
$users->push(createUser());
|
|
}
|
|
|
|
$component = mountIndexComponent($this->user);
|
|
|
|
// Verify relationships are loaded
|
|
$loadedEmployees = $component->get('employees');
|
|
foreach ($loadedEmployees as $loadedEmployee) {
|
|
expect($loadedEmployee->relationLoaded('user'))->toBeTrue();
|
|
expect($loadedEmployee->user->relationLoaded('outlets'))->toBeTrue();
|
|
}
|
|
});
|