Files
alrahma_sunday_school/tests/app/Controllers/Api/PreferencesControllerTest.php
T
2026-02-10 22:11:06 -05:00

251 lines
7.6 KiB
PHP

<?php
namespace Tests\App\Controllers\Api;
use App\Controllers\Api\PreferencesController;
use CodeIgniter\HTTP\URI;
use CodeIgniter\HTTP\UserAgent;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\Mock\MockIncomingRequest;
use Config\App;
use Config\Services;
class StubPreferencesModel
{
private ?array $firstResult = null;
private array $findResults = [];
private int $nextInsertId = 200;
public ?array $lastUpdate = null;
public ?array $lastInsertData = null;
public function where(string $column, $value): self
{
return $this;
}
public function first(): ?array
{
return $this->firstResult;
}
public function setFirstResult(?array $result): void
{
$this->firstResult = $result;
}
public function update(int $id, array $data): bool
{
$this->lastUpdate = ['id' => $id, 'data' => $data];
$this->findResults[$id] = ['id' => $id] + $data;
return true;
}
public function insert(array $data): int
{
$id = $this->nextInsertId++;
$this->lastInsertData = $data;
$this->findResults[$id] = ['id' => $id] + $data;
return $id;
}
public function find(int $id): ?array
{
return $this->findResults[$id] ?? null;
}
public function setFindResult(int $id, array $result): void
{
$this->findResults[$id] = $result;
}
}
class FakeJsonRequest extends MockIncomingRequest
{
public function __construct(private readonly ?array $payload)
{
parent::__construct(config(App::class), new URI('https://test.alrahmaisgl.org'), null, new UserAgent());
}
public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0): ?array
{
return $this->payload;
}
}
class TestablePreferencesController extends PreferencesController
{
private ?object $currentUser = null;
public function __construct()
{
// Skip the real constructor to avoid bootstrapping models.
}
public function setPreferencesModel(StubPreferencesModel $model): void
{
$this->preferencesModel = $model;
}
public function setCurrentUser(?object $user): void
{
$this->currentUser = $user;
}
protected function getCurrentUser(): ?object
{
return $this->currentUser;
}
}
class PreferencesControllerTest extends CIUnitTestCase
{
private TestablePreferencesController $controller;
private StubPreferencesModel $preferencesModel;
protected function setUp(): void
{
parent::setUp();
Services::resetSingle('validation');
Services::resetSingle('session');
$this->preferencesModel = new StubPreferencesModel();
$this->controller = new TestablePreferencesController();
$this->controller->setPreferencesModel($this->preferencesModel);
}
public function testIndexRequiresAuthentication()
{
$this->controller->setCurrentUser(null);
$response = $this->controller->index();
$this->assertFalse($response['status']);
$this->assertSame(401, $response['code']);
$this->assertSame('Authentication required', $response['message']);
}
public function testIndexReturnsDefaultsIfNoPreferences()
{
$this->controller->setCurrentUser((object) ['id' => 7]);
$this->preferencesModel->setFirstResult(null);
$response = $this->controller->index();
$this->assertTrue($response['status']);
$this->assertSame('Preferences retrieved successfully', $response['message']);
$this->assertSame(1, $response['data']['notification_email']);
$this->assertSame('light', $response['data']['theme']);
$this->assertSame('blue', $response['data']['style_color']);
$this->assertSame('white', $response['data']['menu_color']);
}
public function testIndexPropagatesStoredPreferencesAndSessionStyles()
{
$this->controller->setCurrentUser((object) ['id' => 9]);
$this->preferencesModel->setFirstResult([
'id' => 11,
'user_id' => 9,
'notification_email' => 0,
'notification_sms' => 0,
'theme' => 'dark',
'language' => 'fr',
]);
session()->set('style_color', 'rose');
session()->set('menu_color', 'navy');
$response = $this->controller->index();
$this->assertTrue($response['status']);
$this->assertSame(0, $response['data']['notification_email']);
$this->assertSame('rose', $response['data']['style_color']);
$this->assertSame('navy', $response['data']['menu_color']);
}
public function testUpdateReturnsValidationErrors()
{
$this->controller->setCurrentUser((object) ['id' => 3]);
$this->setRequestPayload(['notification_email' => '2']);
$response = $this->controller->update();
$this->assertFalse($response['status']);
$this->assertSame(422, $response['code']);
$this->assertSame('Validation failed', $response['message']);
$this->assertArrayHasKey('errors', $response);
}
public function testUpdateInsertsWhenPreferencesAbsent()
{
$this->controller->setCurrentUser((object) ['id' => 12]);
$this->preferencesModel->setFirstResult(null);
$payload = [
'notification_email' => 0,
'notification_sms' => 1,
'theme' => 'dark',
'language' => 'es',
'style_color' => 'green',
'menu_color' => 'brand',
];
$this->setRequestPayload($payload);
$response = $this->controller->update();
$this->assertTrue($response['status']);
$this->assertSame('Preferences updated successfully', $response['message']);
$this->assertSame(0, $response['data']['notification_email']);
$this->assertSame('green', session()->get('style_color'));
$this->assertSame('brand', session()->get('menu_color'));
$this->assertSame($this->preferencesModel->lastInsertData, [
'user_id' => 12,
'notification_email' => 0,
'notification_sms' => 1,
'theme' => 'dark',
'language' => 'es',
]);
}
public function testUpdateModifiesExistingPreferences()
{
$this->controller->setCurrentUser((object) ['id' => 21]);
$this->preferencesModel->setFirstResult([
'id' => 18,
'user_id' => 21,
'notification_email' => 1,
'notification_sms' => 1,
'theme' => 'light',
'language' => 'en',
]);
$this->preferencesModel->setFindResult(18, [
'id' => 18,
'user_id' => 21,
'notification_email' => 1,
'notification_sms' => 1,
'theme' => 'light',
'language' => 'en',
]);
$payload = ['notification_email' => 1, 'notification_sms' => 0, 'language' => 'fr'];
$this->setRequestPayload($payload);
$response = $this->controller->update();
$this->assertTrue($response['status']);
$this->assertSame('Preferences updated successfully', $response['message']);
$this->assertSame(1, $this->preferencesModel->lastUpdate['data']['notification_email']);
$this->assertSame(0, $this->preferencesModel->lastUpdate['data']['notification_sms']);
$this->assertSame(18, $this->preferencesModel->lastUpdate['id']);
$this->assertSame('fr', $response['data']['language']);
}
private function setRequestPayload(?array $payload): void
{
$request = new FakeJsonRequest($payload);
$this->controller->setRequest($request);
}
}