assertStringContainsString("group('administrator/assessments'", $routes); $this->assertStringContainsString("\$assessmentAdminFilter = 'auth:admin_category'", $routes); $this->assertStringContainsString('AssessmentController::saveGrade', $routes); $this->assertStringContainsString("group('student/assessments'", $routes); $this->assertStringContainsString("'filter' => 'auth:student|parent'", $routes); } public function testMigrationEnforcesSingleAssignmentAndAnswerPerQuestion(): void { $migration = file_get_contents(ROOTPATH . 'app/Database/Migrations/2026-09-09-000100_CreateStudentAssessmentTables.php') ?: ''; $this->assertStringContainsString("addUniqueKey(['form_id', 'student_id'], 'uq_assessment_form_student')", $migration); $this->assertStringContainsString("addUniqueKey(['student_assessment_id', 'question_id'], 'uq_student_answer_question')", $migration); $this->assertStringContainsString("['not_started', 'in_progress', 'completed', 'graded']", $migration); } public function testStudentProfilesExposeAssessmentActions(): void { $view = file_get_contents(ROOTPATH . 'app/Views/administrator/student_profiles.php') ?: ''; foreach (['Assign Assessment', 'View Status', 'Review', 'View Results'] as $label) { $this->assertStringContainsString($label, $view); } } public function testAssessmentRosterUsesTheNewStudentEnrollmentSource(): void { $controller = file_get_contents(ROOTPATH . 'app/Controllers/View/AssessmentController.php') ?: ''; $newStudentView = file_get_contents(ROOTPATH . 'app/Views/enroll_withdraw/new-students.php') ?: ''; $this->assertStringContainsString("service('enrollmentWithdrawal')->newStudents(\$schoolYear)", $controller); $this->assertStringContainsString('administrator/assessments/students/', $newStudentView); $this->assertStringContainsString('Assign Assessment', $newStudentView); } public function testSharedAssessmentsAreNotBlockedByHistoricalYearContext(): void { $filter = file_get_contents(ROOTPATH . 'app/Filters/SchoolYearWritableFilter.php') ?: ''; $this->assertStringContainsString("'administrator/assessments'", $filter); $this->assertStringContainsString("'student/assessments'", $filter); } public function testNewStudentQuestionPoolSeedsAllIntakeQuestions(): void { $migration = file_get_contents(ROOTPATH . 'app/Database/Migrations/2026-09-10-000100_SeedNewStudentAssessmentQuestions.php') ?: ''; $this->assertStringContainsString("POOL_NAME = 'New Student Assessment'", $migration); preg_match_all("/^ 'text' => '[^\n]+',$/m", $migration, $questionLines); $this->assertCount(9, $questionLines[0]); $this->assertStringContainsString('Arabic competency level', $migration); $this->assertStringContainsString('questions / concerns', $migration); } public function testAdminInterviewAutosavesWithoutSaveButton(): void { $view = file_get_contents(ROOTPATH . 'app/Views/assessments/admin_take.php') ?: ''; $this->assertStringContainsString('Responses save automatically as you type.', $view); $this->assertStringContainsString('/progress', $view); $this->assertStringContainsString('Complete Assessment', $view); $this->assertStringNotContainsString('Save Progress', $view); } public function testAssessmentFormsIncludeEducationCommitteeNote(): void { $builder = file_get_contents(ROOTPATH . 'app/Views/assessments/form_builder.php') ?: ''; $migration = file_get_contents(ROOTPATH . 'app/Database/Migrations/2026-09-10-000200_AddEducationCommitteeNoteToAssessmentForms.php') ?: ''; $this->assertStringContainsString('Education Committee Note', $builder); $this->assertStringContainsString('education_committee_note', $builder); $this->assertStringContainsString("'type' => 'TEXT'", $migration); } public function testStudentAssessmentHasAutosavingEducationCommitteeNote(): void { $view = file_get_contents(ROOTPATH . 'app/Views/assessments/admin_take.php') ?: ''; $review = file_get_contents(ROOTPATH . 'app/Views/assessments/grade.php') ?: ''; $results = file_get_contents(ROOTPATH . 'app/Views/assessments/results.php') ?: ''; $routes = file_get_contents(ROOTPATH . 'app/Config/Routes.php') ?: ''; $controller = file_get_contents(ROOTPATH . 'app/Controllers/View/AssessmentController.php') ?: ''; $migration = file_get_contents(ROOTPATH . 'app/Database/Migrations/2026-09-10-000400_AddEducationCommitteeNoteToStudentAssessments.php') ?: ''; $this->assertStringContainsString('Education Committee Note', $view); $this->assertStringContainsString('name="education_committee_note"', $view); $this->assertStringContainsString('assessment-answer', $view); $this->assertStringContainsString('persistEducationCommitteeNote', $controller); $this->assertStringContainsString("addColumn('student_assessments'", $migration); $this->assertStringContainsString('name="education_committee_note"', $review); $this->assertStringContainsString('name="education_committee_note"', $results); $this->assertStringContainsString("attempts/(:num)/note", $routes); $this->assertStringContainsString('saveAdminNote', $controller); $this->assertStringContainsString('saves automatically', $review); } public function testSchoolYearBelongsOnlyToAssessmentForms(): void { $migration = file_get_contents(ROOTPATH . 'app/Database/Migrations/2026-09-10-000300_AddSchoolYearToAssessmentForms.php') ?: ''; $model = file_get_contents(ROOTPATH . 'app/Models/AssessmentFormModel.php') ?: ''; $controller = file_get_contents(ROOTPATH . 'app/Controllers/View/AssessmentController.php') ?: ''; $this->assertStringContainsString("addColumn('assessment_forms'", $migration); $this->assertStringNotContainsString("addColumn('student_assessments'", $migration); $this->assertStringNotContainsString("addColumn('student_answers'", $migration); $this->assertStringContainsString("'school_year'", $model); $this->assertStringContainsString("where('f.school_year', \$schoolYear)", $controller); } public function testAssessmentsAreQualitativeAndHaveNoPointControls(): void { $pool = file_get_contents(ROOTPATH . 'app/Views/assessments/pool.php') ?: ''; $take = file_get_contents(ROOTPATH . 'app/Views/assessments/take.php') ?: ''; $review = file_get_contents(ROOTPATH . 'app/Views/assessments/grade.php') ?: ''; $results = file_get_contents(ROOTPATH . 'app/Views/assessments/results.php') ?: ''; $this->assertStringNotContainsString('name="points"', $pool); $this->assertStringNotContainsString('total points', $take); $this->assertStringNotContainsString('points_awarded', $review); $this->assertStringNotContainsString('is_correct', $review); $this->assertStringNotContainsString("assessment['score']", $results); $this->assertStringContainsString('Complete Review', $review); } public function testAssessmentResultsProvideReturnNavigation(): void { $results = file_get_contents(ROOTPATH . 'app/Views/assessments/results.php') ?: ''; $this->assertStringContainsString('Back to Students', $results); $this->assertStringContainsString("site_url('administrator/assessments/students')", $results); $this->assertStringContainsString('Back to My Assessments', $results); } public function testAssessmentLandingPageIncludesAdminGuide(): void { $forms = file_get_contents(ROOTPATH . 'app/Views/assessments/forms.php') ?: ''; $this->assertStringContainsString('How to use assessments', $forms); foreach (['Questions', 'Create', 'Assess', 'Complete', 'Review'] as $step) { $this->assertStringContainsString("{$step}", $forms); } $this->assertStringContainsString('Assessments are not scored.', $forms); } }