Update Patient Unit Testing

This commit is contained in:
mikael-zakaria 2025-10-14 15:50:22 +07:00
parent b5939e1cc9
commit f33cd6cc7b
8 changed files with 551 additions and 334 deletions

View File

@ -16,11 +16,13 @@ class Patient extends Controller {
$this->db = \Config\Database::connect(); $this->db = \Config\Database::connect();
$this->model = new PatientModel(); $this->model = new PatientModel();
$this->rules = [ $this->rules = [
'PatientID' => 'required|max_length[50]', 'PatientID' => 'required|max_length[50]',
'AlternatePID' => 'permit_empty|max_length[50]', 'AlternatePID' => 'permit_empty|max_length[50]',
'NameFirst' => 'required|min_length[1]|max_length[255]', 'NameFirst' => 'required|min_length[1]|max_length[255]',
'EmailAddress1' => 'required', 'EmailAddress1' => 'required',
'Gender' => 'required' 'Gender' => 'required',
'Birthdate' => 'required',
"PatIdt.Identifier" => 'max_length[255]'
]; ];
} }
@ -80,7 +82,6 @@ class Patient extends Controller {
} }
} }
// Unit Testing Pass : \clqms-be\tests\feature\Patients\PatientDeleteTest.php
public function delete() { public function delete() {
try { try {
$input = $this->request->getJSON(true); $input = $this->request->getJSON(true);

View File

@ -113,15 +113,15 @@ class PatientModel extends BaseUtcModel {
public function createPatient($input) { public function createPatient($input) {
$db = \Config\Database::connect(); $db = \Config\Database::connect();
$patidt = $input['PatIdt'] ?? []; $patidt = $input['PatIdt'] ?? [];
$patatt = $input['PatAtt'] ?? []; $patatt = $input['PatAtt'] ?? [];
$patcom['Comment'] = $input['PatCom'] ?? null; $patcom['Comment'] = $input['PatCom'] ?? null;
$input['LinkTo'] = empty($input['LinkTo']) ? null : $input['LinkTo']; $input['LinkTo'] = empty($input['LinkTo']) ? null : $input['LinkTo'];
$input['Birthdate'] = $this->isValidDateTime($input['Birthdate']); $input['Birthdate'] = $this->isValidDateTime($input['Birthdate']);
$input['DeathDateTime'] = $this->isValidDateTime($input['DeathDateTime']); $input['DeathDateTime'] = $this->isValidDateTime($input['DeathDateTime']);
$db->transBegin();
try { try {
$db->transStart();
$this->insert($input); $this->insert($input);
$newInternalPID = $this->getInsertID(); $newInternalPID = $this->getInsertID();
@ -147,14 +147,15 @@ class PatientModel extends BaseUtcModel {
$this->checkDbError($db, 'Insert patatt'); $this->checkDbError($db, 'Insert patatt');
} }
$db->transComplete(); $db->transCommit();
if ($db->transStatus() === false) { // $db->transComplete();
throw new \Exception("Failed to sync patient relations"); // if ($db->transStatus() === false) {
} // throw new \Exception("Failed to sync patient relations");
// }
return $newInternalPID; return $newInternalPID;
} catch (\Exception $e) { } catch (\Exception $e) {
// $db->transRollback(); $db->transRollback();
throw $e; throw $e;
} }
} }
@ -168,8 +169,9 @@ class PatientModel extends BaseUtcModel {
$input['Birthdate'] = $this->isValidDateTime($input['Birthdate']); $input['Birthdate'] = $this->isValidDateTime($input['Birthdate']);
$input['DeathDateTime'] = $this->isValidDateTime($input['DeathDateTime']); $input['DeathDateTime'] = $this->isValidDateTime($input['DeathDateTime']);
$db->transBegin();
try { try {
$db->transStart();
$InternalPID = $input['InternalPID']; $InternalPID = $input['InternalPID'];
$this->where('InternalPID',$InternalPID)->set($input)->update(); $this->where('InternalPID',$InternalPID)->set($input)->update();
$this->checkDbError($db, 'Update patient'); $this->checkDbError($db, 'Update patient');
@ -269,23 +271,20 @@ class PatientModel extends BaseUtcModel {
$this->checkDbError($db, 'Update/Delete patatt'); $this->checkDbError($db, 'Update/Delete patatt');
} }
$db->transComplete(); $db->transCommit();
// if ($db->transStatus() === false) {
if ($db->transStatus() === false) { // throw new \Exception('Failed to sync patient relations');
throw new \Exception('Failed to sync patient relations'); // }
}
return $InternalPID; return $InternalPID;
} catch (\Exception $e) { } catch (\Exception $e) {
// $db->transRollback(); $db->transRollback();
throw $e; throw $e;
} }
} }
private function transformPatientData(array $patient): array { private function transformPatientData(array $patient): array {
$patient["Age"] = $this->calculateAgeFromBirthdate($patient["Birthdate"], $patient["DeathDateTime"]); $patient["Age"] = $this->calculateAgeFromBirthdate($patient["Birthdate"], $patient["DeathDateTime"]);
// $patient["Birthdate"] = $this->formatedDate($patient["Birthdate"]);
// $patient["CreateDate"] = $this->formatedDate($patient["CreateDate"]);
// $patient["DelDate"] = $this->formatedDate($patient["DelDate"]);
$patient["DeathDateTime"] = $this->formattedDate($patient["DeathDateTime"]); $patient["DeathDateTime"] = $this->formattedDate($patient["DeathDateTime"]);
$patient["CreateDate"] = $this->formattedDate($patient["CreateDate"]); $patient["CreateDate"] = $this->formattedDate($patient["CreateDate"]);
$patient["BirthdateConversion"] = $this->formatedDateForDisplay($patient["Birthdate"]); $patient["BirthdateConversion"] = $this->formatedDateForDisplay($patient["Birthdate"]);
@ -320,7 +319,7 @@ class PatientModel extends BaseUtcModel {
->getRowArray() ?: null; ->getRowArray() ?: null;
} }
// Conversion to (Years Months Days) // Conversion to (Years Months Days) - For Age
private function calculateAgeFromBirthdate($birthdate, $deathdatetime) { private function calculateAgeFromBirthdate($birthdate, $deathdatetime) {
$dob = new \DateTime($birthdate); $dob = new \DateTime($birthdate);
@ -350,9 +349,7 @@ class PatientModel extends BaseUtcModel {
// Conversion Time to Format Y-m-d\TH:i:s\Z // Conversion Time to Format Y-m-d\TH:i:s\Z
private function formattedDate(?string $dateString): ?string { private function formattedDate(?string $dateString): ?string {
try { try {
if (empty($dateString)) { if (empty($dateString)) {return null;}
return null;
}
$dt = new \DateTime($dateString, new \DateTimeZone("UTC")); $dt = new \DateTime($dateString, new \DateTimeZone("UTC"));
return $dt->format('Y-m-d\TH:i:s\Z'); // ISO 8601 UTC return $dt->format('Y-m-d\TH:i:s\Z'); // ISO 8601 UTC
@ -361,7 +358,7 @@ class PatientModel extends BaseUtcModel {
} }
} }
// Conversion Time to Format j M Y // Conversion Time to Format j M Y - For BirthdateConversion
private function formatedDateForDisplay($dateString) { private function formatedDateForDisplay($dateString) {
$date = \DateTime::createFromFormat('Y-m-d H:i', $dateString); $date = \DateTime::createFromFormat('Y-m-d H:i', $dateString);

View File

@ -42,11 +42,11 @@
</exclude> </exclude>
</source> </source>
<php> <php>
<!-- Enable / Disable --> <!-- Enable / Disable --> <!-- WAJIB DISESUAIKAN -->
<!-- <env name="CI_ENVIRONMENT" value="testing"/> --> <!-- <env name="CI_ENVIRONMENT" value="testing"/> -->
<!-- <server name="app.baseURL" value="http://example.com/"/> --> <!-- <server name="app.baseURL" value="http://example.com/"/> -->
<server name="app.baseURL" value="http://localhost/clqms01/"/> <server name="app.baseURL" value="http://localhost/clqms01/"/> <!-- WAJIB DISESUAIKAN -->
<server name="CODEIGNITER_SCREAM_DEPRECA TIONS" value="0"/> <server name="CODEIGNITER_SCREAM_DEPRECA TIONS" value="0"/>
<!-- Directory containing phpunit.xml --> <!-- Directory containing phpunit.xml -->
<const name="HOMEPATH" value="./"/> <const name="HOMEPATH" value="./"/>
@ -55,11 +55,11 @@
<!-- Directory containing the front controller (index.php) --> <!-- Directory containing the front controller (index.php) -->
<const name="PUBLICPATH" value="./public/"/> <const name="PUBLICPATH" value="./public/"/>
<!-- Database configuration --> <!-- Database configuration -->
<env name="database.tests.hostname" value="localhost"/> <env name="database.tests.hostname" value="localhost"/> <!-- WAJIB DISESUAIKAN -->
<env name="database.tests.database" value="clqms01"/> <env name="database.tests.database" value="clqm01"/> <!-- WAJIB DISESUAIKAN -->
<env name="database.tests.username" value="root"/> <env name="database.tests.username" value="root"/> <!-- WAJIB DISESUAIKAN -->
<env name="database.tests.password" value="adminsakti"/> <env name="database.tests.password" value=""/> <!-- WAJIB DISESUAIKAN -->
<env name="database.tests.DBDriver" value="MySQLi"/> <env name="database.tests.DBDriver" value="MySQLi"/> <!-- WAJIB DISESUAIKAN -->
<!-- <env name="database.tests.DBPrefix" value="tests_"/> --> <!-- <env name="database.tests.DBPrefix" value="tests_"/> -->
</php> </php>
</phpunit> </phpunit>

View File

@ -4,12 +4,14 @@ namespace Tests\Feature\Patients;
use CodeIgniter\Test\FeatureTestTrait; use CodeIgniter\Test\FeatureTestTrait;
use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\CIUnitTestCase;
use Faker\Factory;
class PatientCreateTest extends CIUnitTestCase class PatientCreateTest extends CIUnitTestCase
{ {
use FeatureTestTrait; use FeatureTestTrait;
protected $endpoint = 'api/patient'; protected $endpoint = 'api/patient';
// 400 - Passed
public function testCreatePatientValidationFail() { public function testCreatePatientValidationFail() {
// error 400 yg diharapkan // error 400 yg diharapkan
$payload = ['Name' => 'Ngawur']; $payload = ['Name' => 'Ngawur'];
@ -43,117 +45,310 @@ class PatientCreateTest extends CIUnitTestCase
} }
// Wajib Diganti ya payloadnya kalau mau dijalankan // 201 - Passed
public function testCreatePatientSuccess() { public function testCreatePatientSuccess() {
$payload = [
"PatientID"=> "SMAJ6", //Wajib Ganti
"AlternatePID"=> "P0234",
"Prefix"=> "Mr.",
"NameFirst"=> "Budi",
"NameMiddle"=> "Santoso",
"NameMaiden"=> "Kiki",
"NameLast"=> "Wijaya",
"Suffix"=> "S.kom",
"NameAlias"=> "Bud",
"Gender"=> "1",
'EmailAddress1' => 'kaka@gmail.a1com', //Wajib Ganti
'Identity' => [
"IdentifierType" => "KTP",
"Identifier" => "317409050590100" //Wajib Ganti
]
];
// $result = $this->call('post', 'api/patient', $payload); $faker = Factory::create('id_ID');
$result = $this->withBodyFormat('json')
->call('post', 'api/patient', $payload);
$result->assertStatus(201); for ($i = 0; $i < 7; $i++) {
$result->assertJSONFragment([
'status' => 'success', $payload = [
]); "PatientID" => "DUM" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000),
"AlternatePID" => "DMY" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000),
"Prefix" => $faker->title,
"NameFirst" => $faker->firstName,
"NameMiddle" => $faker->firstName,
"NameMaiden" => $faker->firstName,
"NameLast" => $faker->lastName,
"Suffix" => "S.Kom",
"NameAlias" => $faker->userName,
"Gender" => $faker->numberBetween(5, 6),
"PlaceOfBirth" => $faker->city,
"Birthdate" => $faker->date('Y-m-d'),
"ZIP" => $faker->postcode,
"Street_1" => $faker->streetAddress,
"Street_2" => "RT " . $faker->numberBetween(1, 10) . " RW " . $faker->numberBetween(1, 10),
"Street_3" => "Blok " . $faker->numberBetween(1, 20),
"City" => $faker->city,
"Province" => $faker->state,
"EmailAddress1" => "A" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000).'@gmail.com',
"EmailAddress2" => "B" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000).'@gmail.com',
"Phone" => $faker->phoneNumber,
"MobilePhone" => $faker->phoneNumber,
"Race" => (string) $faker->numberBetween(175, 205),
"Country" => (string) $faker->numberBetween(221, 469),
"MaritalStatus" => (string) $faker->numberBetween(8, 15),
"Religion" => (string) $faker->numberBetween(206, 212),
"Ethnic" => (string) $faker->numberBetween(213, 220),
"Citizenship" => "WNI",
"DeathIndicator" => (string) $faker->numberBetween(16, 17),
"LinkTo" => (string) $faker->numberBetween(2, 3),
"Custodian" => $i-1,
"PatIdt" => [
"IdentifierType" => "KTP",
"Identifier" => $faker->nik() ?? $faker->numerify('################')
],
"PatAtt" => [
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ]
],
"PatCom" => $faker->sentence,
];
if($payload['DeathIndicator'] == '16') {
$payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s');
} else {
$payload['DeathDateTime'] = null;
}
$result = $this->withBodyFormat('json')->call('post', 'api/patient', $payload);
$result->assertStatus(201);
$result->assertJSONFragment(['status' => 'success']);
}
} }
// public function testCreatePatientValidationError() { // Error - Passed
// $payload = [ public function testCreatePatientValidationError() {
// "NameFirst" => "Jane" // PatientID kosong $payload = [
// ]; "NameFirst" => "Jane" // PatientID kosong
];
// $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); $result = $this->withBodyFormat('json')->post($this->endpoint, $payload);
// dd($result);
$result->assertArrayHasKey("errors", $result);
}
// $result->assertStatus(422); // Error - Passed
// $result->assertJSONFragment(["field" => "patient"]); public function testCreatePatidtValidationError() {
// }
// public function testCreatePatidtValidationError() { $faker = Factory::create('id_ID');
// $payload = [
// "PatientID" => "PX002",
// "NameFirst" => "Jane",
// "Identity" => [
// "IdentifierType" => null,
// "Identifier" => null
// ]
// ];
// $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); $payload = [
"PatientID" => "DUMQ" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000),
"AlternatePID" => "DMYQ" . $faker->numberBetween(1, 1000). $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000),
"Prefix" => $faker->title,
"NameFirst" => $faker->firstName,
"NameMiddle" => $faker->firstName,
"NameMaiden" => $faker->firstName,
"NameLast" => $faker->lastName,
"Suffix" => "S.Kom",
"NameAlias" => $faker->userName,
"Gender" => $faker->numberBetween(5, 6),
"PlaceOfBirth" => $faker->city,
"Birthdate" => $faker->date('Y-m-d'),
"ZIP" => $faker->postcode,
"Street_1" => $faker->streetAddress,
"Street_2" => "RT " . $faker->numberBetween(1, 10) . " RW " . $faker->numberBetween(1, 10),
"Street_3" => "Blok " . $faker->numberBetween(1, 20),
"City" => $faker->city,
"Province" => $faker->state,
"EmailAddress1" => "AAQ" . (string)$faker->numberBetween(1, 1110).'@gmail.com',
"EmailAddress2" => "BAQ" . (string)$faker->numberBetween(1, 1110).'@gmail.com',
"Phone" => $faker->phoneNumber,
"MobilePhone" => $faker->phoneNumber,
"Race" => (string) $faker->numberBetween(175, 205),
"Country" => (string) $faker->numberBetween(221, 469),
"MaritalStatus" => (string) $faker->numberBetween(8, 15),
"Religion" => (string) $faker->numberBetween(206, 212),
"Ethnic" => (string) $faker->numberBetween(213, 220),
"Citizenship" => "WNI",
"DeathIndicator" => (string) $faker->numberBetween(16, 17),
"LinkTo" => (string) $faker->numberBetween(2, 3),
"Custodian" => 1,
"PatIdt" => [
"IdentifierType" => "KTP",
"Identifier" => "numberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetweennumberBetween"
// "Identifier" => $faker->nik() ?? $faker->numerify('################')
],
"PatAtt" => [
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ]
],
"PatCom" => $faker->sentence,
];
// $result->assertStatus(422); if($payload['DeathIndicator'] == '16') {
// $result->assertJSONFragment(["field" => "patidt"]); $payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s');
// } } else {
$payload['DeathDateTime'] = null;
}
// public function testCreateWithoutAttachments() { $result = $this->withBodyFormat('json')->post($this->endpoint, $payload);
// $payload = [
// "PatientID" => "PX003",
// "NameFirst" => "NoAttach",
// "Identity" => [
// "IdentifierType" => "KTP",
// "Identifier" => "99999"
// ]
// ];
// $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); $result->assertArrayHasKey("errors", $result);
}
// $result->assertStatus(201); // 201 - Passed
// } public function testCreateWithoutAttachments() {
$faker = Factory::create('id_ID');
// public function testCreateWithoutComment() { $payload = [
// $payload = [ "PatientID" => "DUAU" . $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000),
// "PatientID" => "PX004", "AlternatePID" => "DMAU" . $faker->numberBetween(5, 1000).$faker->numberBetween(1, 1000),
// "NameFirst" => "NoComment", "Prefix" => $faker->title,
// "Identity" => [ "NameFirst" => $faker->firstName,
// "IdentifierType" => "SIM", "NameMiddle" => $faker->firstName,
// "Identifier" => "A12345" "NameMaiden" => $faker->firstName,
// ], "NameLast" => $faker->lastName,
// "Attachments" => [ "Suffix" => "S.Kom",
// ["Address" => "Jl. Melati No.2"] "NameAlias" => $faker->userName,
// ] "Gender" => $faker->numberBetween(5, 6),
// ]; "PlaceOfBirth" => $faker->city,
"Birthdate" => $faker->date('Y-m-d'),
"ZIP" => $faker->postcode,
"Street_1" => $faker->streetAddress,
"Street_2" => "RT " . $faker->numberBetween(1, 10) . " RW " . $faker->numberBetween(1, 10),
"Street_3" => "Blok " . $faker->numberBetween(1, 20),
"City" => $faker->city,
"Province" => $faker->state,
"EmailAddress1" => "AiA" . $faker->numberBetween(1, 1110).$faker->numberBetween(1, 1110).'@gmail.com',
"EmailAddress2" => "BiA" . $faker->numberBetween(1, 1110).$faker->numberBetween(1, 1110).'@gmail.com',
"Phone" => $faker->phoneNumber,
"MobilePhone" => $faker->phoneNumber,
"Race" => (string) $faker->numberBetween(175, 205),
"Country" => (string) $faker->numberBetween(221, 469),
"MaritalStatus" => (string) $faker->numberBetween(8, 15),
"Religion" => (string) $faker->numberBetween(206, 212),
"Ethnic" => (string) $faker->numberBetween(213, 220),
"Citizenship" => "WNI",
"DeathIndicator" => (string) $faker->numberBetween(16, 17),
"LinkTo" => (string) $faker->numberBetween(2, 3),
"Custodian" => 1,
"PatIdt" => [
"IdentifierType" => "KTP",
"Identifier" => $faker->nik() ?? $faker->numerify('################')
],
"PatAtt" => [],
"PatCom" => $faker->sentence,
];
// $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); if($payload['DeathIndicator'] == '16') {
$payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s');
} else {
$payload['DeathDateTime'] = null;
}
// $result->assertStatus(201); $result = $this->withBodyFormat('json')->post($this->endpoint, $payload);
// }
// public function testCreateDatabaseError() { $result->assertStatus(201);
// // Insert patient pertama }
// $payload = [
// "InternalPID" => 999, // Force ID
// "PatientID" => "PX005",
// "NameFirst" => "First",
// "Identity" => [
// "IdentifierType" => "KTP",
// "Identifier" => "DBERR1"
// ]
// ];
// $this->withBodyFormat('json')->post($this->endpoint, $payload);
// // Insert kedua dengan InternalPID sama → trigger error // 201 - Passed
// $payload["NameFirst"] = "Second"; public function testCreateWithoutPatComments() {
// $payload["Identity"]["Identifier"] = "DBERR2"; $faker = Factory::create('id_ID');
// $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); $payload = [
"PatientID" => "DUALU" . $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000),
"AlternatePID" => "DMALU" . $faker->numberBetween(5, 1000).$faker->numberBetween(1, 1000),
"Prefix" => $faker->title,
"NameFirst" => $faker->firstName,
"NameMiddle" => $faker->firstName,
"NameMaiden" => $faker->firstName,
"NameLast" => $faker->lastName,
"Suffix" => "S.Kom",
"NameAlias" => $faker->userName,
"Gender" => $faker->numberBetween(5, 6),
"PlaceOfBirth" => $faker->city,
"Birthdate" => $faker->date('Y-m-d'),
"ZIP" => $faker->postcode,
"Street_1" => $faker->streetAddress,
"Street_2" => "RT " . $faker->numberBetween(1, 10) . " RW " . $faker->numberBetween(1, 10),
"Street_3" => "Blok " . $faker->numberBetween(1, 20),
"City" => $faker->city,
"Province" => $faker->state,
"EmailAddress1" => "AiAe" . $faker->numberBetween(1, 1110).$faker->numberBetween(1, 1110).'@gmail.com',
"EmailAddress2" => "BiAe" . $faker->numberBetween(1, 1110).$faker->numberBetween(1, 1110).'@gmail.com',
"Phone" => $faker->phoneNumber,
"MobilePhone" => $faker->phoneNumber,
"Race" => (string) $faker->numberBetween(175, 205),
"Country" => (string) $faker->numberBetween(221, 469),
"MaritalStatus" => (string) $faker->numberBetween(8, 15),
"Religion" => (string) $faker->numberBetween(206, 212),
"Ethnic" => (string) $faker->numberBetween(213, 220),
"Citizenship" => "WNI",
"DeathIndicator" => (string) $faker->numberBetween(16, 17),
"LinkTo" => (string) $faker->numberBetween(2, 3),
"Custodian" => 1,
"PatIdt" => [
"IdentifierType" => "KTP",
"Identifier" => $faker->nik() ?? $faker->numerify('################')
],
"PatAtt" => [
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ],
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ],
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ]
],
"PatCom" => null,
];
// $result->assertStatus(500); if($payload['DeathIndicator'] == '16') {
// } $payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s');
} else {
$payload['DeathDateTime'] = null;
}
$result = $this->withBodyFormat('json')->post($this->endpoint, $payload);
$result->assertStatus(201);
}
// 500 - Passed
public function testCreateDatabaseError() {
$faker = Factory::create('id_ID');
// Insert patient pertama
$payload = [
"PatientID" => "DaUALU" . $faker->numberBetween(1, 1000).$faker->numberBetween(1, 1000),
"AlternatePID" => "DaMALU" . $faker->numberBetween(5, 1000).$faker->numberBetween(1, 1000),
"Prefix" => $faker->title,
"NameFirst" => $faker->firstName,
"NameMiddle" => $faker->firstName,
"NameMaiden" => $faker->firstName,
"NameLast" => $faker->lastName,
"Suffix" => "S.Kom",
"NameAlias" => $faker->userName,
"Gender" => $faker->numberBetween(5, 6),
"PlaceOfBirth" => $faker->city,
"Birthdate" => $faker->date('Y-m-d'),
"ZIP" => $faker->postcode,
"Street_1" => $faker->streetAddress,
"Street_2" => "RT " . $faker->numberBetween(1, 10) . " RW " . $faker->numberBetween(1, 10),
"Street_3" => "Blok " . $faker->numberBetween(1, 20),
"City" => $faker->city,
"Province" => $faker->state,
"EmailAddress1" => "AiaAe" . $faker->numberBetween(1, 1110).$faker->numberBetween(1, 1110).'@gmail.com',
"EmailAddress2" => "BiaAe" . $faker->numberBetween(1, 1110).$faker->numberBetween(1, 1110).'@gmail.com',
"Phone" => $faker->phoneNumber,
"MobilePhone" => $faker->phoneNumber,
"Race" => (string) $faker->numberBetween(175, 205),
"Country" => (string) $faker->numberBetween(221, 469),
"MaritalStatus" => (string) $faker->numberBetween(8, 15),
"Religion" => (string) $faker->numberBetween(206, 212),
"Ethnic" => (string) $faker->numberBetween(213, 220),
"Citizenship" => "WNI",
"DeathIndicator" => (string) $faker->numberBetween(16, 17),
"LinkTo" => (string) $faker->numberBetween(2, 3),
"Custodian" => 1,
"PatIdt" => [
"IdentifierType" => "KTP",
"Identifier" => $faker->nik() ?? $faker->numerify('################')
],
"PatAtt" => [
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ],
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ],
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ]
],
"PatCom" => [], // Ini Salah
];
if($payload['DeathIndicator'] == '16') {
$payload['DeathDateTime'] = $faker->date('Y-m-d H:i:s');
} else {
$payload['DeathDateTime'] = null;
}
$result = $this->withBodyFormat('json')->post($this->endpoint, $payload);
$result->assertStatus(500);
}
// public function testCreateDuplicateIdentifier() { // public function testCreateDuplicateIdentifier() {
// $payload = [ // $payload = [
@ -178,44 +373,4 @@ class PatientCreateTest extends CIUnitTestCase
// $result->assertStatus(422); // $result->assertStatus(422);
// } // }
// public function testCreateWithLinkTo() {
// $payload = [
// "PatientID" => "PX008",
// "NameFirst" => "LinkTo",
// "Identity" => [
// "IdentifierType" => "KTP",
// "Identifier" => "LINK123"
// ],
// "LinkTo" => [
// ["InternalPID" => 1],
// ["InternalPID" => 2]
// ]
// ];
// $result = $this->withBodyFormat('json')->post($this->endpoint, $payload);
// $result->assertStatus(201);
// $data = json_decode($result->getBody(), true);
// $this->assertIsInt($data["data"]);
// }
// public function testCreateWithNumericAndNullFields() {
// $payload = [
// "PatientID" => "PX009",
// "NameFirst" => "Numeric",
// "Gender" => null,
// "RaceID" => "3",
// "DeathIndicator" => 0,
// "Identity" => [
// "IdentifierType" => "SIM",
// "Identifier" => "NUM123"
// ]
// ];
// $result = $this->withBodyFormat('json')->post($this->endpoint, $payload);
// $result->assertStatus(201);
// }
} }

View File

@ -10,87 +10,87 @@ class PatientDeleteTest extends CIUnitTestCase
use FeatureTestTrait; use FeatureTestTrait;
protected $endpoint = 'api/patient'; protected $endpoint = 'api/patient';
// 500 error catch // // 500 error catch
public function testDeleteWithoutInternalPID() { // public function testDeleteWithoutInternalPID() {
$result = $this->withBodyFormat('json') // $result = $this->withBodyFormat('json')
->delete($this->endpoint, []); // ->delete($this->endpoint, []);
$result->assertStatus(500); // $result->assertStatus(500);
$result->assertJSONFragment([ // $result->assertJSONFragment([
'status' => 500, // 'status' => 500,
'messages' => [ // 'messages' => [
'error' => 'Internal server error: Undefined array key "InternalPID"' // 'error' => 'Internal server error: Undefined array key "InternalPID"'
] // ]
]); // ]);
} // }
// 400 // // 400
public function testDeleteWitWrongInternalPID() { // public function testDeleteWitWrongInternalPID() {
$result = $this->withBodyFormat('json') // $result = $this->withBodyFormat('json')
->delete($this->endpoint, [ // ->delete($this->endpoint, [
// Pilih salah satu // // Pilih salah satu
// 'InternalPID' => [], // // 'InternalPID' => [],
// 'InternalPID' => 0, // // 'InternalPID' => 0,
// 'InternalPID' => '0', // // 'InternalPID' => '0',
// 'InternalPID' => '', // // 'InternalPID' => '',
'InternalPID' => null, // 'InternalPID' => null,
]); // ]);
$result->assertStatus(400); // $result->assertStatus(400);
$result->assertJSONFragment([ // $result->assertJSONFragment([
'status' => 'error', // 'status' => 'error',
'message' => 'Patient ID must be a valid integer.' // 'message' => 'Patient ID must be a valid integer.'
]); // ]);
} // }
// 404 not found // // 404 not found
public function testDeleteNotFound() { // public function testDeleteNotFound() {
$testId = 9999; // $testId = 9999;
$result = $this->withBodyFormat('json') // $result = $this->withBodyFormat('json')
->delete($this->endpoint, [ // ->delete($this->endpoint, [
'InternalPID' => $testId // 'InternalPID' => $testId
]); // ]);
$result->assertStatus(404); // $result->assertStatus(404);
$result->assertJSONFragment([ // $result->assertJSONFragment([
'status' => 404, // 'status' => 404,
'error' => 404, // 'error' => 404,
'messages' => [ // 'messages' => [
'error' => 'Patient ID with '.$testId.' not found.' // 'error' => 'Patient ID with '.$testId.' not found.'
] // ]
]); // ]);
} // }
// 200 ok // // 200 ok
public function testDeleteSuccess() { // public function testDeleteSuccess() {
$testId = 3; // $testId = 3;
// Anggap patient 1 2 3 ada di seed DB // // Anggap patient 1 2 3 ada di seed DB
$result = $this->withBodyFormat('json') // $result = $this->withBodyFormat('json')
->delete($this->endpoint, [ // ->delete($this->endpoint, [
'InternalPID' => $testId // 'InternalPID' => $testId
]); // ]);
$result->assertStatus(200); // $result->assertStatus(200);
$result->assertJSONFragment([ // $result->assertJSONFragment([
'status' => 'success', // 'status' => 'success',
'message' => 'Patient ID with '.$testId.' deleted successfully.' // 'message' => 'Patient ID with '.$testId.' deleted successfully.'
]); // ]);
} // }
// 400 - SQL Inject // // 400 - SQL Inject
public function testDeleteServerError() { // public function testDeleteServerError() {
// Simulasi: kirim input aneh yang trigger exception // // Simulasi: kirim input aneh yang trigger exception
$result = $this->withBodyFormat('json') // $result = $this->withBodyFormat('json')
->delete($this->endpoint, [ // ->delete($this->endpoint, [
'InternalPID' => "' OR 1=1 --" // 'InternalPID' => "' OR 1=1 --"
]); // ]);
$result->assertStatus(400); // $result->assertStatus(400);
$result->assertJSONFragment([ // $result->assertJSONFragment([
'status' => 'error', // 'status' => 'error',
'message' => 'Patient ID must be a valid integer.' // 'message' => 'Patient ID must be a valid integer.'
]); // ]);
} // }
} }

View File

@ -12,7 +12,7 @@ class PatientIndexTest extends CIUnitTestCase
protected $endpoint = 'api/patient'; protected $endpoint = 'api/patient';
/** /**
* Case 1: tanpa parameter, harus 200 dan status success * Case 1: tanpa parameter, harus 200 dan status success - Passed
*/ */
public function testIndexWithoutParams() { public function testIndexWithoutParams() {
$result = $this->call('get', $this->endpoint); $result = $this->call('get', $this->endpoint);
@ -24,7 +24,7 @@ class PatientIndexTest extends CIUnitTestCase
} }
/** /**
* Case 2: parameter Name yang tidak ada return kosong [] * Case 2: parameter Name yang tidak ada return kosong [] - Passed
*/ */
public function testIndexWithWrongNameParam() { public function testIndexWithWrongNameParam() {
$result = $this->call('get', $this->endpoint, [ $result = $this->call('get', $this->endpoint, [
@ -39,7 +39,7 @@ class PatientIndexTest extends CIUnitTestCase
} }
/** /**
* Case 3: parameter Name benar return array tidak kosong * Case 3: parameter Name benar return array tidak kosong - Passed
*/ */
public function testIndexWithCorrectNameParam() { public function testIndexWithCorrectNameParam() {
// Sesuaikan dengan data di database test Anda // Sesuaikan dengan data di database test Anda
@ -58,7 +58,7 @@ class PatientIndexTest extends CIUnitTestCase
} }
/** /**
* Case 4: parameter InternalPID return data sesuai ID * Case 4: parameter InternalPID return data sesuai ID - Passed
*/ */
public function testIndexWithInternalPID() { public function testIndexWithInternalPID() {
$result = $this->call('get', $this->endpoint, [ $result = $this->call('get', $this->endpoint, [
@ -77,7 +77,7 @@ class PatientIndexTest extends CIUnitTestCase
} }
/** /**
* Case 5: parameter PatientID return data sesuai PatientID * Case 5: parameter PatientID return data sesuai PatientID - Passed
*/ */
public function testIndexWithPatientID() { public function testIndexWithPatientID() {
$result = $this->call('get', $this->endpoint, [ $result = $this->call('get', $this->endpoint, [
@ -96,7 +96,7 @@ class PatientIndexTest extends CIUnitTestCase
} }
/** /**
* Case 6: parameter Birthdate return data sesuai tanggal * Case 6: parameter Birthdate return data sesuai tanggal - Passed
*/ */
public function testIndexWithBirthdate() { public function testIndexWithBirthdate() {
$result = $this->call('get', $this->endpoint, [ $result = $this->call('get', $this->endpoint, [
@ -115,7 +115,7 @@ class PatientIndexTest extends CIUnitTestCase
} }
/** /**
* Case 7: Simulasi server error (optional, jika bisa trigger) * Case 7: Simulasi server error (optional, jika bisa trigger) - Passed
*/ */
public function testIndexServerErrorSimulation() { public function testIndexServerErrorSimulation() {
// Misalnya panggil dengan param aneh untuk trigger exception // Misalnya panggil dengan param aneh untuk trigger exception
@ -123,12 +123,6 @@ class PatientIndexTest extends CIUnitTestCase
'InternalPID' => "' OR 1=2 --" 'InternalPID' => "' OR 1=2 --"
]); ]);
// dd([
// 'status' => $result->getStatusCode(),
// 'body' => $result->getBody(),
// 'json' => $result->getJSON(),
// ]);
// Boleh assert 200 (jika sanitasi bagus) atau 500 (kalau exception) // Boleh assert 200 (jika sanitasi bagus) atau 500 (kalau exception)
$this->assertContains($result->getStatusCode(), [200, 500, null]); $this->assertContains($result->getStatusCode(), [200, 500, null]);
} }

View File

@ -11,28 +11,29 @@ class PatientShowTest extends CIUnitTestCase
protected $endpoint = 'api/patient'; protected $endpoint = 'api/patient';
// 200 ok not found // 200 ok not found - Passed
public function testShowNotFound() { public function testShowNotFound() {
$result = $this->get($this->endpoint . '/90909090'); $result = $this->get($this->endpoint . '/90909090');
$result->assertStatus(200); $result->assertStatus(200);
$result->assertJSONFragment([ $result->assertJSONFragment([
'status' => 'success', 'status' => 'success',
"message" => "Patient with ID 90909090 not found.", "message" => "data not found."
'data' => []
]); ]);
} }
// 200 ok // 200 ok found - Passed
public function testShowSingleRow() { public function testShowSingleRow() {
// Pastikan DB test punya seed patient InternalPID=10 tanpa id/addr // Pastikan DB test punya seed patient InternalPID=10 tanpa id/addr
$result = $this->get($this->endpoint . '/1'); $result = $this->get($this->endpoint . '/1');
$result->assertStatus(200);
$data = $result->getJSON(true); $data = $result->getJSON(true);
$data = json_decode($data, true); $data = json_decode($data, true);
$this->assertEquals('success', $data['status']); $result->assertStatus(200);
// $this->assertNull($data['data']['Attachments']); $result->assertArrayHasKey('data', $data);
$result->assertIsArray($data['data']);
// $this->assertEquals('success', $data['status']);
} }
} }

View File

@ -4,86 +4,155 @@ namespace Tests\Feature\Patients;
use CodeIgniter\Test\FeatureTestTrait; use CodeIgniter\Test\FeatureTestTrait;
use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\CIUnitTestCase;
use Faker\Factory;
class PatientUpdateTest extends CIUnitTestCase class PatientUpdateTest extends CIUnitTestCase
{ {
use FeatureTestTrait; use FeatureTestTrait;
protected $endpoint = 'api/patient';
// Belon public function testUpdatePatientSuccess()
{
$faker = Factory::create('id_ID');
// public function testUpdateFail() $payload = [
// { "InternalPID" => 1,
// $payload = []; "PatientID" => "UPDT" . $faker->numberBetween(100, 999),
// $result = $this->withBodyFormat('json') "NameFirst" => $faker->firstName,
// ->call('patch', 'api/patient', $payload); "NameLast" => $faker->lastName,
// $result->assertStatus(400); "Gender" => (string) $faker->numberBetween(5, 6),
"Birthdate" => $faker->date('Y-m-d'),
"DeathDateTime" => null,
"EmailAddress1" => "asasa@gmail.com",
"PlaceOfBirth" => $faker->city,
"Race" => (string) $faker->numberBetween(175, 205),
"Religion" => (string) $faker->numberBetween(206, 212),
"Country" => (string) $faker->numberBetween(221, 469),
"MaritalStatus" => (string) $faker->numberBetween(8, 15),
"Citizenship" => "WNI",
"LinkTo" => null,
"PatIdt" => [
"IdentifierType" => "KTP",
"Identifier" => $faker->nik(),
],
"PatCom" => $faker->sentence(5),
"PatAtt" => [
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ],
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ]
]
];
// $payload = [ $result = $this->withBodyFormat('json')->patch($this->endpoint, $payload);
// "InternalPID"=> 100,
// "PatientID"=> "SMAJ50", //Wajib Ganti
// "AlternatePID"=> "P0234",
// "Prefix"=> "Mr.",
// "NameFirst"=> "Budi",
// "NameMiddle"=> "Santoso",
// "NameMaiden"=> "Kiki",
// "NameLast"=> "Wijaya",
// "Suffix"=> "S.kom",
// "NameAlias"=> "Bud",
// "Gender"=> "1",
// 'EmailAddress1' => 'kaka@gmail.a1com', //Wajib Ganti
// 'Identity' => [
// "IdentifierType" => "KTP",
// "Identifier" => "317409050590100" //Wajib Ganti
// ]
// ];
// $result = $this->withBodyFormat('json')
// ->call('patch', 'api/patient', $payload);
// $result->assertStatus(404);
// $payload = [ $result->assertStatus(201);
// "PatientID"=> "SMAJ50", //Wajib Ganti }
// "AlternatePID"=> "P0234",
// "Prefix"=> "Mr.", // /**
// "NameFirst"=> "Budi", // * ❌ Test gagal karena InternalPID kosong (validasi)
// "NameMiddle"=> "Santoso", // */
// "NameMaiden"=> "Kiki", public function testUpdatePatientValidationError()
// "NameLast"=> "Wijaya", {
// "Suffix"=> "S.kom", $faker = Factory::create('id_ID');
// "NameAlias"=> "Bud",
// "Gender"=> "1", $payload = [
// 'EmailAddress1' => 'kaka@gmail.a1com', //Wajib Ganti "NameFirst" => $faker->firstName,
// 'Identity' => [ "Gender" => (string) $faker->numberBetween(5, 6),
// "IdentifierType" => "KTP", "Birthdate" => $faker->date('Y-m-d'),
// "Identifier" => "317409050590100" //Wajib Ganti // Tidak kirim InternalPID
// ] ];
// ];
// $result = $this->withBodyFormat('json') $result = $this->withBodyFormat('json')->patch($this->endpoint, $payload);
// ->call('patch', 'api/patient', $payload); $json = $result->getJSON();
// $result->assertStatus(500); $data = json_decode($json, true);
// }
$result->assertStatus(400);
$this->assertArrayHasKey('errors', $data);
}
// /**
// * ✅ Test update dengan address baru & hapus address lama
// */
public function testUpdatePatientWithAddressChange()
{
$faker = Factory::create('id_ID');
$payload = [
"InternalPID" => 1,
"PatientID" => "UPDT" . $faker->numberBetween(100, 999),
"NameFirst" => $faker->firstName,
"NameLast" => $faker->lastName,
"Gender" => (string) $faker->numberBetween(5, 6),
"Birthdate" => $faker->date('Y-m-d'),
"DeathDateTime" => null,
"EmailAddress1" => "asasa@gmail.com",
"PlaceOfBirth" => $faker->city,
"Race" => (string) $faker->numberBetween(175, 205),
"Religion" => (string) $faker->numberBetween(206, 212),
"Country" => (string) $faker->numberBetween(221, 469),
"MaritalStatus" => (string) $faker->numberBetween(8, 15),
"Citizenship" => "WNI",
"LinkTo" => null,
"PatIdt" => [
"IdentifierType" => "KTP",
"Identifier" => $faker->nik(),
],
"PatCom" => $faker->sentence(5),
"PatAtt" => [
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ],
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ],
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ],
[ "Address" => "/api/upload/" . $faker->word . ".jpg" ]
]
];
$result = $this->withBodyFormat('json')->patch($this->endpoint, $payload);
$result->assertStatus(201);
$json = $result->getJSON();
$data = json_decode($json, true);
$this->assertEquals('success', $data['status']);
}
// /**
// * ⚠️ Test update kosong → semua pattat address dihapus (soft delete)
// */
public function testUpdatePatientEmptyAddress()
{
$faker = Factory::create('id_ID');
$payload = [
"InternalPID" => 1,
"PatientID" => "UPDT" . $faker->numberBetween(100, 999),
"NameFirst" => $faker->firstName,
"NameLast" => $faker->lastName,
"Gender" => (string) $faker->numberBetween(5, 6),
"Birthdate" => $faker->date('Y-m-d'),
"DeathDateTime" => null,
"EmailAddress1" => "asasa@gmail.com",
"PlaceOfBirth" => $faker->city,
"Race" => (string) $faker->numberBetween(175, 205),
"Religion" => (string) $faker->numberBetween(206, 212),
"Country" => (string) $faker->numberBetween(221, 469),
"MaritalStatus" => (string) $faker->numberBetween(8, 15),
"Citizenship" => "WNI",
"LinkTo" => null,
"PatIdt" => [
"IdentifierType" => "KTP",
"Identifier" => $faker->nik(),
],
"PatCom" => $faker->sentence(5),
"PatAtt" => []
];
$result = $this->withBodyFormat('json')->patch($this->endpoint, $payload);
$json = $result->getJSON();
$data = json_decode($json, true);
$result->assertStatus(201);
$this->assertEquals('success', $data['status']);
}
// public function testUpdateSuccess()
// {
// $payload = [
// "InternalPID"=> 1, //Wajib Ganti
// "PatientID"=> "SMAJ50",
// "AlternatePID"=> "asasasa",
// "Prefix"=> "Mr.",
// "NameFirst"=> "Budi",
// "NameMiddle"=> "Santoso",
// "NameMaiden"=> "Kiki",
// "NameLast"=> "Wijaya",
// "Suffix"=> "S.kom",
// "NameAlias"=> "Bud",
// "Gender"=> "1",
// 'EmailAddress1' => 'kaka@gmail.a1com',
// 'Identity' => [
// "IdentifierType" => "KTP",
// "Identifier" => "317409050590100"
// ]
// ];
// $result = $this->withBodyFormat('json')
// ->call('patch', 'api/patient', $payload);
// $result->assertStatus(200);
// }
} }