withoutMiddleware(EnsurePlatformSession::class); $this->user = User::create([ 'public_id' => 'stroke-mvp-user', 'name' => 'Stroke MVP', 'email' => 'stroke@example.com', ]); $this->organization = Organization::create([ 'owner_ref' => $this->user->public_id, 'name' => 'Stroke Clinic', 'slug' => 'stroke-clinic', 'timezone' => 'UTC', 'settings' => [ 'onboarded' => true, 'rollout' => [CareFeatures::ASSESSMENTS_ENGINE => true], ], ]); $this->member = 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', 'is_active' => true, ]); $this->patient = Patient::create([ 'uuid' => (string) Str::uuid(), 'owner_ref' => $this->user->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'patient_number' => 'LC-STROKE-001', 'first_name' => 'Efua', 'last_name' => 'Asante', ]); $this->seed(AssessmentTemplateSeeder::class); $this->seed(ClinicalPathwaySeeder::class); } public function test_seed_packs_load_nihss_and_mrs(): void { $nihss = AssessmentTemplate::currentSystemByCode('nihss'); $mrs = AssessmentTemplate::currentSystemByCode('mrs'); $this->assertNotNull($nihss); $this->assertNotNull($mrs); $this->assertSame('sum_items', $nihss->scoring_strategy); $this->assertSame('single_value', $mrs->scoring_strategy); $this->assertSame(15, $nihss->questions()->count()); $this->assertSame(1, $mrs->questions()->count()); $this->assertSame(['doctor'], $nihss->meta['capture_roles'] ?? null); $pathway = ClinicalPathway::findByCode('stroke'); $this->assertNotNull($pathway); $codes = $pathway->templates()->pluck('template_code')->all(); $this->assertContains('nihss', $codes); $this->assertContains('mrs', $codes); $required = $pathway->templates()->where('is_required_on_activation', true)->pluck('template_code')->all(); $this->assertEqualsCanonicalizing(['nihss', 'mrs'], $required); } public function test_golden_mrs_score_three(): void { $this->actingAs($this->user) ->post(route('care.assessments.store', $this->patient), ['template_code' => 'mrs']) ->assertRedirect(); $assessment = Assessment::first(); $this->actingAs($this->user) ->put(route('care.assessments.update', $assessment), [ 'answers' => ['mrs_score' => '3'], ]) ->assertRedirect(); $this->actingAs($this->user) ->post(route('care.assessments.complete', $assessment)) ->assertRedirect(); $score = AssessmentScore::where('assessment_id', $assessment->id)->first(); $this->assertNotNull($score); $this->assertEquals(3, (float) $score->total_score); $this->assertEquals(6, (float) $score->max_score); $this->assertSame('mrs', $score->template_code); } public function test_golden_nihss_fixture_total_twelve_max_forty_two(): void { // Moderate left hemisphere pattern → total 12; max 42. $answers = [ '1a_loc' => '1', '1b_loc_questions' => '1', '1c_loc_commands' => '0', '2_gaze' => '0', '3_visual' => '1', '4_facial' => '2', '5a_motor_arm_left' => '2', '5b_motor_arm_right' => '0', '6a_motor_leg_left' => '2', '6b_motor_leg_right' => '0', '7_ataxia' => '0', '8_sensory' => '1', '9_language' => '1', '10_dysarthria' => '1', '11_extinction' => '0', ]; // 1+1+0+0+1+2+2+0+2+0+0+1+1+1+0 = 12 $this->actingAs($this->user) ->post(route('care.assessments.store', $this->patient), ['template_code' => 'nihss']) ->assertRedirect(); $assessment = Assessment::first(); $this->actingAs($this->user) ->put(route('care.assessments.update', $assessment), ['answers' => $answers]) ->assertRedirect(); $preview = app(ScoringService::class)->preview( $assessment->fresh(['template.questions', 'answers.question']) ); $this->assertEquals(12.0, $preview['total']); $this->assertEquals(42.0, $preview['max']); $this->actingAs($this->user) ->post(route('care.assessments.complete', $assessment)) ->assertRedirect(); $score = AssessmentScore::first(); $this->assertEquals(12, (float) $score->total_score); $this->assertEquals(42, (float) $score->max_score); $this->assertArrayHasKey('loc', $score->subscores); $this->assertEquals(2.0, (float) $score->subscores['loc']); // 1a+1b+1c = 2 } public function test_m2_e2e_activate_stroke_complete_nihss_and_mrs(): void { $visit = Visit::create([ 'owner_ref' => $this->user->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'patient_id' => $this->patient->id, 'status' => Visit::STATUS_OPEN, 'checked_in_at' => now(), ]); $consultation = Consultation::create([ 'owner_ref' => $this->user->public_id, 'visit_id' => $visit->id, 'patient_id' => $this->patient->id, 'status' => Consultation::STATUS_DRAFT, 'started_at' => now(), ]); Diagnosis::create([ 'owner_ref' => $this->user->public_id, 'consultation_id' => $consultation->id, 'code' => 'I63.9', 'description' => 'Cerebral infarction, unspecified', 'is_primary' => true, ]); $this->actingAs($this->user) ->get(route('care.consultations.show', $consultation)) ->assertOk() ->assertSee('Stroke') ->assertSee('Activate'); $this->actingAs($this->user) ->post(route('care.pathways.store', $this->patient), [ 'pathway_code' => 'stroke', 'consultation_uuid' => $consultation->uuid, ]) ->assertRedirect(); $this->assertSame(1, PatientPathway::where('status', PatientPathway::STATUS_ACTIVE)->count()); $this->assertSame(2, Assessment::where('status', Assessment::STATUS_DRAFT)->count()); $this->actingAs($this->user) ->get(route('care.consultations.show', $consultation)) ->assertOk() ->assertSee('Pathway instruments') ->assertSee('NIH Stroke Scale') ->assertSee('Modified Rankin Scale') ->assertSee('Continue'); $nihss = Assessment::query() ->whereHas('template', fn ($q) => $q->where('code', 'nihss')) ->first(); $mrs = Assessment::query() ->whereHas('template', fn ($q) => $q->where('code', 'mrs')) ->first(); $this->assertNotNull($nihss); $this->assertNotNull($mrs); $this->assertSame($consultation->id, $nihss->consultation_id); // Minimal valid NIHSS (all zeros) → total 0. $zeroAnswers = collect($nihss->template->questions)->mapWithKeys( fn ($q) => [$q->code => '0'] )->all(); $this->actingAs($this->user) ->put(route('care.assessments.update', $nihss), ['answers' => $zeroAnswers]) ->assertRedirect(); $this->actingAs($this->user) ->post(route('care.assessments.complete', $nihss)) ->assertRedirect(); $this->assertEquals(0, (float) AssessmentScore::where('assessment_id', $nihss->id)->value('total_score')); $this->assertEquals(42, (float) AssessmentScore::where('assessment_id', $nihss->id)->value('max_score')); $this->actingAs($this->user) ->put(route('care.assessments.update', $mrs), ['answers' => ['mrs_score' => '2']]) ->assertRedirect(); $this->actingAs($this->user) ->post(route('care.assessments.complete', $mrs)) ->assertRedirect(); $this->assertEquals(2, (float) AssessmentScore::where('assessment_id', $mrs->id)->value('total_score')); $this->actingAs($this->user) ->get(route('care.consultations.show', $consultation)) ->assertOk() ->assertSee('score 0') ->assertSee('score 2'); } public function test_nurse_cannot_start_seeded_nihss(): void { $this->member->update(['role' => 'nurse']); $this->actingAs($this->user) ->post(route('care.assessments.store', $this->patient), ['template_code' => 'nihss']) ->assertForbidden(); } }