258 lines
7.3 KiB
PHP
258 lines
7.3 KiB
PHP
<?php
|
|
|
|
namespace {
|
|
if (!function_exists('view')) {
|
|
function view($name, array $data = [], $options = [])
|
|
{
|
|
return ['view' => $name, 'data' => $data, 'options' => $options];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('local_date')) {
|
|
function local_date($timestamp, $format)
|
|
{
|
|
if ($timestamp instanceof \DateTimeInterface) {
|
|
return $timestamp->format($format);
|
|
}
|
|
if (is_numeric($timestamp)) {
|
|
return date($format, (int) $timestamp);
|
|
}
|
|
return date($format);
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace Tests\App\Controllers\View {
|
|
|
|
use App\Controllers\View\AdministratorController;
|
|
use App\Models\UserModel;
|
|
use CodeIgniter\HTTP\RedirectResponse;
|
|
use CodeIgniter\Test\CIUnitTestCase;
|
|
use Config\Services;
|
|
|
|
class DummyPostRequest
|
|
{
|
|
public function __construct(private array $post = [])
|
|
{
|
|
}
|
|
|
|
public function getPost($key = null)
|
|
{
|
|
if ($key === null) {
|
|
return $this->post;
|
|
}
|
|
return $this->post[$key] ?? null;
|
|
}
|
|
}
|
|
|
|
class FakeRenderer
|
|
{
|
|
public array $lastData = [];
|
|
public string $lastName = '';
|
|
|
|
public function setData(array $data, string $type = 'raw')
|
|
{
|
|
$this->lastData = $data;
|
|
return $this;
|
|
}
|
|
|
|
public function render(string $name, array $options = [], bool $saveData = false)
|
|
{
|
|
$this->lastName = $name;
|
|
return 'fake-render';
|
|
}
|
|
}
|
|
|
|
class FakeAttendanceModel
|
|
{
|
|
public function __construct(private array $existing = [])
|
|
{
|
|
}
|
|
|
|
public function where(...$args)
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function orderBy(...$args)
|
|
{
|
|
return $this;
|
|
}
|
|
|
|
public function findAll()
|
|
{
|
|
return $this->existing;
|
|
}
|
|
|
|
public function upsertOne(...$args)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
class TestableAdministratorController extends AdministratorController
|
|
{
|
|
public function __construct()
|
|
{
|
|
// Skip expensive parent constructor to avoid real DB/models.
|
|
}
|
|
|
|
public function setUserModel(UserModel $model): self
|
|
{
|
|
$this->userModel = $model;
|
|
return $this;
|
|
}
|
|
|
|
public function setStaffAttendanceModel($model): self
|
|
{
|
|
$this->staffAttendanceModel = $model;
|
|
return $this;
|
|
}
|
|
|
|
public function setSemester(string $semester): self
|
|
{
|
|
$this->semester = $semester;
|
|
return $this;
|
|
}
|
|
|
|
public function setSchoolYear(string $schoolYear): self
|
|
{
|
|
$this->schoolYear = $schoolYear;
|
|
return $this;
|
|
}
|
|
|
|
public function setRequest($request): self
|
|
{
|
|
$this->request = $request;
|
|
return $this;
|
|
}
|
|
}
|
|
|
|
class AdministratorControllerTest extends CIUnitTestCase
|
|
{
|
|
private TestableAdministratorController $controller;
|
|
private FakeRenderer $renderer;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
Services::resetSingle('session');
|
|
helper('date');
|
|
session()->start();
|
|
|
|
$this->controller = new TestableAdministratorController();
|
|
$this->controller->setSemester('Fall')->setSchoolYear('2024-2025');
|
|
$this->renderer = new FakeRenderer();
|
|
Services::injectMock('renderer', $this->renderer);
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
session()->destroy();
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function testAbsenceFormRedirectsWhenNotLoggedIn()
|
|
{
|
|
session()->remove('user_id');
|
|
|
|
$response = $this->controller->absenceFormAdmin();
|
|
|
|
$this->assertInstanceOf(RedirectResponse::class, $response);
|
|
$this->assertStringContainsString('/login', $response->getHeaderLine('Location') ?: '');
|
|
}
|
|
|
|
public function testAbsenceFormBuildsViewWithAttendance()
|
|
{
|
|
session()->set('user_id', 7);
|
|
|
|
$userModel = $this->createMock(UserModel::class);
|
|
$userModel->method('find')->with(7)->willReturn([
|
|
'firstname' => 'Alex',
|
|
'lastname' => 'Admin',
|
|
]);
|
|
|
|
$attendance = new FakeAttendanceModel([
|
|
['date' => '2024-12-01'],
|
|
]);
|
|
|
|
$this->controller->setUserModel($userModel)->setStaffAttendanceModel($attendance);
|
|
|
|
$result = $this->controller->absenceFormAdmin();
|
|
|
|
$this->assertSame('fake-render', $result);
|
|
$this->assertSame('administrator/absence_vacation', $this->renderer->lastName);
|
|
$data = $this->renderer->lastData;
|
|
$this->assertSame('Alex Admin', $data['admin_name']);
|
|
$this->assertSame('Fall', $data['semester']);
|
|
$this->assertSame('2024-2025', $data['schoolYear']);
|
|
$this->assertSame([['date' => '2024-12-01']], $data['existing']);
|
|
$this->assertIsArray($data['availableDates']);
|
|
}
|
|
|
|
public function testSubmitAbsenceRejectsMissingReason()
|
|
{
|
|
session()->set('user_id', 9);
|
|
|
|
$req = new DummyPostRequest([
|
|
'dates' => ['2024-12-01'],
|
|
'reason_type' => '',
|
|
'reason' => '',
|
|
]);
|
|
|
|
$this->controller->setRequest($req);
|
|
|
|
$response = $this->controller->submitAbsenceAdmin();
|
|
|
|
$this->assertInstanceOf(RedirectResponse::class, $response);
|
|
$this->assertStringContainsString('/administrator/absence', $response->getHeaderLine('Location') ?: '');
|
|
$this->assertSame('Reason is required.', session()->getFlashdata('message'));
|
|
}
|
|
|
|
public function testSubmitAbsenceSavesAndRedirects()
|
|
{
|
|
session()->set('user_id', 10);
|
|
|
|
$userModel = $this->createMock(UserModel::class);
|
|
$userModel->method('getUserRole')->with(10)->willReturn('administrator');
|
|
$userModel->method('find')->with(10)->willReturn([
|
|
'firstname' => 'Sam',
|
|
'lastname' => 'Admin',
|
|
'email' => 'sam@school.test',
|
|
]);
|
|
|
|
$attendance = new FakeAttendanceModel();
|
|
$this->controller->setUserModel($userModel)->setStaffAttendanceModel($attendance);
|
|
|
|
$method = new \ReflectionMethod($this->controller, 'allowedAbsenceDates');
|
|
$method->setAccessible(true);
|
|
$allowed = $method->invoke($this->controller);
|
|
|
|
if (empty($allowed)) {
|
|
$this->markTestSkipped('No allowed absence dates are currently available.');
|
|
}
|
|
|
|
$date = $allowed[0];
|
|
|
|
$req = new DummyPostRequest([
|
|
'dates' => [$date],
|
|
'reason_type' => 'Personal',
|
|
'reason' => 'Conference',
|
|
]);
|
|
$this->controller->setRequest($req);
|
|
|
|
$emailService = $this->createMock(\App\Services\EmailService::class);
|
|
$emailService->method('send')->willReturn(true);
|
|
Services::injectMock('emailService', $emailService);
|
|
|
|
$response = $this->controller->submitAbsenceAdmin();
|
|
|
|
$this->assertInstanceOf(RedirectResponse::class, $response);
|
|
$this->assertStringContainsString('/administrator/absence', $response->getHeaderLine('Location') ?: '');
|
|
$this->assertSame('success', session()->getFlashdata('status'));
|
|
$this->assertStringContainsString('saved', (string) session()->getFlashdata('message'));
|
|
}
|
|
}
|
|
}
|