Files
2026-02-10 22:11:06 -05:00

305 lines
12 KiB
PHP

<?php
namespace Tests\App\Controllers\Api;
use App\Controllers\Api\AdministratorController;
use CodeIgniter\Test\CIUnitTestCase;
use Config\Services;
class AdministratorControllerTest extends CIUnitTestCase
{
protected $controller;
protected function setUp(): void
{
parent::setUp();
// ✅ Create a fake database connection object
$fakeDb = $this->createMock(\CodeIgniter\Database\BaseConnection::class);
// ✅ Stub Config\Database::connect() globally using class_alias
// so CodeIgniter's static Database::connect() returns our fake DB
if (!class_exists('Config\\FakeDatabase')) {
eval('namespace Config; class FakeDatabase extends \\Config\\Database {
public static function connect($group = null, bool $getShared = true) {
return $GLOBALS["__fakeDb__"];
}
}');
}
$GLOBALS['__fakeDb__'] = $fakeDb;
// Temporarily alias Config\Database to our FakeDatabase
class_alias('Config\\FakeDatabase', 'Config\\Database');
// ✅ Mock all required models/services
foreach ([
\App\Models\UserModel::class,
\App\Models\StudentModel::class,
\App\Models\ConfigurationModel::class,
\App\Models\LoginActivityModel::class,
\App\Models\EnrollmentModel::class,
\App\Models\RefundModel::class,
\App\Models\InvoiceModel::class,
\App\Models\ClassSectionModel::class,
\App\Models\UserRoleModel::class,
\App\Models\StudentClassModel::class,
\App\Models\StaffAttendanceModel::class,
\App\Services\FeeCalculationService::class,
] as $class) {
$this->mockModel($class);
}
// ✅ Configuration mock
$configMock = $this->mockModel(\App\Models\ConfigurationModel::class);
$configMock->method('getConfig')->willReturnMap([
['school_year', '2024-2025'],
['semester', 'Fall'],
]);
// ✅ Instantiate controller safely (no DB hit)
$this->controller = new AdministratorController();
}
protected function mockModel(string $class)
{
$mock = $this->createMock($class);
Services::injectMock($class, $mock);
return $mock;
}
/** @test */
public function testDashboardSuccess()
{
$result = $this->controller->dashboard();
$this->assertNotNull($result);
}
/* --------------------------------------------------------------------------
* absenceInfo()
* -------------------------------------------------------------------------- */
public function testAbsenceInfoWithValidUser()
{
helper('date');
$this->controller->setSession(['user_id' => 7]);
$userMock = model(UserModel::class);
$staffMock = model(StaffAttendanceModel::class);
$userMock->method('find')->willReturn(['firstname' => 'Jane', 'lastname' => 'Admin']);
$staffMock->method('where')->willReturnSelf();
$staffMock->method('orderBy')->willReturnSelf();
$staffMock->method('findAll')->willReturn([
['date' => '2025-09-14', 'status' => 'present'],
]);
$response = $this->controller->absenceInfo();
$this->assertTrue($response['status']);
$this->assertArrayHasKey('available_dates', $response['data']);
}
public function testAbsenceInfoUnauthorized()
{
$this->controller->setSession([]); // no user
$response = $this->controller->absenceInfo();
$this->assertFalse($response['status']);
$this->assertEquals(401, $response['code']);
}
/* --------------------------------------------------------------------------
* submitAbsence()
* -------------------------------------------------------------------------- */
public function testSubmitAbsenceRejectsMissingReason()
{
$this->controller->setSession(['user_id' => 2]);
$req = $this->makeRequest('POST', '/api/v1/administrator/absence', [
'dates' => ['2025-10-05'],
'reason' => '',
]);
$this->controller->setRequest($req);
$resp = $this->controller->submitAbsence();
$this->assertFalse($resp['status']);
$this->assertEquals('Reason is required', $resp['message']);
}
public function testSubmitAbsenceValidDateAndReason()
{
$this->controller->setSession(['user_id' => 5]);
$req = $this->makeRequest('POST', '/api/v1/administrator/absence', [
'dates' => ['2025-09-07'],
'reason_type' => 'Personal',
'reason' => 'Travel',
]);
$this->controller->setRequest($req);
$staffMock = model(StaffAttendanceModel::class);
$userMock = model(UserModel::class);
$userMock->method('getUserRole')->willReturn('admin');
$staffMock->method('upsertOne')->willReturn(true);
$userMock->method('find')->willReturn(['firstname' => 'Sarah', 'lastname' => 'Ali', 'email' => 's@a.com']);
$email = Services::email();
$email->clear();
$resp = $this->controller->submitAbsence();
$this->assertTrue($resp['status']);
$this->assertArrayHasKey('saved_dates', $resp['data']);
}
/* --------------------------------------------------------------------------
* search()
* -------------------------------------------------------------------------- */
public function testSearchRequiresQueryParam()
{
$this->controller->setRequest($this->makeRequest('GET', '/api/v1/administrator/search?q='));
$resp = $this->controller->search();
$this->assertFalse($resp['status']);
$this->assertEquals('Search query is required', $resp['message']);
}
public function testSearchReturnsStructuredResults()
{
$this->controller->setRequest($this->makeRequest('GET', '/api/v1/administrator/search?q=john'));
$db = $this->createMock(\CodeIgniter\Database\BaseConnection::class);
$builder = $this->createMock(\CodeIgniter\Database\BaseBuilder::class);
$builder->method('select')->willReturnSelf();
$builder->method('limit')->willReturnSelf();
$builder->method('get')->willReturnSelf();
$builder->method('getResultArray')->willReturn([
['id' => 1, 'firstname' => 'John', 'lastname' => 'Doe'],
]);
$db->method('table')->willReturn($builder);
service('database')->shouldReceive('connect')->andReturn($db);
$resp = $this->controller->search();
$this->assertTrue($resp['status']);
$this->assertArrayHasKey('users', $resp['data']);
}
/* --------------------------------------------------------------------------
* enrollmentWithdrawal()
* -------------------------------------------------------------------------- */
public function testEnrollmentWithdrawalPagination()
{
$mock = model(EnrollmentModel::class);
$mock->method('where')->willReturnSelf();
$mock->method('orderBy')->willReturnSelf();
$mock->method('findAll')->willReturn([
['student_id' => 1, 'status' => 'enrolled'],
]);
$resp = $this->controller->enrollmentWithdrawal();
$this->assertTrue($resp['status']);
$this->assertEquals('Enrollment/withdrawal data retrieved successfully', $resp['message']);
}
/* --------------------------------------------------------------------------
* enrollmentWithdrawalData()
* -------------------------------------------------------------------------- */
public function testEnrollmentWithdrawalDataBuildsStudentList()
{
$stuMock = model(StudentModel::class);
$stuMock->method('getStudentsWithClassAndEnrollment')->willReturn([
['id' => 1, 'firstname' => 'A', 'lastname' => 'Z', 'parent_id' => 10],
]);
$clsMock = model(ClassSectionModel::class);
$clsMock->method('select')->willReturnSelf();
$clsMock->method('where')->willReturnSelf();
$clsMock->method('orderBy')->willReturnSelf();
$clsMock->method('findAll')->willReturn([
['id' => 1, 'class_section_name' => 'KG1'],
]);
$enrollMock = model(EnrollmentModel::class);
$enrollMock->method('getEnrollmentStatus')->willReturn('enrolled');
$resp = $this->controller->enrollmentWithdrawalData();
$this->assertTrue($resp['status']);
$this->assertArrayHasKey('students', $resp['data']);
$this->assertArrayHasKey('classes', $resp['data']);
}
/* --------------------------------------------------------------------------
* updateEnrollmentStatuses()
* -------------------------------------------------------------------------- */
public function testUpdateEnrollmentStatusesRejectsEmptyPayload()
{
$req = $this->makeRequest('POST', '/api/v1/administrator/enrollment-withdrawal/update', []);
$this->controller->setRequest($req);
$resp = $this->controller->updateEnrollmentStatuses();
$this->assertFalse($resp['status']);
$this->assertEquals('No enrollment statuses were submitted.', $resp['message']);
}
public function testUpdateEnrollmentStatusesWithValidStatus()
{
$req = $this->makeRequest('POST', '/api/v1/administrator/enrollment-withdrawal/update', [
'enrollment_status' => [1 => 'enrolled']
]);
$this->controller->setRequest($req);
$stuMock = model(StudentModel::class);
$stuMock->method('find')->willReturn(['id' => 1, 'parent_id' => 2]);
$enrollMock = model(EnrollmentModel::class);
$enrollMock->method('where')->willReturnSelf();
$enrollMock->method('get')->willReturnSelf();
$enrollMock->method('getRowArray')->willReturn(['enrollment_status' => 'payment pending', 'parent_id' => 2]);
$invoiceMock = model(InvoiceModel::class);
$invoiceMock->method('where')->willReturnSelf();
$invoiceMock->method('orderBy')->willReturnSelf();
$invoiceMock->method('first')->willReturn(['id' => 10, 'school_year' => '2024-2025']);
$refundMock = model(RefundModel::class);
$refundMock->method('where')->willReturnSelf();
$refundMock->method('first')->willReturn(null);
$resp = $this->controller->updateEnrollmentStatuses();
$this->assertTrue($resp['status']);
$this->assertArrayHasKey('groupsByParentStatus', $resp['data']);
}
/* --------------------------------------------------------------------------
* studentProfiles()
* -------------------------------------------------------------------------- */
public function testStudentProfilesReturnsList()
{
$studClassMock = model(StudentClassModel::class);
$studClassMock->method('getClassSectionNameByStudentId')->willReturn('KG2');
$resp = $this->controller->studentProfiles();
$this->assertTrue($resp['status']);
$this->assertArrayHasKey('students', $resp['data']);
}
/* --------------------------------------------------------------------------
* parentProfiles()
* -------------------------------------------------------------------------- */
public function testParentProfilesWithParentRole()
{
$userMock = model(UserModel::class);
$userMock->method('findAll')->willReturn([
['id' => 20, 'firstname' => 'Layla', 'lastname' => 'Yusuf', 'email' => 'layla@test.com', 'cellphone' => '123', 'school_id' => 'P1'],
]);
$roleMock = model(UserRoleModel::class);
$roleMock->method('getRolesByUserId')->willReturn([
['role_name' => 'parent'],
]);
$invMock = model(InvoiceModel::class);
$invMock->method('getLatestInvoicePaidAmount')->willReturn(150.00);
$invMock->method('getLatestInvoiceBalance')->willReturn(50.00);
$resp = $this->controller->parentProfiles();
$this->assertTrue($resp['status']);
$this->assertArrayHasKey('parents', $resp['data']);
$this->assertEquals('Layla', $resp['data']['parents'][0]['firstname']);
}
}