withoutMiddleware(EnsurePlatformSession::class); $this->user = User::create([ 'public_id' => 'stroke-ext-user', 'name' => 'Stroke Ext', 'email' => 'stroke-ext@example.com', ]); $this->organization = Organization::create([ 'owner_ref' => $this->user->public_id, 'name' => 'Ext Clinic', 'slug' => 'ext-clinic', 'timezone' => 'UTC', 'settings' => [ 'onboarded' => true, 'rollout' => [CareFeatures::ASSESSMENTS_ENGINE => true], ], ]); Member::create([ 'owner_ref' => $this->user->public_id, 'organization_id' => $this->organization->id, 'user_ref' => $this->user->public_id, 'role' => 'doctor', ]); Branch::create([ 'owner_ref' => $this->user->public_id, 'organization_id' => $this->organization->id, 'name' => 'Main', 'is_active' => true, ]); $this->patient = Patient::create([ 'uuid' => (string) Str::uuid(), 'owner_ref' => $this->user->public_id, 'organization_id' => $this->organization->id, 'patient_number' => 'LC-SEXT-001', 'first_name' => 'Yaw', 'last_name' => 'Mensah', ]); $this->seed(AssessmentTemplateSeeder::class); $this->seed(ClinicalPathwaySeeder::class); } public function test_stroke_pathway_includes_extended_optional_instruments(): void { $pathway = ClinicalPathway::findByCode('stroke'); $codes = $pathway->templates()->pluck('template_code')->all(); $this->assertContains('barthel', $codes); $this->assertContains('gcs', $codes); $this->assertContains('stroke_swallow', $codes); $this->assertContains('stroke_clinical', $codes); $required = $pathway->templates()->where('is_required_on_activation', true)->pluck('template_code')->all(); $this->assertEqualsCanonicalizing(['nihss', 'mrs'], $required); } public function test_gcs_golden_score_e4_v5_m6_is_fifteen(): void { $this->actingAs($this->user) ->post(route('care.assessments.store', $this->patient), ['template_code' => 'gcs']) ->assertRedirect(); $assessment = Assessment::first(); $this->actingAs($this->user) ->put(route('care.assessments.update', $assessment), [ 'answers' => ['eye' => '4', 'verbal' => '5', 'motor' => '6'], ]); $this->actingAs($this->user) ->post(route('care.assessments.complete', $assessment)) ->assertRedirect(); $score = AssessmentScore::first(); $this->assertEquals(15, (float) $score->total_score); $this->assertEquals(15, (float) $score->max_score); } public function test_barthel_fully_independent_is_one_hundred(): void { $this->actingAs($this->user) ->post(route('care.assessments.store', $this->patient), ['template_code' => 'barthel']) ->assertRedirect(); $assessment = Assessment::first(); $answers = [ 'feeding' => '10', 'bathing' => '5', 'grooming' => '5', 'dressing' => '10', 'bowels' => '10', 'bladder' => '10', 'toilet' => '10', 'transfers' => '15', 'mobility' => '15', 'stairs' => '10', ]; $this->actingAs($this->user) ->put(route('care.assessments.update', $assessment), ['answers' => $answers]); $this->actingAs($this->user) ->post(route('care.assessments.complete', $assessment)) ->assertRedirect(); $this->assertEquals(100, (float) AssessmentScore::first()->total_score); $this->assertEquals(100, (float) AssessmentScore::first()->max_score); } public function test_stroke_clinical_records_tia_subtype(): void { $this->actingAs($this->user) ->post(route('care.assessments.store', $this->patient), ['template_code' => 'stroke_clinical']) ->assertRedirect(); $assessment = Assessment::first(); $this->actingAs($this->user) ->put(route('care.assessments.update', $assessment), [ 'answers' => [ 'stroke_subtype' => 'tia', 'thrombolysis_status' => 'not_indicated', ], ]); $this->actingAs($this->user) ->post(route('care.assessments.complete', $assessment)) ->assertRedirect(); $this->assertTrue($assessment->fresh()->isCompleted()); $this->assertSame(0, AssessmentScore::count()); // no scoring strategy $subtype = $assessment->fresh()->answers->first( fn ($a) => $a->question?->code === 'stroke_subtype' ); $this->assertSame('tia', $subtype->value_text); } public function test_all_extended_templates_seeded(): void { foreach (['barthel', 'gcs', 'stroke_swallow', 'stroke_clinical'] as $code) { $this->assertNotNull(AssessmentTemplate::currentSystemByCode($code), $code); } } }