admin = User::factory()->admin()->create(); } // ------------------------------------------------------- // Access Control // ------------------------------------------------------- public function test_regular_user_cannot_access_admin_user_list(): void { $user = User::factory()->create(); $this->actingAs($user)->get(route('admin.users.index'))->assertForbidden(); } public function test_admin_can_view_user_list(): void { $this->actingAs($this->admin) ->get(route('admin.users.index')) ->assertOk() ->assertViewIs('admin.users.index'); } // ------------------------------------------------------- // Create User // ------------------------------------------------------- public function test_admin_can_create_user(): void { $this->actingAs($this->admin) ->post(route('admin.users.store'), [ 'name' => 'Pengguna Baru', 'email' => 'baru@mbip.my', 'password' => 'Password@123', 'password_confirmation' => 'Password@123', 'role' => 'user', 'department_id' => null, ])->assertRedirect(route('admin.users.index')); $this->assertDatabaseHas('users', ['email' => 'baru@mbip.my', 'role' => 'user']); $this->assertDatabaseHas('audit_logs', ['action' => 'user_created']); } // ------------------------------------------------------- // Deactivate / Activate // ------------------------------------------------------- public function test_admin_can_deactivate_user(): void { $user = User::factory()->create(); $this->actingAs($this->admin) ->patch(route('admin.users.deactivate', $user)) ->assertRedirect(route('admin.users.index')); $this->assertFalse($user->fresh()->is_active); $this->assertDatabaseHas('audit_logs', ['action' => 'user_deactivated', 'target_user_id' => $user->id]); } public function test_admin_can_activate_user(): void { $user = User::factory()->inactive()->create(); $this->actingAs($this->admin) ->patch(route('admin.users.activate', $user)) ->assertRedirect(route('admin.users.index')); $this->assertTrue($user->fresh()->is_active); $this->assertDatabaseHas('audit_logs', ['action' => 'user_reactivated']); } public function test_deactivated_user_cannot_login(): void { $user = User::factory()->inactive()->create(); $this->post(route('login'), [ 'email' => $user->email, 'password' => 'password', ])->assertSessionHasErrors('email'); $this->assertGuest(); } // ------------------------------------------------------- // Email Change // ------------------------------------------------------- public function test_admin_can_change_user_email(): void { $user = User::factory()->create(['email' => 'lama@mbip.my']); $this->actingAs($this->admin) ->patch(route('admin.users.update-email', $user), [ 'email' => 'baru@mbip.my', 'justification' => 'Pertukaran emel rasmi', ])->assertRedirect(route('admin.users.index')); $this->assertEquals('baru@mbip.my', $user->fresh()->email); $this->assertDatabaseHas('audit_logs', [ 'action' => 'user_email_changed', 'target_user_id' => $user->id, ]); } // ------------------------------------------------------- // Delete // ------------------------------------------------------- public function test_admin_can_delete_user_without_usage(): void { $user = User::factory()->create(); $this->actingAs($this->admin) ->delete(route('admin.users.destroy', $user)) ->assertRedirect(route('admin.users.index')); $this->assertNull(User::find($user->id)); $this->assertDatabaseHas('audit_logs', ['action' => 'user_deleted']); } public function test_admin_cannot_delete_user_with_usage(): void { $user = User::factory()->create(); // Cipta audit log untuk simulasi usage AuditLog::create([ 'actor_user_id' => $user->id, 'actor_role' => 'user', 'action' => 'project_created', 'created_at' => now(), ]); $this->actingAs($this->admin) ->delete(route('admin.users.destroy', $user)) ->assertForbidden(); $this->assertNotNull(User::find($user->id)); } // ------------------------------------------------------- // Admin cannot access own account // ------------------------------------------------------- public function test_admin_cannot_deactivate_self(): void { $this->actingAs($this->admin) ->patch(route('admin.users.deactivate', $this->admin)) ->assertForbidden(); } }