withoutMiddleware(EnsurePlatformSession::class); $this->user = User::create([ 'public_id' => 'outcome-user', 'name' => 'Outcome User', 'email' => 'outcome@example.com', ]); $this->organization = Organization::create([ 'owner_ref' => $this->user->public_id, 'name' => 'Outcome Clinic', 'slug' => 'outcome-clinic', 'timezone' => 'UTC', 'settings' => [ 'onboarded' => true, 'plan' => 'free', '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' => 'nurse', ]); 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-OUT-001', 'first_name' => 'Kofi', 'last_name' => 'Owusu', ]); $this->seed(AssessmentTemplateSeeder::class); } public function test_outcome_core_seeded(): void { $t = AssessmentTemplate::currentSystemByCode('outcome_core'); $this->assertNotNull($t); $this->assertSame(AssessmentTemplate::CATEGORY_OUTCOME, $t->category); $this->assertTrue($t->questions()->where('code', 'quality_of_life')->exists()); $this->assertTrue($t->questions()->where('code', 'falls_count')->exists()); } public function test_nurse_can_record_outcomes_and_see_trends_on_free_plan(): void { $this->actingAs($this->user) ->post(route('care.outcomes.store', $this->patient)) ->assertRedirect(); $assessment = Assessment::first(); $this->assertSame('outcome_core', $assessment->template->code); $this->actingAs($this->user) ->put(route('care.assessments.update', $assessment), [ 'answers' => [ 'quality_of_life' => 7, 'pain_score' => 3, 'falls_count' => 1, 'hospital_admissions_since_last' => 0, 'medication_adherence' => 'good', ], ]); $this->actingAs($this->user) ->post(route('care.assessments.complete', $assessment)) ->assertRedirect(); $this->actingAs($this->user) ->get(route('care.outcomes.index', $this->patient)) ->assertOk() ->assertSee('Longitudinal outcomes') ->assertSee('Quality of life trend') ->assertSee('7') ->assertSee('Pain score trend') ->assertSee('3') ->assertSee('Enterprise'); // free plan notice $this->actingAs($this->user) ->get(route('care.patients.show', $this->patient)) ->assertOk() ->assertSee('Outcomes'); } public function test_second_outcome_builds_series(): void { foreach ([[5, 4], [8, 2]] as [$qol, $pain]) { $this->actingAs($this->user) ->post(route('care.outcomes.store', $this->patient)) ->assertRedirect(); $assessment = Assessment::query()->where('status', Assessment::STATUS_DRAFT)->latest('id')->first(); $this->actingAs($this->user) ->put(route('care.assessments.update', $assessment), [ 'answers' => [ 'quality_of_life' => $qol, 'pain_score' => $pain, ], ]); $this->actingAs($this->user) ->post(route('care.assessments.complete', $assessment)); } // Idempotent start when draft exists would reuse — after complete, second store creates new. $this->assertSame(2, Assessment::where('status', Assessment::STATUS_COMPLETED)->count()); $html = $this->actingAs($this->user) ->get(route('care.outcomes.index', $this->patient)) ->assertOk() ->getContent(); $this->assertStringContainsString('8', $html); $this->assertStringContainsString('5', $html); } }