Files
ladill-care/tests/Feature/CareLabTest.php
T
isaaccladandCursor 656f402e8f
Deploy Ladill Care / deploy (push) Successful in 38s
Restrict lab catalog pricing to admins only.
Split catalog CRUD onto lab.catalog.manage so technicians keep lab.manage for queue and results workflow without setting investigation prices.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-18 18:58:57 +00:00

300 lines
10 KiB
PHP

<?php
namespace Tests\Feature;
use App\Http\Middleware\EnsurePlatformSession;
use App\Models\Branch;
use App\Models\Consultation;
use App\Models\Department;
use App\Models\InvestigationRequest;
use App\Models\InvestigationType;
use App\Models\Member;
use App\Models\Organization;
use App\Models\Patient;
use App\Models\Practitioner;
use App\Models\User;
use App\Models\Visit;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;
class CareLabTest extends TestCase
{
use RefreshDatabase;
protected User $user;
protected Organization $organization;
protected Branch $branch;
protected Patient $patient;
protected Consultation $consultation;
protected InvestigationType $investigationType;
protected function setUp(): void
{
parent::setUp();
$this->withoutMiddleware(EnsurePlatformSession::class);
$this->user = User::create([
'public_id' => 'test-user-001',
'name' => 'Test User',
'email' => 'test@example.com',
]);
$this->organization = Organization::create([
'owner_ref' => $this->user->public_id,
'name' => 'Test Clinic',
'slug' => 'test-clinic',
'timezone' => 'UTC',
'settings' => ['onboarded' => true, 'plan' => 'pro', 'plan_expires_at' => now()->addMonth()->toIso8601String()],
]);
Member::create([
'owner_ref' => $this->user->public_id,
'organization_id' => $this->organization->id,
'user_ref' => $this->user->public_id,
'role' => 'doctor',
]);
$this->branch = Branch::create([
'owner_ref' => $this->user->public_id,
'organization_id' => $this->organization->id,
'name' => 'Main Branch',
'is_active' => true,
]);
Department::create([
'owner_ref' => $this->user->public_id,
'branch_id' => $this->branch->id,
'name' => 'Laboratory',
'type' => 'laboratory',
'is_active' => true,
]);
$this->patient = Patient::create([
'uuid' => (string) \Illuminate\Support\Str::uuid(),
'owner_ref' => $this->user->public_id,
'organization_id' => $this->organization->id,
'branch_id' => $this->branch->id,
'patient_number' => 'LC-2026-00001',
'first_name' => 'Ama',
'last_name' => 'Mensah',
]);
$visit = Visit::create([
'uuid' => (string) \Illuminate\Support\Str::uuid(),
'owner_ref' => $this->user->public_id,
'organization_id' => $this->organization->id,
'branch_id' => $this->branch->id,
'patient_id' => $this->patient->id,
'status' => Visit::STATUS_IN_PROGRESS,
'checked_in_at' => now(),
]);
$this->consultation = Consultation::create([
'uuid' => (string) \Illuminate\Support\Str::uuid(),
'owner_ref' => $this->user->public_id,
'visit_id' => $visit->id,
'patient_id' => $this->patient->id,
'status' => Consultation::STATUS_DRAFT,
'started_at' => now(),
]);
$this->investigationType = InvestigationType::create([
'owner_ref' => $this->user->public_id,
'organization_id' => $this->organization->id,
'name' => 'Fasting Blood Glucose',
'code' => 'FBG',
'category' => 'blood',
'unit' => 'mmol/L',
'reference_low' => 3.9,
'reference_high' => 6.1,
'price_minor' => 2500,
'is_active' => true,
]);
}
public function test_doctor_can_request_investigation(): void
{
$this->actingAs($this->user)
->post(route('care.lab.requests.store', $this->consultation), [
'investigation_type_ids' => [$this->investigationType->id],
'clinical_notes' => 'Suspected hyperglycemia',
'priority' => 'routine',
])
->assertRedirect();
$this->assertDatabaseHas('care_investigation_requests', [
'patient_id' => $this->patient->id,
'status' => InvestigationRequest::STATUS_PENDING,
]);
$this->assertDatabaseHas('care_audit_logs', ['action' => 'investigation.requested']);
}
public function test_full_lab_workflow(): void
{
$request = InvestigationRequest::create([
'uuid' => (string) \Illuminate\Support\Str::uuid(),
'owner_ref' => $this->user->public_id,
'organization_id' => $this->organization->id,
'branch_id' => $this->branch->id,
'visit_id' => $this->consultation->visit_id,
'consultation_id' => $this->consultation->id,
'patient_id' => $this->patient->id,
'investigation_type_id' => $this->investigationType->id,
'status' => InvestigationRequest::STATUS_PENDING,
'priority' => 'routine',
]);
Member::where('user_ref', $this->user->public_id)->update(['role' => 'lab_technician']);
$this->actingAs($this->user)
->post(route('care.lab.requests.collect-sample', $request))
->assertRedirect();
$request->refresh();
$this->assertSame(InvestigationRequest::STATUS_SAMPLE_COLLECTED, $request->status);
$this->assertNotNull($request->sample_barcode);
$this->actingAs($this->user)
->post(route('care.lab.requests.start', $request))
->assertRedirect();
$request->refresh();
$this->assertSame(InvestigationRequest::STATUS_IN_PROGRESS, $request->status);
$this->actingAs($this->user)
->post(route('care.lab.requests.results', $request), [
'value' => '8.5',
'result_summary' => 'Elevated fasting glucose',
'interpretation' => 'Repeat test recommended',
])
->assertRedirect();
$request->refresh();
$this->assertSame(InvestigationRequest::STATUS_AWAITING_REVIEW, $request->status);
$this->assertTrue($request->result->is_abnormal);
$this->actingAs($this->user)
->post(route('care.lab.requests.approve', $request))
->assertRedirect();
$request->refresh();
$this->assertSame(InvestigationRequest::STATUS_COMPLETED, $request->status);
$this->actingAs($this->user)
->post(route('care.lab.requests.deliver', $request))
->assertRedirect();
$request->refresh();
$this->assertSame(InvestigationRequest::STATUS_DELIVERED, $request->status);
}
public function test_lab_queue_loads(): void
{
Member::where('user_ref', $this->user->public_id)->update(['role' => 'lab_technician']);
$this->actingAs($this->user)
->get(route('care.lab.queue.index', ['branch_id' => $this->branch->id]))
->assertOk()
->assertSee('Lab work queue')
->assertDontSee('Catalog');
}
public function test_lab_technician_cannot_manage_catalog(): void
{
Member::where('user_ref', $this->user->public_id)->update(['role' => 'lab_technician']);
$this->actingAs($this->user)
->get(route('care.lab.catalog.index'))
->assertForbidden();
$this->actingAs($this->user)
->get(route('care.lab.catalog.create'))
->assertForbidden();
$this->actingAs($this->user)
->post(route('care.lab.catalog.store'), [
'name' => 'Unauthorized Test',
'category' => 'blood',
'price_minor' => 1000,
])
->assertForbidden();
$this->actingAs($this->user)
->get(route('care.lab.catalog.edit', $this->investigationType))
->assertForbidden();
$this->actingAs($this->user)
->put(route('care.lab.catalog.update', $this->investigationType), [
'name' => 'Hacked Price',
'category' => 'blood',
'price_minor' => 1,
])
->assertForbidden();
}
public function test_hospital_admin_can_manage_catalog(): void
{
Member::where('user_ref', $this->user->public_id)->update(['role' => 'hospital_admin']);
$this->actingAs($this->user)
->get(route('care.lab.catalog.index'))
->assertOk()
->assertSee('Investigation catalog');
$this->actingAs($this->user)
->get(route('care.lab.catalog.create'))
->assertOk();
$this->actingAs($this->user)
->post(route('care.lab.catalog.store'), [
'name' => 'Lipid Panel',
'code' => 'LIP',
'category' => 'blood',
'price_minor' => 4500,
'is_active' => true,
])
->assertRedirect(route('care.lab.catalog.index'));
$this->assertDatabaseHas('care_investigation_types', [
'organization_id' => $this->organization->id,
'name' => 'Lipid Panel',
'price_minor' => 4500,
]);
$this->actingAs($this->user)
->put(route('care.lab.catalog.update', $this->investigationType), [
'name' => 'Fasting Blood Glucose',
'code' => 'FBG',
'category' => 'blood',
'unit' => 'mmol/L',
'reference_low' => 3.9,
'reference_high' => 6.1,
'price_minor' => 3000,
'is_active' => true,
])
->assertRedirect(route('care.lab.catalog.index'));
$this->assertDatabaseHas('care_investigation_types', [
'id' => $this->investigationType->id,
'price_minor' => 3000,
]);
}
public function test_api_can_request_investigation(): void
{
Sanctum::actingAs($this->user);
$this->postJson("/api/v1/consultations/{$this->consultation->uuid}/investigations", [
'investigation_type_ids' => [$this->investigationType->id],
])
->assertCreated()
->assertJsonPath('data.0.patient_id', $this->patient->id);
}
}