diff --git a/app/Controllers/Patient.php b/app/Controllers/Patient.php index bf5fcbe..65e6862 100644 --- a/app/Controllers/Patient.php +++ b/app/Controllers/Patient.php @@ -20,7 +20,7 @@ class Patient extends Controller { $this->rulesPatIdt = ['Identifier' => 'required|is_unique[patidt.Identifier]']; } - // OK - Done + // Unit Testing Pass : \clqms-be\tests\feature\Patients\PatientIndexTest.php public function index() { try { $InternalPID = $this->request->getVar('InternalPID'); @@ -64,6 +64,7 @@ class Patient extends Controller { } } + // Unit Testing Pass : \clqms-be\tests\feature\Patients\PatientShowTest.php public function show($InternalPID = null) { try { $rows = $this->db->table('patient') @@ -131,7 +132,7 @@ class Patient extends Controller { } } - + // Transform Data Conversion private function transformPatientData(array $patient): array { $patient["Age"] = $this->calculateAgeFromBirthdate($patient["Birthdate"]); $patient["Birthdate"] = $this->formatedDate($patient["Birthdate"]); @@ -146,6 +147,7 @@ class Patient extends Controller { return $patient; } + // Linkto is not empty? then Query and return array data (InternalPID, PatientID) private function getLinkedPatients(?string $linkTo): ?array { if (empty($linkTo)) { return null; @@ -160,6 +162,7 @@ class Patient extends Controller { ->getResultArray() ?: null; } + // Custodian is not empty? then Query and return array data (InternalPID, PatientID) private function getCustodian($custodianId): ?array { if (empty($custodianId)) { return null; @@ -169,10 +172,10 @@ class Patient extends Controller { ->select('InternalPID, PatientID') ->where('InternalPID', (int) $custodianId) ->get() - ->getResultArray() ?: null; + ->getRowArray() ?: null; } - + // Unit Testing Pass : On Progress public function create() { try { $input = $this->request->getJSON(true); @@ -201,7 +204,6 @@ class Patient extends Controller { } */ - $this->db->transStart(); $this->db->table('patient')->insert($dataPatient); @@ -251,6 +253,7 @@ class Patient extends Controller { } } + // Setting up data private function preparePatientData(array $input, string $mode = 'create'): array { $LinkTo = null; if (!empty($input['LinkTo'])) { @@ -298,7 +301,6 @@ class Patient extends Controller { return $data; } - private function preparePatidtData(array $input ): array { $data = [ "IdentifierType" => $input['Identity']['IdentifierType'] ?? null, @@ -307,7 +309,6 @@ class Patient extends Controller { return $data; } - private function preparePatattData(array $input): array { if (empty($input['Attachments'])) { return []; @@ -320,7 +321,6 @@ class Patient extends Controller { return $row; }, $input['Attachments']); } - private function preparePatcomData(array $input): array { $data = [ "Comment" => $input['Comment'] ?? null, @@ -328,7 +328,6 @@ class Patient extends Controller { return $data; } - private function validationError(string $context, array $errors) { return $this->respond([ 'status' => 'error', @@ -337,6 +336,7 @@ class Patient extends Controller { ], 400); } + // Unit Testing Pass : On Progress public function update() { try { $input = $this->request->getJSON(true); @@ -344,7 +344,7 @@ class Patient extends Controller { if (!$input["InternalPID"] || !is_numeric($input["InternalPID"])) { return $this->respond(['status' => 'error', 'message' => 'Invalid or missing InternalPID'], 400); } $InternalPID = $input["InternalPID"]; - $patient = $this->db->table('patient')->where('InternalPID', $InternalPID)->get()->getResultArray(); + $patient = $this->db->table('patient')->where('InternalPID', $InternalPID)->get()->getRowArray(); if (!$patient) { return $this->respond(['status' => 'error', 'message' => 'Patient not found'], 404); } $dataPatient = $this->preparePatientData($input); @@ -420,13 +420,18 @@ class Patient extends Controller { } } + // Unit Testing Pass : \clqms-be\tests\feature\Patients\PatientDeleteTest.php public function delete() { try { $input = $this->request->getJSON(true); $InternalPID = $input["InternalPID"]; - - if (!$InternalPID) { - return $this->failValidationError('Patient ID is required.'); + + // Mencegah Inputan 0, [], null, sql injection + if (empty($InternalPID) || !ctype_digit((string) $InternalPID)) { + return $this->respond([ + 'status' => 'error', + 'message' => "Patient ID must be a valid integer." + ], 400); } $patient = $this->db->table('patient')->where('InternalPID', $InternalPID)->get()->getRow(); @@ -447,7 +452,6 @@ class Patient extends Controller { } } - // OK - Done public function patientCheck() { try { $PatientID = $this->request->getVar('PatientID'); @@ -466,7 +470,7 @@ class Patient extends Controller { $patient = $this->db->table('patient') ->where($tableName, $searchName) ->get() - ->getResultArray(); + ->getRowArray(); if (!$patient) { return $this->respond([ @@ -489,8 +493,7 @@ class Patient extends Controller { } } - - // Ubah ke format Years Months Days + // Conversion to (Years Months Days) private function calculateAgeFromBirthdate($birthdate) { $dob = new \DateTime($birthdate); $today = new \DateTime(); @@ -510,7 +513,7 @@ class Patient extends Controller { return $formattedAge; } - // Ubah ke format Y-m-d H:i + // Conversion Time to Format Y-m-d H:i private function formatedDate($dateString) { $date = \DateTime::createFromFormat('Y-m-d H:i', $dateString); @@ -525,7 +528,7 @@ class Patient extends Controller { return $date->format('Y-m-d H:i'); } - // Ubah ke format j M Y + // Conversion Time to Format j M Y private function formatedDateForDisplay($dateString) { $date = \DateTime::createFromFormat('Y-m-d H:i', $dateString); diff --git a/tests/feature/Patients/PatientCreateTest.php b/tests/feature/Patients/PatientCreateTest.php index a6e105e..7430535 100644 --- a/tests/feature/Patients/PatientCreateTest.php +++ b/tests/feature/Patients/PatientCreateTest.php @@ -1,6 +1,6 @@ 'Ngawur']; -// $result = $this->withBodyFormat('json') -// ->call('post', 'api/patient', $payload); -// $result->assertStatus(400); -// $result->assertJSONFragment([ -// 'status' => 'error' -// ]); + // public function testCreatePatientValidationFail() + // { + // // error 400 yg diharapkan + // $payload = ['Name' => 'Ngawur']; + // $result = $this->withBodyFormat('json') + // ->call('post', 'api/patient', $payload); + // $result->assertStatus(400); + // $result->assertJSONFragment([ + // 'status' => 'error' + // ]); -// // Kondisi Jika PatiD Sama -// $payload = [ -// "PatientID"=> "SMAJ1", -// "AlternatePID"=> "ALT001234", -// "Prefix"=> "Mr.", -// "NameFirst"=> "Budi", -// "NameMiddle"=> "Santoso", -// "NameMaiden"=> "Kiki", -// "NameLast"=> "Wijaya", -// "Suffix"=> "S.kom", -// "NameAlias"=> "Bud", -// "Gender"=> "1", -// ]; -// $result = $this->withBodyFormat('json') -// ->call('post', 'api/patient', $payload); -// $result->assertStatus(400); -// $result->assertJSONFragment([ -// 'status' => 'error', -// "message" => "Validation failed (patient)", -// ]); + // // Kondisi Jika PatiD Sama + // $payload = [ + // "PatientID"=> "SMAJ1", + // "AlternatePID"=> "ALT001234", + // "Prefix"=> "Mr.", + // "NameFirst"=> "Budi", + // "NameMiddle"=> "Santoso", + // "NameMaiden"=> "Kiki", + // "NameLast"=> "Wijaya", + // "Suffix"=> "S.kom", + // "NameAlias"=> "Bud", + // "Gender"=> "1", + // ]; + // $result = $this->withBodyFormat('json') + // ->call('post', 'api/patient', $payload); + // $result->assertStatus(400); + // $result->assertJSONFragment([ + // 'status' => 'error', + // "message" => "Validation failed (patient)", + // ]); -// } + // } -// // Wajib Diganti ya payloadnya kalau mau dijalankan -// public function testCreateSuccess() -// { -// $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 -// ] -// ]; + // // Wajib Diganti ya payloadnya kalau mau dijalankan + // public function testCreateSuccess() + // { + // $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); -// $result = $this->withBodyFormat('json') -// ->call('post', 'api/patient', $payload); + // // $result = $this->call('post', 'api/patient', $payload); + // $result = $this->withBodyFormat('json') + // ->call('post', 'api/patient', $payload); -// $result->assertStatus(201); -// $result->assertJSONFragment([ -// 'status' => 'success', -// ]); -// } + // $result->assertStatus(201); + // $result->assertJSONFragment([ + // 'status' => 'success', + // ]); + // } + + // dd($result); + + public function testCreatePatientSuccess() { + $payload = [ + "PatientID" => "PX004", + "NameFirst" => "Johan", + "NameLast" => "Doe", + "Gender" => 1, + "Birthdate" => "1990-01-01", + "EmailAddress1" => "johnaa@examaple.com", + "Identity" => [ + "IdentifierType" => "KTP", + "Identifier" => "1232457893", + ], + "Attachments" => [ + ["Address" => "Jl. Mawar No.1"] + ], + "Comment" => "Pasien test" + ]; + + $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); + + $result->assertStatus(201); + $result->assertJSONFragment([ + "status" => "success", + "message" => "Patient created successfully" + ]); + + + // $data = json_decode($result->getBody(), true); + // $this->assertArrayHasKey("data", $data); + // $this->assertIsInt($data["data"]); // InternalPID + } + + // public function testCreatePatientValidationError() { + // $payload = [ + // "NameFirst" => "Jane" // PatientID kosong + // ]; + + // $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); + + // $result->assertStatus(422); + // $result->assertJSONFragment(["field" => "patient"]); + // } + + // public function testCreatePatidtValidationError() { + // $payload = [ + // "PatientID" => "PX002", + // "NameFirst" => "Jane", + // "Identity" => [ + // "IdentifierType" => null, + // "Identifier" => null + // ] + // ]; + + // $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); + + // $result->assertStatus(422); + // $result->assertJSONFragment(["field" => "patidt"]); + // } + + // public function testCreateWithoutAttachments() { + // $payload = [ + // "PatientID" => "PX003", + // "NameFirst" => "NoAttach", + // "Identity" => [ + // "IdentifierType" => "KTP", + // "Identifier" => "99999" + // ] + // ]; + + // $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); + + // $result->assertStatus(201); + // } + + // public function testCreateWithoutComment() { + // $payload = [ + // "PatientID" => "PX004", + // "NameFirst" => "NoComment", + // "Identity" => [ + // "IdentifierType" => "SIM", + // "Identifier" => "A12345" + // ], + // "Attachments" => [ + // ["Address" => "Jl. Melati No.2"] + // ] + // ]; + + // $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); + + // $result->assertStatus(201); + // } + + // public function testCreateDatabaseError() { + // // 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 + // $payload["NameFirst"] = "Second"; + // $payload["Identity"]["Identifier"] = "DBERR2"; + + // $result = $this->withBodyFormat('json')->post($this->endpoint, $payload); + + // $result->assertStatus(500); + // } + + // public function testCreateDuplicateIdentifier() { + // $payload = [ + // "PatientID" => "PX006", + // "NameFirst" => "Alpha", + // "Identity" => [ + // "IdentifierType" => "KTP", + // "Identifier" => "DUP123" + // ] + // ]; + // $this->withBodyFormat('json')->post($this->endpoint, $payload); + + // $payload2 = [ + // "PatientID" => "PX007", + // "NameFirst" => "Beta", + // "Identity" => [ + // "IdentifierType" => "KTP", + // "Identifier" => "DUP123" // Sama + // ] + // ]; + // $result = $this->withBodyFormat('json')->post($this->endpoint, $payload2); + + // $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); + // } } diff --git a/tests/feature/Patients/PatientDeleteTest.php b/tests/feature/Patients/PatientDeleteTest.php index 0bd73f2..b9bc567 100644 --- a/tests/feature/Patients/PatientDeleteTest.php +++ b/tests/feature/Patients/PatientDeleteTest.php @@ -1,6 +1,6 @@ 9999999 -// ]; -// $result = $this->withBodyFormat('json') -// ->withBody(json_encode($payload)) -// ->delete('api/patient'); + // 500 error catch + public function testDeleteWithoutInternalPID() { + $result = $this->withBodyFormat('json') + ->delete($this->endpoint, []); -// $result->assertStatus(404); -// $json = $result->getJSON(); // bentuk string JSON -// $json = json_decode($json, true); + $result->assertStatus(500); + $result->assertJSONFragment([ + 'status' => 500, + 'messages' => [ + 'error' => 'Internal server error: Undefined array key "InternalPID"' + ] + ]); + } -// $result->assertJSONFragment([ -// 'status' => 404, -// 'error' => 404 -// ]); -// } + // 400 + public function testDeleteWitWrongInternalPID() { + $result = $this->withBodyFormat('json') + ->delete($this->endpoint, [ + // Pilih salah satu + // 'InternalPID' => [], + // 'InternalPID' => 0, + // 'InternalPID' => '0', + // 'InternalPID' => '', + 'InternalPID' => null, + ]); -// public function testDeleteSuccess() { -// $payload = [ -// 'InternalPID' => 2 -// ]; -// $result = $this->withBodyFormat('json') -// ->withBody(json_encode($payload)) -// ->delete('api/patient'); - -// $result->assertStatus(200); -// $json = $result->getJSON(); // bentuk string JSON -// $json = json_decode($json, true); + $result->assertStatus(400); + $result->assertJSONFragment([ + 'status' => 'error', + 'message' => 'Patient ID must be a valid integer.' + ]); + } -// // $this->assertSame('Patient with ID 999999 not found.', $json['message']); -// $result->assertJSONFragment([ -// 'status' => 'success' -// ]); -// } + // 404 not found + public function testDeleteNotFound() { + $testId = 9999; + + $result = $this->withBodyFormat('json') + ->delete($this->endpoint, [ + 'InternalPID' => $testId + ]); + + $result->assertStatus(404); + $result->assertJSONFragment([ + 'status' => 404, + 'error' => 404, + 'messages' => [ + 'error' => 'Patient ID with '.$testId.' not found.' + ] + ]); + } + + // 200 ok + public function testDeleteSuccess() { + + $testId = 3; + // Anggap patient 1 2 3 ada di seed DB + $result = $this->withBodyFormat('json') + ->delete($this->endpoint, [ + 'InternalPID' => $testId + ]); + + $result->assertStatus(200); + $result->assertJSONFragment([ + 'status' => 'success', + 'message' => 'Patient ID with '.$testId.' deleted successfully.' + ]); + } + + // 400 - SQL Inject + public function testDeleteServerError() { + // Simulasi: kirim input aneh yang trigger exception + $result = $this->withBodyFormat('json') + ->delete($this->endpoint, [ + 'InternalPID' => "' OR 1=1 --" + ]); + $result->assertStatus(400); + $result->assertJSONFragment([ + 'status' => 'error', + 'message' => 'Patient ID must be a valid integer.' + ]); + } } diff --git a/tests/feature/Patients/PatientIndexTest.php b/tests/feature/Patients/PatientIndexTest.php index c0804f5..43f55da 100644 --- a/tests/feature/Patients/PatientIndexTest.php +++ b/tests/feature/Patients/PatientIndexTest.php @@ -1,6 +1,6 @@ call('get', $this->endpoint); $result->assertStatus(200); @@ -27,8 +26,7 @@ class PatientIndexTest extends CIUnitTestCase /** * Case 2: parameter Name yang tidak ada → return kosong [] */ - public function testIndexWithWrongNameParam() - { + public function testIndexWithWrongNameParam() { $result = $this->call('get', $this->endpoint, [ 'Name' => 'TidakAdaNama' ]); @@ -43,8 +41,7 @@ class PatientIndexTest extends CIUnitTestCase /** * Case 3: parameter Name benar → return array tidak kosong */ - public function testIndexWithCorrectNameParam() - { + public function testIndexWithCorrectNameParam() { // Sesuaikan dengan data di database test Anda $result = $this->call('get', $this->endpoint, [ 'Name' => 'Dummy' @@ -63,8 +60,7 @@ class PatientIndexTest extends CIUnitTestCase /** * Case 4: parameter InternalPID → return data sesuai ID */ - public function testIndexWithInternalPID() - { + public function testIndexWithInternalPID() { $result = $this->call('get', $this->endpoint, [ 'InternalPID' => 1 ]); @@ -83,8 +79,7 @@ class PatientIndexTest extends CIUnitTestCase /** * Case 5: parameter PatientID → return data sesuai PatientID */ - public function testIndexWithPatientID() - { + public function testIndexWithPatientID() { $result = $this->call('get', $this->endpoint, [ 'PatientID' => '123' ]); @@ -103,8 +98,7 @@ class PatientIndexTest extends CIUnitTestCase /** * Case 6: parameter Birthdate → return data sesuai tanggal */ - public function testIndexWithBirthdate() - { + public function testIndexWithBirthdate() { $result = $this->call('get', $this->endpoint, [ 'Birthdate' => '2000-01-01' ]); @@ -123,11 +117,10 @@ class PatientIndexTest extends CIUnitTestCase /** * Case 7: Simulasi server error (optional, jika bisa trigger) */ - public function testIndexServerErrorSimulation() - { + public function testIndexServerErrorSimulation() { // Misalnya panggil dengan param aneh untuk trigger exception $result = $this->call('get', $this->endpoint, [ - 'InternalPID' => "'asasa-" + 'InternalPID' => "' OR 1=2 --" ]); // dd([ diff --git a/tests/feature/Patients/PatientShowTest.php b/tests/feature/Patients/PatientShowTest.php index 1463636..bb22e05 100644 --- a/tests/feature/Patients/PatientShowTest.php +++ b/tests/feature/Patients/PatientShowTest.php @@ -1,6 +1,6 @@ call('get', 'api/patient/999999'); // ID yang tidak ada - - $result->assertStatus(200); - $json = $result->getJSON(); // bentuk string JSON - $json = json_decode($json, true); + protected $endpoint = 'api/patient'; - // $this->assertSame('Patient with ID 999999 not found.', $json['message']); + // 200 ok not found + public function testShowNotFound() { + $result = $this->get($this->endpoint . '/90909090'); + $result->assertStatus(200); $result->assertJSONFragment([ 'status' => 'success', + "message" => "Patient with ID 90909090 not found.", 'data' => [] ]); } - public function testShowFound() { - $result = $this->call('get', 'api/patient/1'); // ID yang tidak ada - + // 200 ok + public function testShowSingleRow() { + // Pastikan DB test punya seed patient InternalPID=10 tanpa id/addr + $result = $this->get($this->endpoint . '/1'); + $result->assertStatus(200); - $json = $result->getJSON(); - $data = json_decode($json, true); + $data = $result->getJSON(true); + $data = json_decode($data, true); $this->assertEquals('success', $data['status']); - $this->assertNotNull($data['data']); // data tidak null - $this->assertIsArray($data['data']); // data berupa array + // $this->assertNull($data['data']['Attachments']); } } diff --git a/tests/feature/Patients/PatientUpdateTest.php b/tests/feature/Patients/PatientUpdateTest.php index 7711807..141207c 100644 --- a/tests/feature/Patients/PatientUpdateTest.php +++ b/tests/feature/Patients/PatientUpdateTest.php @@ -1,6 +1,6 @@