add assessment feature
Deploy to Shared Hosting / Shared hosting deploy (push) Failing after 49s
Tests / PHPUnit (push) Successful in 1m36s

This commit is contained in:
root
2026-09-10 06:44:24 -04:00
parent ac19226bf0
commit b5e719382d
31 changed files with 1712 additions and 65 deletions
@@ -0,0 +1,144 @@
<?php
namespace Tests\App\Config;
use CodeIgniter\Test\CIUnitTestCase;
final class AssessmentFeatureIntegrityTest extends CIUnitTestCase
{
public function testAssessmentRoutesAreExplicitAndRoleProtected(): void
{
$routes = file_get_contents(ROOTPATH . 'app/Config/Routes.php') ?: '';
$this->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);
}
}