_mockUser = $u; } protected function getAuthUser(): ?array { return $this->_mockUser; } }; $request = \Config\Services::request(); $response = \Config\Services::response(); $logger = \Config\Services::logger(); $controller->initController($request, $response, $logger); return $controller; } /** * Build a fluent stub model. * $firstReturn → returned by ->first() * $allReturn → returned by ->findAll() */ protected function makeFluentStub(mixed $firstReturn, array $allReturn = []): object { return new class($firstReturn, $allReturn) { private mixed $fr; private array $ar; public function __construct(mixed $fr, array $ar) { $this->fr = $fr; $this->ar = $ar; } public function __call(string $name, array $args): mixed { if ($name === 'first') return $this->fr; if ($name === 'findAll') return $this->ar; return $this; } }; } protected function inject(NonEbClaimApiController $ctrl, string $property, object $stub): void { $ref = new \ReflectionClass($ctrl); $prop = $ref->getProperty($property); $prop->setAccessible(true); $prop->setValue($ctrl, $stub); } protected function body(\CodeIgniter\HTTP\ResponseInterface $resp): array { return json_decode($resp->getBody(), true); } // ─── Tests ────────────────────────────────────────────────────────────── public function testReturns401WhenNoAuth(): void { $ctrl = $this->makeController(null); $resp = $ctrl->claimHistory(1); $this->assertSame(401, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertFalse($body['status']); $this->assertSame(401, $body['code']); } public function testReturns404WhenClaimNotFound(): void { $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); // nonEbTicketModel->first() returns null — claim not found $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub(null)); $resp = $ctrl->claimHistory(999); $this->assertSame(404, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertFalse($body['status']); $this->assertSame(404, $body['code']); $this->assertStringContainsString('not found', strtolower($body['message'])); } public function testReturnsEmptyHistoryWhenNoHistoryRows(): void { $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub([ 'id' => 10, 'client_id' => 5, 'policy_type_id' => 10, ])); // ticketHistoryModel returns no rows $this->inject($ctrl, 'ticketHistoryModel', $this->makeFluentStub(null, [])); $resp = $ctrl->claimHistory(10); $this->assertSame(200, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertTrue($body['status']); $this->assertSame(10, $body['claim_id']); $this->assertIsArray($body['history']); $this->assertEmpty($body['history']); } public function testFiltersOutStatusesWithNoDisplayName(): void { $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub([ 'id' => 10, 'client_id' => 5, 'policy_type_id' => 10, ])); // History rows: status IDs 1, 2, 3 $historyRows = [ ['new_value' => '1', 'created_at' => '2026-03-22 10:00:00'], ['new_value' => '2', 'created_at' => '2026-03-23 11:00:00'], ['new_value' => '3', 'created_at' => '2026-03-24 12:00:00'], ]; // display_map: only status 1 and 3 have display_name; status 2 is internal $statusRows = [ ['id' => 1, 'claim_status' => 'Internal-A', 'display_name' => 'Claim Intimation'], ['id' => 3, 'claim_status' => 'Internal-C', 'display_name' => 'Under Process'], ]; // ticketHistoryModel findAll() returns history rows $histStub = new class($historyRows) { private array $rows; public function __construct(array $rows) { $this->rows = $rows; } public function __call(string $n, array $a): mixed { if ($n === 'findAll') return $this->rows; if ($n === 'first') return $this->rows[0] ?? null; return $this; } }; // claimStatusModel findAll() returns status rows $statusStub = new class($statusRows) { private array $rows; public function __construct(array $rows) { $this->rows = $rows; } public function __call(string $n, array $a): mixed { if ($n === 'findAll') return $this->rows; if ($n === 'first') return $this->rows[0] ?? null; return $this; } }; $this->inject($ctrl, 'ticketHistoryModel', $histStub); $this->inject($ctrl, 'claimStatusModel', $statusStub); $resp = $ctrl->claimHistory(10); $this->assertSame(200, $resp->getStatusCode()); $body = $this->body($resp); print_r($body); $this->assertTrue($body['status']); $this->assertCount(2, $body['history']); // Status 2 (no display_name) must not appear $statuses = array_column($body['history'], 'status'); $this->assertContains('Claim Intimation', $statuses); $this->assertContains('Under Process', $statuses); $this->assertNotContains('Internal-B', $statuses); } public function testHistoryIsReturnedOldestFirst(): void { $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub([ 'id' => 10, 'client_id' => 5, 'policy_type_id' => 10, ])); $historyRows = [ ['new_value' => '1', 'created_at' => '2026-03-22 10:00:00'], ['new_value' => '2', 'created_at' => '2026-03-25 14:00:00'], ]; $statusRows = [ ['id' => 1, 'claim_status' => 'A', 'display_name' => 'Claim Intimation'], ['id' => 2, 'claim_status' => 'B', 'display_name' => 'Under Process'], ]; $histStub = new class($historyRows) { private array $rows; public function __construct(array $rows) { $this->rows = $rows; } public function __call(string $n, array $a): mixed { if ($n === 'findAll') return $this->rows; return $this; } }; $statusStub = new class($statusRows) { private array $rows; public function __construct(array $rows) { $this->rows = $rows; } public function __call(string $n, array $a): mixed { if ($n === 'findAll') return $this->rows; return $this; } }; $this->inject($ctrl, 'ticketHistoryModel', $histStub); $this->inject($ctrl, 'claimStatusModel', $statusStub); $resp = $ctrl->claimHistory(10); $body = $this->body($resp); print_r($body); $this->assertCount(2, $body['history']); $this->assertSame('Claim Intimation', $body['history'][0]['status']); $this->assertSame('Under Process', $body['history'][1]['status']); } public function testHistoryItemHasRequiredKeys(): void { $ctrl = $this->makeController(['id' => 1, 'name' => 'U', 'email' => 'u@t.com', 'mobile' => '9']); $this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub([ 'id' => 10, 'client_id' => 5, 'policy_type_id' => 10, ])); $historyRows = [ ['new_value' => '1', 'created_at' => '2026-03-22 10:15:00'], ]; $statusRows = [ ['id' => 1, 'claim_status' => 'A', 'display_name' => 'Claim Settled'], ]; $histStub = new class($historyRows) { private array $rows; public function __construct(array $rows) { $this->rows = $rows; } public function __call(string $n, array $a): mixed { if ($n === 'findAll') return $this->rows; return $this; } }; $statusStub = new class($statusRows) { private array $rows; public function __construct(array $rows) { $this->rows = $rows; } public function __call(string $n, array $a): mixed { if ($n === 'findAll') return $this->rows; return $this; } }; $this->inject($ctrl, 'ticketHistoryModel', $histStub); $this->inject($ctrl, 'claimStatusModel', $statusStub); $resp = $ctrl->claimHistory(10); $body = $this->body($resp); print_r($body); $item = $body['history'][0]; $this->assertArrayHasKey('status', $item); $this->assertArrayHasKey('changed_at', $item); $this->assertArrayNotHasKey('modified_by', $item); // must not expose who changed it } }