test: Add feature tests for user creation, editing, and index page, and refactor user index Livewire component data fetching.
This commit is contained in:
parent
39c0652e3e
commit
8358e20575
@ -21,52 +21,16 @@ class Index extends Component
|
||||
{
|
||||
use WithAuthorization, WithConfirmation, WithRequestNotification, WithSubscribeNotification, WithToast;
|
||||
|
||||
public Collection $employees;
|
||||
|
||||
public string $search = '';
|
||||
|
||||
public array $status = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->loadEmployees();
|
||||
}
|
||||
|
||||
protected function loadEmployees(): void
|
||||
{
|
||||
$this->employees = Employee::with(['user', 'user.referralCode', 'user.outlets'])
|
||||
->when(! empty($this->search), function ($query) {
|
||||
return $query->where('full_name', 'like', '%'.$this->search.'%')
|
||||
->orWhere('code', 'like', '%'.$this->search.'%')
|
||||
->orWhereHas('user', fn ($q) => $q->where('email', 'like', '%'.$this->search.'%'))
|
||||
->orWhereHas('user', fn ($q) => $q->where('username', 'like', '%'.$this->search.'%'));
|
||||
})
|
||||
->when(! empty($this->status), fn ($query) => $query->whereHas('user', fn ($q) => $q->whereIn('status', $this->status)))
|
||||
->withoutDeveloper()
|
||||
->latest()
|
||||
->get();
|
||||
}
|
||||
|
||||
public function updatedSearch(string $value): void
|
||||
{
|
||||
$this->search = $value;
|
||||
|
||||
$this->loadEmployees();
|
||||
}
|
||||
|
||||
public function updatedStatus(): void
|
||||
{
|
||||
$this->loadEmployees();
|
||||
}
|
||||
|
||||
public function delete(User $user): void
|
||||
{
|
||||
$this->canOrAbort('delete user');
|
||||
|
||||
$user->delete();
|
||||
|
||||
$this->loadEmployees();
|
||||
|
||||
$this->toast('Pegawai berhasil dihapus.');
|
||||
|
||||
Flux::modals()->close();
|
||||
@ -85,8 +49,21 @@ public function resetPassword(User $user): void
|
||||
|
||||
public function render(): View
|
||||
{
|
||||
$employees = Employee::with(['user', 'user.referralCode', 'user.outlets'])
|
||||
->when(! empty($this->search), function ($query) {
|
||||
return $query->where('full_name', 'like', '%' . $this->search . '%')
|
||||
->orWhere('code', 'like', '%' . $this->search . '%')
|
||||
->orWhereHas('user', fn($q) => $q->where('email', 'like', '%' . $this->search . '%'))
|
||||
->orWhereHas('user', fn($q) => $q->where('username', 'like', '%' . $this->search . '%'));
|
||||
})
|
||||
->when(! empty($this->status), fn($query) => $query->whereHas('user', fn($q) => $q->whereIn('status', $this->status)))
|
||||
->withoutDeveloper()
|
||||
->latest()
|
||||
->get();
|
||||
|
||||
return view('livewire.studio.master.user.index', [
|
||||
'pageTitle' => 'Pegawai',
|
||||
'employees' => $employees,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
109
tests/Feature/Studio/Master/User/CreateTest.php
Normal file
109
tests/Feature/Studio/Master/User/CreateTest.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\Gender;
|
||||
use App\Enums\UserStatus;
|
||||
use App\Livewire\Studio\Master\User\Create;
|
||||
use App\Models\Outlet;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use Livewire\Livewire;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
beforeEach(function () {
|
||||
$this->setupUser();
|
||||
|
||||
$role = Role::firstOrCreate(['name' => 'Owner']);
|
||||
Permission::firstOrCreate(['name' => 'create user']);
|
||||
$role->givePermissionTo('create user');
|
||||
$this->user->assignRole($role);
|
||||
});
|
||||
|
||||
it('renders the create user page correctly', function () {
|
||||
$this->actingAs($this->user)
|
||||
->get(route('studio.master.user.create'))
|
||||
->assertOk()
|
||||
->assertSeeLivewire(Create::class);
|
||||
});
|
||||
|
||||
it('validates required fields', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->call('save')
|
||||
->assertHasErrors([
|
||||
'form.full_name' => 'required',
|
||||
'form.username' => 'required',
|
||||
'form.email' => 'required',
|
||||
'form.phone_number' => 'required',
|
||||
'form.base_salary' => 'required',
|
||||
'form.birthdate' => 'required',
|
||||
'form.hire_date' => 'required',
|
||||
'form.gender' => 'required',
|
||||
'form.outlet_ids' => 'required',
|
||||
'form.role_ids' => 'required',
|
||||
]);
|
||||
});
|
||||
|
||||
it('validates username minimum length', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.username', 'abc')
|
||||
->call('save')
|
||||
->assertHasErrors(['form.username' => 'min']);
|
||||
});
|
||||
|
||||
it('validates birthdate must be at least 18 years ago', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.birthdate', Carbon::now()->subYears(17)->format('Y-m-d'))
|
||||
->call('save')
|
||||
->assertHasErrors(['form.birthdate' => 'before']);
|
||||
});
|
||||
|
||||
it('can store a new user/employee', function () {
|
||||
$outlet = Outlet::factory()->create();
|
||||
$role = Role::firstOrCreate(['name' => 'Admin']);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.full_name', 'Pegawai Baru')
|
||||
->set('form.username', 'pegawaibaru')
|
||||
->set('form.email', 'pegawai@example.com')
|
||||
->set('form.phone_number', '0812 3456 7890')
|
||||
->set('form.base_salary', '5.000.000')
|
||||
->set('form.birthdate', '2000-01-01')
|
||||
->set('form.hire_date', '2024-01-01')
|
||||
->set('form.gender', Gender::MALE->value)
|
||||
->set('form.status', UserStatus::ACTIVE->value)
|
||||
->set('form.outlet_ids', [$outlet->id])
|
||||
->set('form.role_ids', [$role->id])
|
||||
->call('save')
|
||||
->assertHasNoErrors()
|
||||
->assertRedirect(route('studio.master.user.index', ['notification' => 'Pegawai berhasil ditambahkan.']));
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'username' => 'pegawaibaru',
|
||||
'email' => 'pegawai@example.com',
|
||||
]);
|
||||
|
||||
$user = User::where('username', 'pegawaibaru')->first();
|
||||
$this->assertDatabaseHas('employees', [
|
||||
'user_id' => $user->id,
|
||||
'full_name' => 'Pegawai Baru',
|
||||
'base_salary' => 5000000,
|
||||
]);
|
||||
|
||||
expect($user->outlets)->toHaveCount(1);
|
||||
expect($user->hasRole('Admin'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('cannot create user without permission', function () {
|
||||
$this->user->roles()->detach();
|
||||
$this->user->permissions()->detach();
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Create::class)
|
||||
->set('form.full_name', 'Unauthorized User')
|
||||
->call('save')
|
||||
->assertForbidden();
|
||||
});
|
||||
64
tests/Feature/Studio/Master/User/EditTest.php
Normal file
64
tests/Feature/Studio/Master/User/EditTest.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\UserStatus;
|
||||
use App\Livewire\Studio\Master\User\Edit;
|
||||
use App\Models\Employee;
|
||||
use App\Models\User;
|
||||
use Livewire\Livewire;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
beforeEach(function () {
|
||||
$this->setupUser();
|
||||
|
||||
$role = Role::firstOrCreate(['name' => 'Owner']);
|
||||
Permission::firstOrCreate(['name' => 'update user']);
|
||||
$role->givePermissionTo('update user');
|
||||
$this->user->assignRole($role);
|
||||
|
||||
$this->targetUser = User::factory()->create();
|
||||
$this->targetEmployee = Employee::factory()->for($this->targetUser)->create();
|
||||
$this->targetUser->outlets()->attach($this->outlet);
|
||||
$this->targetUser->assignRole(Role::firstOrCreate(['name' => 'Admin']));
|
||||
});
|
||||
|
||||
it('renders the edit user page correctly', function () {
|
||||
$this->actingAs($this->user)
|
||||
->get(route('studio.master.user.edit', $this->targetUser))
|
||||
->assertOk()
|
||||
->assertSeeLivewire(Edit::class);
|
||||
});
|
||||
|
||||
it('loads existing user data correctly', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Edit::class, ['user' => $this->targetUser])
|
||||
->assertSet('form.full_name', $this->targetEmployee->full_name)
|
||||
->assertSet('form.username', $this->targetUser->username);
|
||||
});
|
||||
|
||||
it('can update a user', function () {
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Edit::class, ['user' => $this->targetUser])
|
||||
->set('form.full_name', 'Pegawai Diperbarui')
|
||||
->set('form.status', UserStatus::INACTIVE->value)
|
||||
->call('save')
|
||||
->assertHasNoErrors()
|
||||
->assertRedirect(route('studio.master.user.index', ['notification' => 'Pegawai berhasil diperbarui.']));
|
||||
|
||||
$this->targetUser->refresh();
|
||||
$this->targetEmployee->refresh();
|
||||
|
||||
expect($this->targetEmployee->full_name)->toBe('Pegawai Diperbarui');
|
||||
expect($this->targetUser->status)->toBe(UserStatus::INACTIVE);
|
||||
});
|
||||
|
||||
it('cannot update user without permission', function () {
|
||||
$this->user->roles()->detach();
|
||||
$this->user->permissions()->detach();
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Edit::class, ['user' => $this->targetUser])
|
||||
->set('form.full_name', 'Unauthorized Edit')
|
||||
->call('save')
|
||||
->assertForbidden();
|
||||
});
|
||||
98
tests/Feature/Studio/Master/User/IndexTest.php
Normal file
98
tests/Feature/Studio/Master/User/IndexTest.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
use App\Livewire\Studio\Master\User\Index;
|
||||
use App\Models\Employee;
|
||||
use App\Models\User;
|
||||
use Livewire\Livewire;
|
||||
use Spatie\Permission\Models\Permission;
|
||||
use Spatie\Permission\Models\Role;
|
||||
|
||||
beforeEach(function () {
|
||||
$this->setupUser();
|
||||
|
||||
$role = Role::firstOrCreate(['name' => 'Owner']);
|
||||
Permission::firstOrCreate(['name' => 'view user']);
|
||||
Permission::firstOrCreate(['name' => 'delete user']);
|
||||
Permission::firstOrCreate(['name' => 'reset password user']);
|
||||
$role->givePermissionTo(['view user', 'delete user', 'reset password user']);
|
||||
$this->user->assignRole($role);
|
||||
});
|
||||
|
||||
it('renders the user index page correctly', function () {
|
||||
$this->actingAs($this->user)
|
||||
->get(route('studio.master.user.index'))
|
||||
->assertOk()
|
||||
->assertSeeLivewire(Index::class);
|
||||
});
|
||||
|
||||
it('displays list of employees correctly', function () {
|
||||
$employees = collect();
|
||||
foreach (range(1, 3) as $i) {
|
||||
$employees->push(Employee::factory()->create());
|
||||
}
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Index::class)
|
||||
->assertViewHas('employees', function ($viewEmployees) use ($employees) {
|
||||
return $viewEmployees->count() >= 3;
|
||||
})
|
||||
->assertSee($employees->first()->full_name)
|
||||
->assertSee($employees->last()->full_name);
|
||||
});
|
||||
|
||||
it('can search employees by name', function () {
|
||||
$targetEmployee = Employee::factory()->create(['full_name' => 'Pegawai Spesifik']);
|
||||
$otherEmployee = Employee::factory()->create(['full_name' => 'Biasa Saja']);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Index::class)
|
||||
->set('search', 'Spesifik')
|
||||
->assertSee($targetEmployee->full_name)
|
||||
->assertDontSee($otherEmployee->full_name);
|
||||
});
|
||||
|
||||
it('can filter employees by status', function () {
|
||||
$activeUser = User::factory()->active()->create();
|
||||
$activeEmployee = Employee::factory()->for($activeUser)->create(['full_name' => 'Pegawai Aktif']);
|
||||
|
||||
$inactiveUser = User::factory()->inactive()->create();
|
||||
$inactiveEmployee = Employee::factory()->for($inactiveUser)->create(['full_name' => 'Pegawai Nonaktif']);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Index::class)
|
||||
->set('status', [\App\Enums\UserStatus::ACTIVE->value])
|
||||
->assertSee($activeEmployee->full_name)
|
||||
->assertDontSee($inactiveEmployee->full_name);
|
||||
});
|
||||
|
||||
it('can delete a user', function () {
|
||||
$userToDelete = User::factory()->create();
|
||||
Employee::factory()->for($userToDelete)->create();
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Index::class)
|
||||
->call('delete', $userToDelete->id);
|
||||
|
||||
$this->assertSoftDeleted('users', ['id' => $userToDelete->id]);
|
||||
$this->assertSoftDeleted('employees', ['user_id' => $userToDelete->id]);
|
||||
});
|
||||
|
||||
it('can reset user password', function () {
|
||||
$userToReset = User::factory()->create(['password' => Hash::make('old-password')]);
|
||||
|
||||
Livewire::actingAs($this->user)
|
||||
->test(Index::class)
|
||||
->call('resetPassword', $userToReset->id);
|
||||
|
||||
$userToReset->refresh();
|
||||
expect(Hash::check(config('myconfig.password_default'), $userToReset->password))->toBeTrue();
|
||||
});
|
||||
|
||||
it('cannot access index page without permission', function () {
|
||||
$this->user->roles()->detach();
|
||||
$this->user->permissions()->detach();
|
||||
|
||||
$this->actingAs($this->user)
|
||||
->get(route('studio.master.user.index'))
|
||||
->assertForbidden();
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user