- Memperbarui UsersController: - Mengaktifkan middleware untuk menginisialisasi pengguna yang terautentikasi. - Mengubah nama izin dari pola 'users.*' menjadi 'usermanagement.*' untuk konsistensi. - Menggunakan Storage Facade untuk operasi penyimpanan file tanda tangan. - Menambahkan validasi untuk direktori sebelum menyimpan file baru. - Mengubah metode untuk memberikan respons JSON pada penghapusan pengguna. - Memperbarui views/users/index.blade.php: - Menghapus dropdown filter yang tidak digunakan. - Menambahkan tombol Export to Excel dan Add User dengan styling yang diperbarui. - Menambahkan file `UsersControllerTest` untuk memastikan kelengkapan pengujian: - Pengujian CRUD (Create, Read, Update, Delete) pengguna. - Pengujian pagination, sorting, dan filtering untuk datatable. - Pengujian pengelolaan file tanda tangan pengguna (penyimpanan baru dan penghapusan tanda tangan lama). - Pengujian pemulihan untuk soft-deleted users. - Pengujian validasi peran dan izin untuk setiap tindakan. - Memastikan konsistensi dan reliabilitas proses pengelolaan pengguna melalui pengujian otomatis.
467 lines
17 KiB
PHP
467 lines
17 KiB
PHP
<?php
|
|
|
|
namespace Modules\Usermanagement\Tests\Feature;
|
|
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Tests\TestCase;
|
|
use Modules\Usermanagement\Models\User;
|
|
use Modules\Usermanagement\Models\Role;
|
|
use Modules\Usermanagement\Models\Permission;
|
|
use Modules\Usermanagement\Models\PermissionGroup;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\UploadedFile;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
|
|
class UsersControllerTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected $user;
|
|
protected $adminRole;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// Create permission group
|
|
$permissionGroup = PermissionGroup::create([
|
|
'name' => 'usermanagement',
|
|
'slug' => 'usermanagement'
|
|
]);
|
|
|
|
// Create usermanagement.read permission
|
|
Permission::create([
|
|
'name' => 'usermanagement.read',
|
|
'guard_name' => 'web',
|
|
'permission_group_id' => $permissionGroup->id
|
|
]);
|
|
|
|
// Create role with usermanagement.read permission
|
|
$this->adminRole = Role::create(['name' => 'admin', 'guard_name' => 'web']);
|
|
$this->adminRole->givePermissionTo('usermanagement.read');
|
|
|
|
// Create a user with admin role
|
|
// Create a user for testing
|
|
$this->user = User::factory()->create([
|
|
'name' => 'Original Name',
|
|
'email' => 'original@example.com',
|
|
'nik' => '123456',
|
|
'sign' => 'old-signature.jpg'
|
|
]);
|
|
|
|
// Mock the storage
|
|
Storage::fake('public');
|
|
$this->user->assignRole($this->adminRole);
|
|
|
|
// Create test role for assignment to new user
|
|
Role::create(['name' => 'operator', 'guard_name' => 'web']);
|
|
|
|
}
|
|
|
|
#[Test]
|
|
public function should_display_users_index_page_when_user_has_users_view_permission()
|
|
{
|
|
$response = $this->actingAs($this->user)
|
|
->get(route('users.index'));
|
|
|
|
$response->assertStatus(200);
|
|
$response->assertViewIs('usermanagement::users.index');
|
|
}
|
|
|
|
#[Test]
|
|
public function should_return_json_response_with_correct_pagination_data_for_datatables()
|
|
{
|
|
// Create some test users
|
|
$testUsers = User::factory()->count(15)->create();
|
|
|
|
// Set up the request parameters
|
|
$requestData = [
|
|
'draw' => 1,
|
|
'page' => 1, // Changed from 2 to 1 to match the controller logic
|
|
'size' => 5,
|
|
'search' => '',
|
|
'sortField' => 'name',
|
|
'sortOrder' => 'asc'
|
|
];
|
|
|
|
// Make the request
|
|
$response = $this->actingAs($this->user)
|
|
->getJson(route('users.datatables') . '?' . http_build_query($requestData));
|
|
|
|
// Assert response status and structure
|
|
$response->assertStatus(200);
|
|
$response->assertJsonStructure([
|
|
'draw',
|
|
'recordsTotal',
|
|
'recordsFiltered',
|
|
'pageCount',
|
|
'page',
|
|
'totalCount',
|
|
'data'
|
|
]);
|
|
|
|
// Get total count of users for verification (16 = 15 created + 1 from setup)
|
|
$totalUsers = User::count();
|
|
|
|
// Verify the pagination data
|
|
$responseData = $response->json();
|
|
$this->assertEquals(1, $responseData['draw']);
|
|
$this->assertEquals($totalUsers, $responseData['recordsTotal']);
|
|
$this->assertEquals($totalUsers, $responseData['recordsFiltered']);
|
|
$this->assertEquals(ceil($totalUsers / $requestData['size']), $responseData['pageCount']);
|
|
$this->assertEquals($requestData['page'], $responseData['page']);
|
|
|
|
// Verify that we have the correct number of users in the response
|
|
$this->assertCount(5, $responseData['data']);
|
|
|
|
// Verify that the data is ordered correctly - get first page of sorted data
|
|
$this->assertEquals(
|
|
User::orderBy('name', 'asc')->take(5)->pluck('id')->toArray(),
|
|
collect($responseData['data'])->pluck('id')->toArray()
|
|
);
|
|
}
|
|
|
|
#[Test]
|
|
public function should_filter_users_by_search_term_when_search_parameter_is_provided()
|
|
{
|
|
// Create test users with specific names for testing search
|
|
$matchingUser1 = User::factory()->create(['name' => 'Test User One']);
|
|
$matchingUser2 = User::factory()->create(['email' => 'test@example.com']);
|
|
$nonMatchingUser = User::factory()->create(['name' => 'Different User', 'email' => 'different@example.com']);
|
|
|
|
// Set up the request parameters with search term
|
|
$requestData = [
|
|
'draw' => 1,
|
|
'page' => 1,
|
|
'size' => 10,
|
|
'search' => 'test',
|
|
'sortField' => 'name',
|
|
'sortOrder' => 'asc'
|
|
];
|
|
|
|
// Make the request
|
|
$response = $this->actingAs($this->user)
|
|
->getJson(route('users.datatables') . '?' . http_build_query($requestData));
|
|
|
|
// Assert response status and structure
|
|
$response->assertStatus(200);
|
|
$response->assertJsonStructure([
|
|
'draw',
|
|
'recordsTotal',
|
|
'recordsFiltered',
|
|
'pageCount',
|
|
'page',
|
|
'totalCount',
|
|
'data'
|
|
]);
|
|
|
|
// Get the response data
|
|
$responseData = $response->json();
|
|
|
|
// Verify that only matching users are returned
|
|
$this->assertEquals(2, $responseData['recordsFiltered']);
|
|
|
|
// Extract user IDs from the response
|
|
$returnedUserIds = collect($responseData['data'])->pluck('id')->toArray();
|
|
|
|
// Verify the correct users are returned
|
|
$this->assertContains($matchingUser1->id, $returnedUserIds);
|
|
$this->assertContains($matchingUser2->id, $returnedUserIds);
|
|
$this->assertNotContains($nonMatchingUser->id, $returnedUserIds);
|
|
}
|
|
|
|
#[Test]
|
|
public function should_correctly_sort_users_when_sortField_and_sortOrder_parameters_are_specified()
|
|
{
|
|
// Create test users with varying names to test different sort orders
|
|
$userA = User::factory()->create(['name' => 'Adam Smith']);
|
|
$userB = User::factory()->create(['name' => 'Brian Jones']);
|
|
$userC = User::factory()->create(['name' => 'Charlie Brown']);
|
|
|
|
// Test ascending order
|
|
$requestDataAsc = [
|
|
'draw' => 1,
|
|
'page' => 1,
|
|
'size' => 10,
|
|
'search' => '',
|
|
'sortField' => 'name',
|
|
'sortOrder' => 'asc'
|
|
];
|
|
|
|
$responseAsc = $this->actingAs($this->user)
|
|
->getJson(route('users.datatables') . '?' . http_build_query($requestDataAsc));
|
|
|
|
$responseAsc->assertStatus(200);
|
|
$responseDataAsc = $responseAsc->json();
|
|
|
|
// Check if sorted ascending by name
|
|
$userIdsAsc = collect($responseDataAsc['data'])->pluck('id')->toArray();
|
|
$expectedOrderAsc = User::orderBy('name', 'asc')->pluck('id')->toArray();
|
|
$this->assertEquals($expectedOrderAsc, $userIdsAsc);
|
|
|
|
// Test descending order
|
|
$requestDataDesc = [
|
|
'draw' => 1,
|
|
'page' => 1,
|
|
'size' => 10,
|
|
'search' => '',
|
|
'sortField' => 'name',
|
|
'sortOrder' => 'desc'
|
|
];
|
|
|
|
$responseDesc = $this->actingAs($this->user)
|
|
->getJson(route('users.datatables') . '?' . http_build_query($requestDataDesc));
|
|
|
|
$responseDesc->assertStatus(200);
|
|
$responseDataDesc = $responseDesc->json();
|
|
|
|
// Check if sorted descending by name
|
|
$userIdsDesc = collect($responseDataDesc['data'])->pluck('id')->toArray();
|
|
$expectedOrderDesc = User::orderBy('name', 'desc')->pluck('id')->toArray();
|
|
$this->assertEquals($expectedOrderDesc, $userIdsDesc);
|
|
|
|
// Test sorting by a different field (email)
|
|
$requestDataEmail = [
|
|
'draw' => 1,
|
|
'page' => 1,
|
|
'size' => 10,
|
|
'search' => '',
|
|
'sortField' => 'email',
|
|
'sortOrder' => 'asc'
|
|
];
|
|
|
|
$responseEmail = $this->actingAs($this->user)
|
|
->getJson(route('users.datatables') . '?' . http_build_query($requestDataEmail));
|
|
|
|
$responseEmail->assertStatus(200);
|
|
$responseDataEmail = $responseEmail->json();
|
|
|
|
// Check if sorted by email
|
|
$userIdsEmail = collect($responseDataEmail['data'])->pluck('id')->toArray();
|
|
$expectedOrderEmail = User::orderBy('email', 'asc')->pluck('id')->toArray();
|
|
$this->assertEquals($expectedOrderEmail, $userIdsEmail);
|
|
}
|
|
|
|
#[Test]
|
|
public function should_successfully_create_a_new_user_and_assign_roles_when_valid_data_is_submitted()
|
|
{
|
|
// Prepare valid user data
|
|
$userData = [
|
|
'name' => 'Test User',
|
|
'email' => 'test@example.com',
|
|
'password' => 'password123',
|
|
'password_confirmation' => 'password123',
|
|
'nik' => '789234',
|
|
'roles' => ['operator']
|
|
];
|
|
|
|
// Submit the request to create a new user
|
|
$response = $this->actingAs($this->user)
|
|
->post(route('users.store'), $userData);
|
|
|
|
// Assert redirect to users index page with success message
|
|
$response->assertRedirect(route('users.index'));
|
|
$response->assertSessionHas('success', 'User created successfully.');
|
|
|
|
// Assert the user was created in the database
|
|
$this->assertDatabaseHas('users', [
|
|
'name' => 'Test User',
|
|
'email' => 'test@example.com',
|
|
'nik' => '789234'
|
|
]);
|
|
|
|
// Assert the user was assigned the correct role
|
|
$newUser = User::where('email', 'test@example.com')->first();
|
|
$this->assertTrue($newUser->hasRole('operator'));
|
|
}
|
|
|
|
#[Test]
|
|
public function should_successfully_update_existing_user_information_and_role_assignments()
|
|
{
|
|
// Create a test user with admin role
|
|
$userToUpdate = User::factory()->create([
|
|
'name' => 'Original Name',
|
|
'email' => 'originalee@example.com',
|
|
'nik' => '987654'
|
|
]);
|
|
$userToUpdate->assignRole($this->adminRole);
|
|
|
|
// Create an additional role for the update test
|
|
$newRole = Role::create(['name' => 'editor', 'guard_name' => 'web']);
|
|
|
|
// Prepare update data
|
|
$updateData = [
|
|
'name' => 'Updated Name',
|
|
'email' => 'updated@example.com',
|
|
'nik' => '654321',
|
|
'roles' => ['operator'] // Change role from admin to operator
|
|
];
|
|
|
|
// Make the request to update the user
|
|
$response = $this->actingAs($this->user)
|
|
->put(route('users.update', $userToUpdate->id), $updateData);
|
|
|
|
// Assert redirect to users index page with success message
|
|
$response->assertRedirect(route('users.index'));
|
|
$response->assertSessionHas('success', 'User updated successfully.');
|
|
|
|
// Assert the user was updated in the database
|
|
$this->assertDatabaseHas('users', [
|
|
'id' => $userToUpdate->id,
|
|
'name' => 'Updated Name',
|
|
'email' => 'updated@example.com',
|
|
'nik' => '654321'
|
|
]);
|
|
|
|
// Refresh the user model from database
|
|
$userToUpdate->refresh();
|
|
|
|
// Assert the user has the new role and doesn't have the old role
|
|
$this->assertTrue($userToUpdate->hasRole('operator'));
|
|
$this->assertFalse($userToUpdate->hasRole('admin'));
|
|
}
|
|
|
|
#[Test]
|
|
public function should_delete_a_user_when_the_authenticated_user_has_users_delete_permission()
|
|
{
|
|
// Create the permission for delete users
|
|
$permissionGroup = PermissionGroup::create([
|
|
'name' => 'usermanagement',
|
|
'slug' => 'usermanagement'
|
|
]);
|
|
|
|
// Create delete permission
|
|
Permission::create([
|
|
'name' => 'usermanagement.delete',
|
|
'guard_name' => 'web',
|
|
'permission_group_id' => $permissionGroup->id
|
|
]);
|
|
|
|
// Create role with delete permission
|
|
$role = Role::create(['name' => 'manager', 'guard_name' => 'web']);
|
|
$role->givePermissionTo('usermanagement.delete');
|
|
|
|
// Create an admin user with the role that has delete permission
|
|
$adminUser = User::factory()->create();
|
|
$adminUser->assignRole($role);
|
|
|
|
// Create a user to be deleted
|
|
$userToDelete = User::factory()->create();
|
|
|
|
// Make the request to delete the user
|
|
$response = $this->actingAs($adminUser)
|
|
->delete(route('users.destroy', $userToDelete->id));
|
|
|
|
// Assert the response is correct
|
|
$decodedResponse = json_decode($response->getContent(), true);
|
|
$this->assertEquals('User deleted successfully.', $decodedResponse['message']);
|
|
$this->assertTrue($decodedResponse['success']);
|
|
|
|
// Assert the user was soft deleted
|
|
$this->assertSoftDeleted('users', ['id' => $userToDelete->id]);
|
|
}
|
|
|
|
#[Test]
|
|
public function should_restore_a_soft_deleted_user_when_the_authenticated_user_has_users_restore_permission()
|
|
{
|
|
// Create permission group
|
|
$permissionGroup = PermissionGroup::create([
|
|
'name' => 'usermanagement',
|
|
'slug' => 'usermanagement'
|
|
]);
|
|
|
|
// Create restore permission
|
|
Permission::create([
|
|
'name' => 'usermanagement.restore',
|
|
'guard_name' => 'web',
|
|
'permission_group_id' => $permissionGroup->id
|
|
]);
|
|
|
|
// Create role with restore permission
|
|
$role = Role::create(['name' => 'restorer', 'guard_name' => 'web']);
|
|
$role->givePermissionTo('usermanagement.restore');
|
|
|
|
// Create an admin user with the role that has restore permission
|
|
$adminUser = User::factory()->create();
|
|
$adminUser->assignRole($role);
|
|
|
|
// Create a user to be restored
|
|
$userToRestore = User::factory()->create();
|
|
$userToRestore->delete(); // Soft delete the user
|
|
|
|
// Verify the user is soft-deleted
|
|
$this->assertSoftDeleted('users', ['id' => $userToRestore->id]);
|
|
|
|
// Make the request to restore the user
|
|
$response = $this->actingAs($adminUser)
|
|
->get(route('users.restore', $userToRestore->id));
|
|
|
|
// Assert the response redirects to users.index with success message
|
|
$response->assertRedirect(route('users.index'));
|
|
$response->assertSessionHas('success', 'User restored successfully.');
|
|
|
|
// Assert the user was restored
|
|
$this->assertDatabaseHas('users', [
|
|
'id' => $userToRestore->id,
|
|
'deleted_at' => null
|
|
]);
|
|
}
|
|
|
|
#[Test]
|
|
public function should_update_users_profile_including_signature_image_when_valid_data_is_submitted()
|
|
{
|
|
// Create a fake signature file
|
|
$file = UploadedFile::fake()->image('new-signature.jpg');
|
|
|
|
// Create a fake old signature file in storage
|
|
Storage::disk('public')->put(
|
|
'signatures/' . $this->user->id . '/old-signature.jpg',
|
|
'fake content'
|
|
);
|
|
|
|
// Prepare valid profile data with new signature
|
|
$profileData = [
|
|
'name' => 'Updated Name',
|
|
'email' => 'updated@example.com',
|
|
'nik' => '654321',
|
|
'sign' => $file
|
|
];
|
|
|
|
// Make the request to update the profile
|
|
$response = $this->actingAs($this->user)
|
|
->put(route('users.update-profile'), $profileData);
|
|
|
|
// Assert redirect to profile page with success message
|
|
$response->assertRedirect(route('users.profile'));
|
|
$response->assertSessionHas('success', 'Profile updated successfully.');
|
|
|
|
// Assert the user was updated in the database
|
|
$this->assertDatabaseHas('users', [
|
|
'id' => $this->user->id,
|
|
'name' => 'Updated Name',
|
|
'email' => 'updated@example.com',
|
|
'nik' => '654321',
|
|
]);
|
|
|
|
// Refresh the user model from database
|
|
$this->user->refresh();
|
|
|
|
// Assert that the user has a sign value (any non-empty string)
|
|
$this->assertNotEmpty($this->user->sign);
|
|
|
|
// Debug information
|
|
$files = Storage::disk('public')->allFiles('signatures/' . $this->user->id);
|
|
|
|
// Assert the file has been stored in the expected location
|
|
// Use a more flexible check that doesn't rely on the exact filename
|
|
$signaturePath = 'signatures/' . $this->user->id;
|
|
$this->assertTrue(
|
|
Storage::disk('public')->exists($signaturePath . '/' . $this->user->sign),
|
|
"Signature file not found at expected location: {$signaturePath}/{$this->user->sign}"
|
|
);
|
|
|
|
// Verify old signature was deleted
|
|
Storage::disk('public')->assertMissing('signatures/' . $this->user->id . '/old-signature.jpg');
|
|
}
|
|
}
|