nhance/tests/unit/Api/CreateClaimTest.php
2026-03-31 12:04:35 +05:30

298 lines
11 KiB
PHP

<?php
namespace Tests\unit\Api;
use CodeIgniter\Test\CIUnitTestCase;
use App\Controllers\Api\NonEbClaimApiController;
/**
* Unit tests for NonEbClaimApiController::createClaim()
*
* Auth is controlled by overriding getAuthUser() in an anonymous subclass.
* Model dependencies are stubbed via ReflectionClass property injection.
*/
class CreateClaimTest extends CIUnitTestCase
{
// ─── Helpers ────────────────────────────────────────────────────────────
/**
* Build a controller subclass where getAuthUser() returns $user (or null).
*/
protected function makeController(?array $user = null): NonEbClaimApiController
{
$mockUser = $user;
$controller = new class($mockUser) extends NonEbClaimApiController {
private ?array $_mockUser;
public function __construct(?array $mockUser)
{
$this->_mockUser = $mockUser;
}
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 minimal fluent stub model that returns $returnValue on ->first().
* Unknown chained method calls return $this (fluent builder pattern).
*/
protected function makeFluentStub(mixed $returnValue): object
{
return new class($returnValue) {
private mixed $rv;
private array $inserts = [];
public function __construct(mixed $rv) { $this->rv = $rv; }
public function __call(string $name, array $args): mixed
{
if ($name === 'first') return $this->rv;
if ($name === 'findAll') return is_array($this->rv) ? $this->rv : [$this->rv];
if ($name === 'insert') { $this->inserts[] = $args[0] ?? []; return 99; }
if ($name === 'insertID') return 99;
return $this; // fluent chain
}
public function getInserts(): array { return $this->inserts; }
};
}
/**
* Inject a stub into a named property of the controller.
*/
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);
}
/** Decode response body to array. */
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->createClaim();
$this->assertSame(401, $resp->getStatusCode());
$body = $this->body($resp);
print_r($body);
$this->assertFalse($body['status']);
$this->assertSame(401, $body['code']);
}
public function testReturns400WhenRequiredFieldsMissing(): void
{
$_POST = []; // empty body — all required fields missing
$ctrl = $this->makeController(['id' => 1, 'name' => 'Test', 'email' => 't@t.com', 'mobile' => '9999']);
$resp = $ctrl->createClaim();
$this->assertSame(400, $resp->getStatusCode());
$body = $this->body($resp);
print_r($body);
$this->assertFalse($body['status']);
$this->assertSame(400, $body['code']);
$this->assertArrayHasKey('errors', $body);
$this->assertArrayHasKey('nature_of_loss', $body['errors']);
}
public function testReturns404WhenClientPolicyNotFound(): void
{
$_POST = [
'client_policy_id' => 8101,
'nature_of_loss' => 'Fire damage',
'loss_location' => 'Chennai',
'loss_date' => '22-03-2026',
];
$ctrl = $this->makeController(['id' => 1, 'name' => 'User', 'email' => 'u@t.com', 'mobile' => '999']);
// clientPolicyModel returns null — policy not found
$this->inject($ctrl, 'clientPolicyModel', $this->makeFluentStub(null));
$resp = $ctrl->createClaim();
$this->assertSame(404, $resp->getStatusCode());
$body = $this->body($resp);
print_r($body);
$this->assertFalse($body['status']);
$this->assertSame(404, $body['code']);
$this->assertStringContainsString('policy', strtolower($body['message']));
}
public function testReturns422WhenPolicyTypeIsEB(): void
{
$_POST = [
'client_policy_id' => 10,
'nature_of_loss' => 'Theft',
'loss_location' => 'Mumbai',
'loss_date' => '01-03-2026',
];
$ctrl = $this->makeController(['id' => 1, 'name' => 'User', 'email' => 'u@t.com', 'mobile' => '999']);
$this->inject($ctrl, 'clientPolicyModel', $this->makeFluentStub([
'id' => 10,
'client_id' => 5,
'client_branch_id' => 2,
'policy_type_id' => 3,
'insurer_id' => 7,
'policy_no' => 'POL/2026/001',
]));
// policyTypeModel returns EB — should be rejected
$this->inject($ctrl, 'policyTypeModel', $this->makeFluentStub(['allocg' => 'EB']));
$resp = $ctrl->createClaim();
$this->assertSame(422, $resp->getStatusCode());
$body = $this->body($resp);
print_r($body);
$this->assertFalse($body['status']);
$this->assertSame(422, $body['code']);
}
public function testReturns422WhenNoClaimStatusConfigured(): void
{
$_POST = [
'client_policy_id' => 10,
'nature_of_loss' => 'Flood',
'loss_location' => 'Kochi',
'loss_date' => '05-03-2026',
];
$ctrl = $this->makeController(['id' => 1, 'name' => 'User', 'email' => 'u@t.com', 'mobile' => '999']);
$this->inject($ctrl, 'clientPolicyModel', $this->makeFluentStub([
'id' => 10,
'client_id' => 5,
'client_branch_id' => 2,
'policy_type_id' => 10,
'insurer_id' => 7,
'policy_no' => 'POL/2026/002',
]));
$this->inject($ctrl, 'policyTypeModel', $this->makeFluentStub(['allocg' => 'Non-EB']));
$this->inject($ctrl, 'clientRMModel', $this->makeFluentStub(['user_id' => 4]));
// claimStatusModel returns null — no status configured
$this->inject($ctrl, 'claimStatusModel', $this->makeFluentStub(null));
$resp = $ctrl->createClaim();
$this->assertSame(422, $resp->getStatusCode());
$body = $this->body($resp);
print_r($body);
$this->assertFalse($body['status']);
$this->assertStringContainsString('status', strtolower($body['message']));
}
public function testReturns409OnDuplicateClaim(): void
{
$_POST = [
'client_policy_id' => 8101,
'nature_of_loss' => 'Fire accident one edited two',
'loss_location' => 'bjdbkkjb',
'loss_date' => '01-03-2026',
];
$ctrl = $this->makeController(['id' => 1, 'name' => 'User', 'email' => 'u@t.com', 'mobile' => '999']);
$this->inject($ctrl, 'clientPolicyModel', $this->makeFluentStub([
'id' => 10,
'client_id' => 12,
'client_branch_id' => 2,
'policy_type_id' => 10,
'insurer_id' => 7,
'policy_no' => 'POL/2026/DUPJHBVJH',
]));
$this->inject($ctrl, 'policyTypeModel', $this->makeFluentStub(['allocg' => 'Non-EB']));
$this->inject($ctrl, 'clientRMModel', $this->makeFluentStub(['user_id' => 4]));
$this->inject($ctrl, 'claimStatusModel', $this->makeFluentStub(['id' => 1]));
// nonEbTicketModel->first() returns existing row => duplicate detected
$this->inject($ctrl, 'nonEbTicketModel', $this->makeFluentStub(['id' => 550]));
$resp = $ctrl->createClaim();
$this->assertSame(409, $resp->getStatusCode());
$body = $this->body($resp);
print_r($body);
$this->assertFalse($body['status']);
$this->assertSame(409, $body['code']);
$this->assertStringContainsString('Duplicate', $body['message']);
}
public function testReturns200AndClaimIdOnSuccess(): void
{
$_POST = [
'client_policy_id' => 10,
'nature_of_loss' => 'Storm damage',
'loss_location' => 'Hyderabad',
'loss_date' => '15-03-2026',
];
$ctrl = $this->makeController(['id' => 1, 'name' => 'Test User', 'email' => 'u@t.com', 'mobile' => '9876543210']);
$this->inject($ctrl, 'clientPolicyModel', $this->makeFluentStub([
'id' => 10,
'client_id' => 5,
'client_branch_id' => 2,
'policy_type_id' => 10,
'insurer_id' => 7,
'policy_no' => 'POL/2026/STR',
]));
$this->inject($ctrl, 'policyTypeModel', $this->makeFluentStub(['allocg' => 'Marine']));
$this->inject($ctrl, 'clientRMModel', $this->makeFluentStub(['user_id' => 4]));
$this->inject($ctrl, 'claimStatusModel', $this->makeFluentStub(['id' => 1]));
// nonEbTicketModel: first() returns null (no duplicate), insert() returns 99
$ticketStub = new class {
private int $callCount = 0;
public function __call(string $name, array $args): mixed
{
if ($name === 'first') return null; // no duplicate
if ($name === 'insert') return 99;
if ($name === 'insertID') return 99;
return $this;
}
};
$this->inject($ctrl, 'nonEbTicketModel', $ticketStub);
// Provide pass-through stubs for asset and history models
$noopStub = new class {
public function __call(string $n, array $a): mixed { return $this; }
};
$this->inject($ctrl, 'assetModel', $noopStub);
$this->inject($ctrl, 'ticketHistoryModel', $noopStub);
$resp = $ctrl->createClaim();
$this->assertSame(200, $resp->getStatusCode());
$body = $this->body($resp);
print_r($body);
$this->assertTrue($body['status']);
$this->assertSame(200, $body['code']);
$this->assertSame(99, $body['claim_id']);
$this->assertStringContainsString('created', strtolower($body['message']));
}
}