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); } }