Files
Verde-Web/tests/Feature/Api/V1/Admin/AdminUserCrudTest.php

322 lines
11 KiB
PHP

<?php
namespace Tests\Feature\Api\V1\Admin;
use App\Models\Barangay;
use App\Models\DriverProfile;
use App\Models\Household;
use App\Models\HouseholdMember;
use App\Models\ResidentProfile;
use App\Models\User;
use Database\Seeders\RoleSeeder;
use Database\Seeders\SamplePsgcSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use MatanYadaev\EloquentSpatial\Objects\Point;
use Tests\TestCase;
class AdminUserCrudTest extends TestCase
{
use RefreshDatabase;
private User $admin;
protected function setUp(): void
{
parent::setUp();
$this->seed(RoleSeeder::class);
$this->admin = User::factory()->create([
'role' => User::ROLE_ADMIN,
'status' => User::STATUS_ACTIVE,
]);
}
public function test_admin_can_list_users_with_filters(): void
{
Sanctum::actingAs($this->admin);
User::factory()->count(3)->create(['role' => User::ROLE_RESIDENT]);
User::factory()->count(2)->create(['role' => User::ROLE_DRIVER]);
$response = $this->getJson('/api/v1/admin/users?role=resident');
$response->assertOk();
$items = $response->json('data');
$this->assertGreaterThanOrEqual(3, count($items));
foreach ($items as $u) {
$this->assertSame('resident', $u['role']);
}
}
public function test_admin_can_search_users_by_name_or_email(): void
{
Sanctum::actingAs($this->admin);
User::factory()->create(['email' => 'unique-find@example.com']);
$response = $this->getJson('/api/v1/admin/users?q=unique-find');
$response->assertOk()
->assertJsonFragment(['email' => 'unique-find@example.com']);
}
public function test_admin_can_show_user_with_profile(): void
{
Sanctum::actingAs($this->admin);
$user = User::factory()->create(['role' => User::ROLE_RESIDENT]);
ResidentProfile::create(['user_id' => $user->id, 'occupation' => 'Teacher']);
$response = $this->getJson("/api/v1/admin/users/{$user->uuid}");
$response->assertOk()
->assertJsonPath('data.id', $user->uuid)
->assertJsonPath('data.profile.occupation', 'Teacher');
}
public function test_admin_can_update_user(): void
{
Sanctum::actingAs($this->admin);
$user = User::factory()->create();
$response = $this->patchJson("/api/v1/admin/users/{$user->uuid}", [
'first_name' => 'Updated',
'preferred_language' => 'tl',
]);
$response->assertOk()
->assertJsonPath('data.first_name', 'Updated')
->assertJsonPath('data.preferred_language', 'tl');
}
public function test_admin_can_suspend_and_activate_user(): void
{
Sanctum::actingAs($this->admin);
$user = User::factory()->create([
'role' => User::ROLE_DRIVER,
'status' => User::STATUS_ACTIVE,
]);
$this->postJson("/api/v1/admin/users/{$user->uuid}/suspend")
->assertOk()
->assertJsonPath('data.status', User::STATUS_SUSPENDED);
$this->postJson("/api/v1/admin/users/{$user->uuid}/activate")
->assertOk()
->assertJsonPath('data.status', User::STATUS_ACTIVE);
}
public function test_admin_cannot_suspend_other_admin(): void
{
Sanctum::actingAs($this->admin);
$otherAdmin = User::factory()->create(['role' => User::ROLE_ADMIN]);
$response = $this->postJson("/api/v1/admin/users/{$otherAdmin->uuid}/suspend");
$response->assertStatus(422);
}
public function test_admin_can_soft_delete_user(): void
{
Sanctum::actingAs($this->admin);
$user = User::factory()->create(['role' => User::ROLE_RESIDENT]);
$response = $this->deleteJson("/api/v1/admin/users/{$user->uuid}");
$response->assertOk();
$this->assertSoftDeleted('users', ['id' => $user->id]);
}
public function test_admin_can_approve_driver_profile(): void
{
Sanctum::actingAs($this->admin);
$driver = User::factory()->create([
'role' => User::ROLE_DRIVER,
'status' => User::STATUS_PENDING,
]);
DriverProfile::create(['user_id' => $driver->id, 'license_number' => 'D-1234']);
$response = $this->postJson("/api/v1/admin/users/{$driver->uuid}/approve-profile");
$response->assertOk()
->assertJsonPath('data.status', User::STATUS_ACTIVE)
->assertJsonPath('data.profile.verification_status', 'approved');
$this->assertDatabaseHas('driver_profiles', [
'user_id' => $driver->id,
'verification_status' => 'approved',
]);
}
public function test_admin_can_reject_driver_profile_with_reason(): void
{
Sanctum::actingAs($this->admin);
$driver = User::factory()->create(['role' => User::ROLE_DRIVER]);
DriverProfile::create(['user_id' => $driver->id, 'license_number' => 'D-9999']);
$response = $this->postJson("/api/v1/admin/users/{$driver->uuid}/reject-profile", [
'reason' => 'License photo unreadable',
]);
$response->assertOk()
->assertJsonPath('data.profile.verification_status', 'rejected')
->assertJsonPath('data.profile.rejection_reason', 'License photo unreadable');
}
public function test_resident_blocked_from_admin_users(): void
{
$resident = User::factory()->create([
'role' => User::ROLE_RESIDENT,
'status' => User::STATUS_ACTIVE,
]);
Sanctum::actingAs($resident);
$this->getJson('/api/v1/admin/users')->assertStatus(403);
}
public function test_unauthed_blocked_from_admin_users(): void
{
$this->getJson('/api/v1/admin/users')->assertStatus(401);
}
public function test_resident_activation_requires_super_admin_and_coordinates(): void
{
$resident = User::factory()->create([
'role' => User::ROLE_RESIDENT,
'status' => User::STATUS_PENDING,
]);
Sanctum::actingAs($this->admin);
$this->postJson("/api/v1/admin/users/{$resident->uuid}/activate")
->assertStatus(403);
$superAdmin = User::factory()->create([
'role' => User::ROLE_SUPER_ADMIN,
'status' => User::STATUS_ACTIVE,
]);
Sanctum::actingAs($superAdmin);
$this->postJson("/api/v1/admin/users/{$resident->uuid}/activate")
->assertStatus(422)
->assertJsonFragment(['message' => 'Resident household must have coordinates pinned before activation']);
$household = Household::factory()->create([
'head_user_id' => $resident->id,
'coordinates' => new Point(14.5995, 120.9842, 4326),
]);
HouseholdMember::create([
'household_id' => $household->id,
'user_id' => $resident->id,
'relationship' => HouseholdMember::RELATIONSHIP_HEAD,
'full_name' => $resident->full_name,
]);
$this->postJson("/api/v1/admin/users/{$resident->uuid}/activate")
->assertOk()
->assertJsonPath('data.status', User::STATUS_ACTIVE);
}
public function test_admin_can_group_resident_into_existing_household(): void
{
Sanctum::actingAs($this->admin);
$resident = User::factory()->create([
'role' => User::ROLE_RESIDENT,
'status' => User::STATUS_PENDING,
]);
$household = Household::factory()->create();
$response = $this->postJson("/api/v1/admin/users/{$resident->uuid}/group-into-household", [
'household_id' => $household->id,
]);
$response->assertOk()
->assertJsonPath('data.household.id', $household->uuid);
$this->assertDatabaseHas('household_members', [
'household_id' => $household->id,
'user_id' => $resident->id,
'relationship' => HouseholdMember::RELATIONSHIP_OTHER,
]);
}
public function test_admin_can_group_resident_into_new_household(): void
{
Sanctum::actingAs($this->admin);
$this->seed(SamplePsgcSeeder::class);
$barangay = Barangay::firstOrFail();
$resident = User::factory()->create([
'role' => User::ROLE_RESIDENT,
'status' => User::STATUS_PENDING,
]);
$response = $this->postJson("/api/v1/admin/users/{$resident->uuid}/group-into-household", [
'address_line' => '123 New Pin Street',
'barangay_id' => $barangay->id,
'household_size' => 3,
'lat' => 14.5995,
'lng' => 120.9842,
]);
$response->assertOk()
->assertJsonPath('data.household.address_line', '123 New Pin Street')
->assertJsonPath('data.household.household_size', 3);
$this->assertDatabaseHas('households', [
'head_user_id' => $resident->id,
'address_line' => '123 New Pin Street',
'household_size' => 3,
]);
$this->assertDatabaseHas('household_members', [
'user_id' => $resident->id,
'relationship' => HouseholdMember::RELATIONSHIP_HEAD,
]);
}
public function test_admin_can_group_resident_with_existing_household_and_clean_it_up(): void
{
Sanctum::actingAs($this->admin);
$resident = User::factory()->create([
'role' => User::ROLE_RESIDENT,
'status' => User::STATUS_ACTIVE,
]);
$oldHousehold = Household::factory()->create([
'head_user_id' => $resident->id,
]);
$oldMember = HouseholdMember::create([
'household_id' => $oldHousehold->id,
'user_id' => $resident->id,
'relationship' => HouseholdMember::RELATIONSHIP_HEAD,
'full_name' => $resident->full_name,
]);
$newHousehold = Household::factory()->create();
$response = $this->postJson("/api/v1/admin/users/{$resident->uuid}/group-into-household", [
'household_id' => $newHousehold->id,
]);
$response->assertOk();
// Check new membership
$this->assertDatabaseHas('household_members', [
'household_id' => $newHousehold->id,
'user_id' => $resident->id,
'relationship' => HouseholdMember::RELATIONSHIP_OTHER,
]);
// Check old membership deleted
$this->assertSoftDeleted('household_members', [
'id' => $oldMember->id,
]);
// Check old household deleted
$this->assertSoftDeleted('households', [
'id' => $oldHousehold->id,
]);
}
}