feat(routes): add container alias endpoint for ContainerDefController
Added an alternative route alias 'container' that points to ContainerDefController, providing backward compatibility and flexibility in API endpoint naming. - Routes '/api/specimen/container' to ContainerDefController methods - Supports GET, GET with ID, POST, and PATCH operations - Existing '/api/specimen/containerdef' routes remain unchanged File: app/Config/Routes.php (+7 lines) --- refactor(seeds): update and standardize seed data across multiple seeders Improved data consistency and coverage in database seeds: AreaGeoSeeder.php: - Updated geographic area data for better regional coverage - Standardized data format and field values DummySeeder.php: - Refactored dummy data generation for test environments - Improved data integrity and relationships PatientSeeder.php: - Enhanced patient test data with more realistic scenarios - Updated patient demographic information - Improved test result distributions Total: 111 lines changed across seed files --- docs: add CLQMS project documentation - Added project documentation file: "prj_clinical laboratory quality management system_3a.docx" - Comprehensive project specification and requirements document --- test: remove deprecated TestDefSiteTest.php - Removed obsolete test file that is no longer needed - Test coverage consolidated into other test classes File: tests/feature/TestDef/TestDefSiteTest.php (-374 lines) --- Summary: - +58 lines added (routes, seeds, docs) - -434 lines removed (deprecated test file) - 6 files affected
This commit is contained in:
parent
a2097ade6a
commit
5fb572c122
@ -230,6 +230,13 @@ $routes->group('api', function ($routes) {
|
|||||||
|
|
||||||
// Specimen
|
// Specimen
|
||||||
$routes->group('specimen', function ($routes) {
|
$routes->group('specimen', function ($routes) {
|
||||||
|
// Container aliases - 'container' and 'containerdef' both point to ContainerDefController
|
||||||
|
$routes->group('container', function ($routes) {
|
||||||
|
$routes->get('/', 'Specimen\ContainerDefController::index');
|
||||||
|
$routes->get('(:num)', 'Specimen\ContainerDefController::show/$1');
|
||||||
|
$routes->post('/', 'Specimen\ContainerDefController::create');
|
||||||
|
$routes->patch('/', 'Specimen\ContainerDefController::update');
|
||||||
|
});
|
||||||
$routes->group('containerdef', function ($routes) {
|
$routes->group('containerdef', function ($routes) {
|
||||||
$routes->get('/', 'Specimen\ContainerDefController::index');
|
$routes->get('/', 'Specimen\ContainerDefController::index');
|
||||||
$routes->get('(:num)', 'Specimen\ContainerDefController::show/$1');
|
$routes->get('(:num)', 'Specimen\ContainerDefController::show/$1');
|
||||||
|
|||||||
@ -3,23 +3,36 @@
|
|||||||
namespace App\Database\Seeds;
|
namespace App\Database\Seeds;
|
||||||
|
|
||||||
use CodeIgniter\Database\Seeder;
|
use CodeIgniter\Database\Seeder;
|
||||||
|
use CodeIgniter\HTTP\CURLRequest;
|
||||||
|
|
||||||
class AreaGeoSeeder extends Seeder
|
class AreaGeoSeeder extends Seeder
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* External database configuration (same server)
|
* API configuration for fetching zones data
|
||||||
*/
|
*/
|
||||||
protected string $externalDbName = 'crm_v2';
|
protected string $apiUrl = 'https://your-api-domain.com/api/zones';
|
||||||
|
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
// Query external database directly using database.table syntax
|
// Fetch data from external API
|
||||||
$externalData = $this->db->query(
|
$options = [
|
||||||
"SELECT zonecode, zoneclass, zonename, parentzoneid FROM {$this->externalDbName}.zones ORDER BY zoneid ASC"
|
'baseURI' => $this->apiUrl,
|
||||||
)->getResultArray();
|
'timeout' => 30,
|
||||||
|
];
|
||||||
|
|
||||||
|
$client = new CURLRequest($options);
|
||||||
|
|
||||||
|
$response = $client->get('');
|
||||||
|
|
||||||
|
if ($response->getStatusCode() !== 200) {
|
||||||
|
echo "Failed to fetch data from API. Status: " . $response->getStatusCode() . "\n";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$externalData = $response->getJSON(true);
|
||||||
|
|
||||||
if (empty($externalData)) {
|
if (empty($externalData)) {
|
||||||
echo "No data found in external database.\n";
|
echo "No data found from API.\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,10 +40,10 @@ class AreaGeoSeeder extends Seeder
|
|||||||
$data = [];
|
$data = [];
|
||||||
foreach ($externalData as $row) {
|
foreach ($externalData as $row) {
|
||||||
$data[] = [
|
$data[] = [
|
||||||
'AreaCode' => $row['zonecode'],
|
'AreaCode' => $row['zonecode'] ?? null,
|
||||||
'Class' => $row['zoneclass'],
|
'Class' => $row['zoneclass'] ?? null,
|
||||||
'AreaName' => $row['zonename'],
|
'AreaName' => str_replace('_', ' ', $row['zonename'] ?? ''),
|
||||||
'Parent' => $row['parentzoneid'],
|
'Parent' => $row['parentzoneid'] ?? null,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,17 +4,18 @@ namespace App\Database\Seeds;
|
|||||||
|
|
||||||
use CodeIgniter\Database\Seeder;
|
use CodeIgniter\Database\Seeder;
|
||||||
|
|
||||||
class DummySeeder extends Seeder {
|
class DummySeeder extends Seeder
|
||||||
public function run() {
|
{
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
$now = date('Y-m-d H:i:s');
|
$now = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
// users
|
// users
|
||||||
// Password: 'password' for all users (bcrypt hash)
|
// Password: 'password' for all users (bcrypt hash)
|
||||||
$passwordHash = password_hash('password', PASSWORD_BCRYPT);
|
$passwordHash = password_hash('123', PASSWORD_BCRYPT);
|
||||||
$data = [
|
$data = [
|
||||||
['id' => 1, 'role_id' => 1, 'username' => 'zaka', 'password' => $passwordHash],
|
['id' => 1, 'role_id' => 1, 'username' => 'lisfse', 'password' => $passwordHash],
|
||||||
['id' => 2, 'role_id' => 1, 'username' => 'tes' , 'password' => $passwordHash],
|
['id' => 2, 'role_id' => 1, 'username' => 'tes', 'password' => $passwordHash]
|
||||||
['id' => 3, 'role_id' => 1, 'username' => 'tes2', 'password' => $passwordHash],
|
|
||||||
];
|
];
|
||||||
$this->db->table('users')->insertBatch($data);
|
$this->db->table('users')->insertBatch($data);
|
||||||
|
|
||||||
|
|||||||
@ -13,12 +13,12 @@ use CodeIgniter\Database\Seeder;
|
|||||||
* Run with: php spark db:seed PatientTestSeeder
|
* Run with: php spark db:seed PatientTestSeeder
|
||||||
* Or for test DB: php spark db:seed PatientTestSeeder --all --n tests
|
* Or for test DB: php spark db:seed PatientTestSeeder --all --n tests
|
||||||
*/
|
*/
|
||||||
class PatientSeeder extends Seeder
|
class PatientSeeder extends Seeder
|
||||||
{
|
{
|
||||||
public function run()
|
public function run()
|
||||||
{
|
{
|
||||||
$now = date('Y-m-d H:i:s');
|
$now = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
// ========================================
|
// ========================================
|
||||||
// 1. VALUESET - Required for joins
|
// 1. VALUESET - Required for joins
|
||||||
// ========================================
|
// ========================================
|
||||||
@ -27,38 +27,38 @@ class PatientSeeder extends Seeder
|
|||||||
['VID' => 5, 'SiteID' => 1, 'VSetID' => 1, 'VOrder' => 1, 'VValue' => 'M', 'VDesc' => 'Male', 'CreateDate' => $now],
|
['VID' => 5, 'SiteID' => 1, 'VSetID' => 1, 'VOrder' => 1, 'VValue' => 'M', 'VDesc' => 'Male', 'CreateDate' => $now],
|
||||||
['VID' => 6, 'SiteID' => 1, 'VSetID' => 1, 'VOrder' => 2, 'VValue' => 'F', 'VDesc' => 'Female', 'CreateDate' => $now],
|
['VID' => 6, 'SiteID' => 1, 'VSetID' => 1, 'VOrder' => 2, 'VValue' => 'F', 'VDesc' => 'Female', 'CreateDate' => $now],
|
||||||
['VID' => 7, 'SiteID' => 1, 'VSetID' => 1, 'VOrder' => 3, 'VValue' => 'O', 'VDesc' => 'Other', 'CreateDate' => $now],
|
['VID' => 7, 'SiteID' => 1, 'VSetID' => 1, 'VOrder' => 3, 'VValue' => 'O', 'VDesc' => 'Other', 'CreateDate' => $now],
|
||||||
|
|
||||||
// Marital Status (VSetID = 3)
|
// Marital Status (VSetID = 3)
|
||||||
['VID' => 8, 'SiteID' => 1, 'VSetID' => 3, 'VOrder' => 1, 'VValue' => 'S', 'VDesc' => 'Single', 'CreateDate' => $now],
|
['VID' => 8, 'SiteID' => 1, 'VSetID' => 3, 'VOrder' => 1, 'VValue' => 'S', 'VDesc' => 'Single', 'CreateDate' => $now],
|
||||||
['VID' => 9, 'SiteID' => 1, 'VSetID' => 3, 'VOrder' => 2, 'VValue' => 'M', 'VDesc' => 'Married', 'CreateDate' => $now],
|
['VID' => 9, 'SiteID' => 1, 'VSetID' => 3, 'VOrder' => 2, 'VValue' => 'M', 'VDesc' => 'Married', 'CreateDate' => $now],
|
||||||
['VID' => 10, 'SiteID' => 1, 'VSetID' => 3, 'VOrder' => 3, 'VValue' => 'D', 'VDesc' => 'Divorced', 'CreateDate' => $now],
|
['VID' => 10, 'SiteID' => 1, 'VSetID' => 3, 'VOrder' => 3, 'VValue' => 'D', 'VDesc' => 'Divorced', 'CreateDate' => $now],
|
||||||
['VID' => 11, 'SiteID' => 1, 'VSetID' => 3, 'VOrder' => 4, 'VValue' => 'W', 'VDesc' => 'Widowed', 'CreateDate' => $now],
|
['VID' => 11, 'SiteID' => 1, 'VSetID' => 3, 'VOrder' => 4, 'VValue' => 'W', 'VDesc' => 'Widowed', 'CreateDate' => $now],
|
||||||
|
|
||||||
// Death Indicator (VSetID = 4)
|
// Death Indicator (VSetID = 4)
|
||||||
['VID' => 16, 'SiteID' => 1, 'VSetID' => 4, 'VOrder' => 1, 'VValue' => 'Y', 'VDesc' => 'Deceased', 'CreateDate' => $now],
|
['VID' => 16, 'SiteID' => 1, 'VSetID' => 4, 'VOrder' => 1, 'VValue' => 'Y', 'VDesc' => 'Deceased', 'CreateDate' => $now],
|
||||||
['VID' => 17, 'SiteID' => 1, 'VSetID' => 4, 'VOrder' => 2, 'VValue' => 'N', 'VDesc' => 'Alive', 'CreateDate' => $now],
|
['VID' => 17, 'SiteID' => 1, 'VSetID' => 4, 'VOrder' => 2, 'VValue' => 'N', 'VDesc' => 'Alive', 'CreateDate' => $now],
|
||||||
|
|
||||||
// Race (VSetID = 5)
|
// Race (VSetID = 5)
|
||||||
['VID' => 175, 'SiteID' => 1, 'VSetID' => 5, 'VOrder' => 1, 'VValue' => 'AS', 'VDesc' => 'Asian', 'CreateDate' => $now],
|
['VID' => 175, 'SiteID' => 1, 'VSetID' => 5, 'VOrder' => 1, 'VValue' => 'AS', 'VDesc' => 'Asian', 'CreateDate' => $now],
|
||||||
['VID' => 176, 'SiteID' => 1, 'VSetID' => 5, 'VOrder' => 2, 'VValue' => 'WH', 'VDesc' => 'White', 'CreateDate' => $now],
|
['VID' => 176, 'SiteID' => 1, 'VSetID' => 5, 'VOrder' => 2, 'VValue' => 'WH', 'VDesc' => 'White', 'CreateDate' => $now],
|
||||||
|
|
||||||
// Religion (VSetID = 6)
|
// Religion (VSetID = 6)
|
||||||
['VID' => 206, 'SiteID' => 1, 'VSetID' => 6, 'VOrder' => 1, 'VValue' => 'IS', 'VDesc' => 'Islam', 'CreateDate' => $now],
|
['VID' => 206, 'SiteID' => 1, 'VSetID' => 6, 'VOrder' => 1, 'VValue' => 'IS', 'VDesc' => 'Islam', 'CreateDate' => $now],
|
||||||
['VID' => 207, 'SiteID' => 1, 'VSetID' => 6, 'VOrder' => 2, 'VValue' => 'CH', 'VDesc' => 'Christian', 'CreateDate' => $now],
|
['VID' => 207, 'SiteID' => 1, 'VSetID' => 6, 'VOrder' => 2, 'VValue' => 'CH', 'VDesc' => 'Christian', 'CreateDate' => $now],
|
||||||
['VID' => 208, 'SiteID' => 1, 'VSetID' => 6, 'VOrder' => 3, 'VValue' => 'CA', 'VDesc' => 'Catholic', 'CreateDate' => $now],
|
['VID' => 208, 'SiteID' => 1, 'VSetID' => 6, 'VOrder' => 3, 'VValue' => 'CA', 'VDesc' => 'Catholic', 'CreateDate' => $now],
|
||||||
['VID' => 209, 'SiteID' => 1, 'VSetID' => 6, 'VOrder' => 4, 'VValue' => 'HI', 'VDesc' => 'Hindu', 'CreateDate' => $now],
|
['VID' => 209, 'SiteID' => 1, 'VSetID' => 6, 'VOrder' => 4, 'VValue' => 'HI', 'VDesc' => 'Hindu', 'CreateDate' => $now],
|
||||||
['VID' => 210, 'SiteID' => 1, 'VSetID' => 6, 'VOrder' => 5, 'VValue' => 'BU', 'VDesc' => 'Buddha', 'CreateDate' => $now],
|
['VID' => 210, 'SiteID' => 1, 'VSetID' => 6, 'VOrder' => 5, 'VValue' => 'BU', 'VDesc' => 'Buddha', 'CreateDate' => $now],
|
||||||
|
|
||||||
// Ethnic (VSetID = 7)
|
// Ethnic (VSetID = 7)
|
||||||
['VID' => 213, 'SiteID' => 1, 'VSetID' => 7, 'VOrder' => 1, 'VValue' => 'JV', 'VDesc' => 'Javanese', 'CreateDate' => $now],
|
['VID' => 213, 'SiteID' => 1, 'VSetID' => 7, 'VOrder' => 1, 'VValue' => 'JV', 'VDesc' => 'Javanese', 'CreateDate' => $now],
|
||||||
['VID' => 214, 'SiteID' => 1, 'VSetID' => 7, 'VOrder' => 2, 'VValue' => 'SD', 'VDesc' => 'Sundanese', 'CreateDate' => $now],
|
['VID' => 214, 'SiteID' => 1, 'VSetID' => 7, 'VOrder' => 2, 'VValue' => 'SD', 'VDesc' => 'Sundanese', 'CreateDate' => $now],
|
||||||
['VID' => 215, 'SiteID' => 1, 'VSetID' => 7, 'VOrder' => 3, 'VValue' => 'BT', 'VDesc' => 'Batak', 'CreateDate' => $now],
|
['VID' => 215, 'SiteID' => 1, 'VSetID' => 7, 'VOrder' => 3, 'VValue' => 'BT', 'VDesc' => 'Batak', 'CreateDate' => $now],
|
||||||
|
|
||||||
// Country (VSetID = 8)
|
// Country (VSetID = 8)
|
||||||
['VID' => 221, 'SiteID' => 1, 'VSetID' => 8, 'VOrder' => 1, 'VValue' => 'ID', 'VDesc' => 'Indonesia', 'CreateDate' => $now],
|
['VID' => 221, 'SiteID' => 1, 'VSetID' => 8, 'VOrder' => 1, 'VValue' => 'ID', 'VDesc' => 'Indonesia', 'CreateDate' => $now],
|
||||||
['VID' => 222, 'SiteID' => 1, 'VSetID' => 8, 'VOrder' => 2, 'VValue' => 'MY', 'VDesc' => 'Malaysia', 'CreateDate' => $now],
|
['VID' => 222, 'SiteID' => 1, 'VSetID' => 8, 'VOrder' => 2, 'VValue' => 'MY', 'VDesc' => 'Malaysia', 'CreateDate' => $now],
|
||||||
['VID' => 223, 'SiteID' => 1, 'VSetID' => 8, 'VOrder' => 3, 'VValue' => 'SG', 'VDesc' => 'Singapore', 'CreateDate' => $now],
|
['VID' => 223, 'SiteID' => 1, 'VSetID' => 8, 'VOrder' => 3, 'VValue' => 'SG', 'VDesc' => 'Singapore', 'CreateDate' => $now],
|
||||||
|
|
||||||
// Link Type (VSetID = 9)
|
// Link Type (VSetID = 9)
|
||||||
['VID' => 2, 'SiteID' => 1, 'VSetID' => 9, 'VOrder' => 1, 'VValue' => 'F', 'VDesc' => 'Family', 'CreateDate' => $now],
|
['VID' => 2, 'SiteID' => 1, 'VSetID' => 9, 'VOrder' => 1, 'VValue' => 'F', 'VDesc' => 'Family', 'CreateDate' => $now],
|
||||||
['VID' => 3, 'SiteID' => 1, 'VSetID' => 9, 'VOrder' => 2, 'VValue' => 'S', 'VDesc' => 'Spouse', 'CreateDate' => $now],
|
['VID' => 3, 'SiteID' => 1, 'VSetID' => 9, 'VOrder' => 2, 'VValue' => 'S', 'VDesc' => 'Spouse', 'CreateDate' => $now],
|
||||||
@ -74,30 +74,7 @@ class PatientSeeder extends Seeder
|
|||||||
echo "Valueset data seeded.\n";
|
echo "Valueset data seeded.\n";
|
||||||
|
|
||||||
// ========================================
|
// ========================================
|
||||||
// 2. AREAGEO - Province & City
|
// 2. PATIENT - Main patient data
|
||||||
// ========================================
|
|
||||||
$areageos = [
|
|
||||||
['AreaGeoID' => 1, 'AreaCode' => '31', 'Class' => 1, 'AreaName' => 'DKI Jakarta', 'Parent' => null],
|
|
||||||
['AreaGeoID' => 2, 'AreaCode' => '3101', 'Class' => 2, 'AreaName' => 'Jakarta Pusat', 'Parent' => 1],
|
|
||||||
['AreaGeoID' => 3, 'AreaCode' => '3102', 'Class' => 2, 'AreaName' => 'Jakarta Utara', 'Parent' => 1],
|
|
||||||
['AreaGeoID' => 4, 'AreaCode' => '3103', 'Class' => 2, 'AreaName' => 'Jakarta Barat', 'Parent' => 1],
|
|
||||||
['AreaGeoID' => 5, 'AreaCode' => '3104', 'Class' => 2, 'AreaName' => 'Jakarta Selatan', 'Parent' => 1],
|
|
||||||
['AreaGeoID' => 6, 'AreaCode' => '3105', 'Class' => 2, 'AreaName' => 'Jakarta Timur', 'Parent' => 1],
|
|
||||||
['AreaGeoID' => 7, 'AreaCode' => '32', 'Class' => 1, 'AreaName' => 'Jawa Barat', 'Parent' => null],
|
|
||||||
['AreaGeoID' => 8, 'AreaCode' => '3201', 'Class' => 2, 'AreaName' => 'Bandung', 'Parent' => 7],
|
|
||||||
['AreaGeoID' => 9, 'AreaCode' => '3202', 'Class' => 2, 'AreaName' => 'Bogor', 'Parent' => 7],
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($areageos as $area) {
|
|
||||||
$exists = $this->db->table('areageo')->where('AreaGeoID', $area['AreaGeoID'])->get()->getRow();
|
|
||||||
if (!$exists) {
|
|
||||||
$this->db->table('areageo')->insert($area);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
echo "AreaGeo data seeded.\n";
|
|
||||||
|
|
||||||
// ========================================
|
|
||||||
// 3. PATIENT - Main patient data
|
|
||||||
// ========================================
|
// ========================================
|
||||||
$patients = [
|
$patients = [
|
||||||
[
|
[
|
||||||
@ -111,14 +88,14 @@ class PatientSeeder extends Seeder
|
|||||||
'NameLast' => 'Patient',
|
'NameLast' => 'Patient',
|
||||||
'Suffix' => 'S.Kom',
|
'Suffix' => 'S.Kom',
|
||||||
'NameAlias' => 'DummyTest',
|
'NameAlias' => 'DummyTest',
|
||||||
'Gender' => 5, // Male
|
'Gender' => 5,
|
||||||
'PlaceOfBirth' => 'Jakarta',
|
'PlaceOfBirth' => 'Jakarta',
|
||||||
'Birthdate' => '1990-05-15',
|
'Birthdate' => '1990-05-15',
|
||||||
'Street_1' => 'Jl. Sudirman No. 123',
|
'Street_1' => 'Jl. Sudirman No. 123',
|
||||||
'Street_2' => 'RT 01 RW 02',
|
'Street_2' => 'RT 01 RW 02',
|
||||||
'Street_3' => 'Kelurahan Menteng',
|
'Street_3' => 'Kelurahan Menteng',
|
||||||
'City' => '2', // Jakarta Pusat
|
'City' => '2',
|
||||||
'Province' => '1', // DKI Jakarta
|
'Province' => '1',
|
||||||
'ZIP' => '10110',
|
'ZIP' => '10110',
|
||||||
'EmailAddress1' => 'dummy1@test.com',
|
'EmailAddress1' => 'dummy1@test.com',
|
||||||
'EmailAddress2' => 'dummy1alt@test.com',
|
'EmailAddress2' => 'dummy1alt@test.com',
|
||||||
@ -126,13 +103,13 @@ class PatientSeeder extends Seeder
|
|||||||
'MobilePhone' => '081234567890',
|
'MobilePhone' => '081234567890',
|
||||||
'Custodian' => null,
|
'Custodian' => null,
|
||||||
'AccountNumber' => null,
|
'AccountNumber' => null,
|
||||||
'Country' => 221, // Indonesia
|
'Country' => 221,
|
||||||
'Race' => 175, // Asian
|
'Race' => 175,
|
||||||
'MaritalStatus' => 9, // Married
|
'MaritalStatus' => 9,
|
||||||
'Religion' => 206, // Islam
|
'Religion' => 206,
|
||||||
'Ethnic' => 213, // Javanese
|
'Ethnic' => 213,
|
||||||
'Citizenship' => 'WNI',
|
'Citizenship' => 'WNI',
|
||||||
'DeathIndicator' => 17, // Alive
|
'DeathIndicator' => 17,
|
||||||
'TimeOfDeath' => null,
|
'TimeOfDeath' => null,
|
||||||
'LinkTo' => null,
|
'LinkTo' => null,
|
||||||
'CreateDate' => $now,
|
'CreateDate' => $now,
|
||||||
|
|||||||
BIN
docs/prj_clinical laboratory quality management system_3a.docx
Normal file
BIN
docs/prj_clinical laboratory quality management system_3a.docx
Normal file
Binary file not shown.
@ -1,374 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Tests\Feature\TestDef;
|
|
||||||
|
|
||||||
use CodeIgniter\Test\CIUnitTestCase;
|
|
||||||
use CodeIgniter\Test\DatabaseTestTrait;
|
|
||||||
use App\Models\Test\TestDefSiteModel;
|
|
||||||
use App\Models\Test\TestDefTechModel;
|
|
||||||
use App\Models\Test\TestDefCalModel;
|
|
||||||
use App\Models\Test\TestDefGrpModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Integration tests for Test Definitions API
|
|
||||||
*
|
|
||||||
* Tests the CRUD operations for test definitions through the API
|
|
||||||
*/
|
|
||||||
class TestDefSiteTest extends CIUnitTestCase
|
|
||||||
{
|
|
||||||
use DatabaseTestTrait;
|
|
||||||
|
|
||||||
protected $seed = 'App\Database\Seeds\TestSeeder';
|
|
||||||
protected $refresh = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test listing all tests returns success response
|
|
||||||
*/
|
|
||||||
public function testIndexReturnsSuccessResponse(): void
|
|
||||||
{
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get('api/tests');
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$result->assertJSONExact([
|
|
||||||
'status' => 'success',
|
|
||||||
'message' => 'Data fetched successfully',
|
|
||||||
'data' => $result->getJSON(true)['data']
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test listing all tests returns array
|
|
||||||
*/
|
|
||||||
public function testIndexReturnsArray(): void
|
|
||||||
{
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get('api/tests');
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
$this->assertIsArray($response['data']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test index contains test type information
|
|
||||||
*/
|
|
||||||
public function testIndexContainsTypeInformation(): void
|
|
||||||
{
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get('api/tests');
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
|
|
||||||
if (!empty($response['data'])) {
|
|
||||||
$test = $response['data'][0];
|
|
||||||
$this->assertArrayHasKey('TypeCode', $test);
|
|
||||||
$this->assertArrayHasKey('TypeName', $test);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test filtering by test type
|
|
||||||
*/
|
|
||||||
public function testIndexFiltersByTestType(): void
|
|
||||||
{
|
|
||||||
// Test filtering by TEST type (VID = 1)
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get('api/tests?TestType=1');
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
|
|
||||||
foreach ($response['data'] as $test) {
|
|
||||||
$this->assertEquals('TEST', $test['TypeCode']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test filtering by keyword
|
|
||||||
*/
|
|
||||||
public function testIndexFiltersByKeyword(): void
|
|
||||||
{
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get('api/tests?TestSiteName=HB');
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
|
|
||||||
if (!empty($response['data'])) {
|
|
||||||
foreach ($response['data'] as $test) {
|
|
||||||
$this->assertStringContainsString('HB', $test['TestSiteName']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test showing single test returns success
|
|
||||||
*/
|
|
||||||
public function testShowReturnsSuccess(): void
|
|
||||||
{
|
|
||||||
// Get a test ID from the seeder data
|
|
||||||
$model = new TestDefSiteModel();
|
|
||||||
$test = $model->first();
|
|
||||||
|
|
||||||
if ($test) {
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get("api/tests/{$test['TestSiteID']}");
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
$this->assertArrayHasKey('data', $response);
|
|
||||||
} else {
|
|
||||||
$this->markTestSkipped('No test data available');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test showing single test includes type-specific details for TEST type
|
|
||||||
*/
|
|
||||||
public function testShowIncludesTechDetailsForTestType(): void
|
|
||||||
{
|
|
||||||
$model = new TestDefSiteModel();
|
|
||||||
$test = $model->first();
|
|
||||||
|
|
||||||
if ($test && $test['TypeCode'] === 'TEST') {
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get("api/tests/{$test['TestSiteID']}");
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
$this->assertArrayHasKey('testdeftech', $response['data']);
|
|
||||||
} else {
|
|
||||||
$this->markTestSkipped('No TEST type data available');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test showing single test includes type-specific details for CALC type
|
|
||||||
*/
|
|
||||||
public function testShowIncludesCalcDetailsForCalcType(): void
|
|
||||||
{
|
|
||||||
$model = new TestDefSiteModel();
|
|
||||||
$test = $model->first();
|
|
||||||
|
|
||||||
if ($test && $test['TypeCode'] === 'CALC') {
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get("api/tests/{$test['TestSiteID']}");
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
$this->assertArrayHasKey('testdefcal', $response['data']);
|
|
||||||
} else {
|
|
||||||
$this->markTestSkipped('No CALC type data available');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test showing single test includes type-specific details for GROUP type
|
|
||||||
*/
|
|
||||||
public function testShowIncludesGrpDetailsForGroupType(): void
|
|
||||||
{
|
|
||||||
$model = new TestDefSiteModel();
|
|
||||||
$test = $model->first();
|
|
||||||
|
|
||||||
if ($test && $test['TypeCode'] === 'GROUP') {
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get("api/tests/{$test['TestSiteID']}");
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
$this->assertArrayHasKey('testdefgrp', $response['data']);
|
|
||||||
} else {
|
|
||||||
$this->markTestSkipped('No GROUP type data available');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creating a new test
|
|
||||||
*/
|
|
||||||
public function testCreateTest(): void
|
|
||||||
{
|
|
||||||
$testData = [
|
|
||||||
'SiteID' => 1,
|
|
||||||
'TestSiteCode' => 'NEWTEST',
|
|
||||||
'TestSiteName' => 'New Test',
|
|
||||||
'TestType' => 1, // TEST type
|
|
||||||
'Description' => 'Test description',
|
|
||||||
'SeqScr' => 100,
|
|
||||||
'SeqRpt' => 100,
|
|
||||||
'VisibleScr' => 1,
|
|
||||||
'VisibleRpt' => 1,
|
|
||||||
'CountStat' => 1
|
|
||||||
];
|
|
||||||
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->post('api/tests', $testData);
|
|
||||||
|
|
||||||
$result->assertStatus(201);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
$this->assertArrayHasKey('data', $response);
|
|
||||||
$this->assertArrayHasKey('TestSiteId', $response['data']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test creating test with validation error (missing required fields)
|
|
||||||
*/
|
|
||||||
public function testCreateTestValidationError(): void
|
|
||||||
{
|
|
||||||
$testData = [
|
|
||||||
'SiteID' => 1
|
|
||||||
// Missing required fields
|
|
||||||
];
|
|
||||||
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->post('api/tests', $testData);
|
|
||||||
|
|
||||||
$result->assertStatus(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test updating a test
|
|
||||||
*/
|
|
||||||
public function testUpdateTest(): void
|
|
||||||
{
|
|
||||||
$model = new TestDefSiteModel();
|
|
||||||
$test = $model->first();
|
|
||||||
|
|
||||||
if ($test) {
|
|
||||||
$updateData = [
|
|
||||||
'TestSiteID' => $test['TestSiteID'],
|
|
||||||
'TestSiteName' => 'Updated Test Name',
|
|
||||||
'Description' => 'Updated description'
|
|
||||||
];
|
|
||||||
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->patch('api/tests', $updateData);
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
$this->assertEquals('success', $response['status']);
|
|
||||||
} else {
|
|
||||||
$this->markTestSkipped('No test data available');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test deleting a test (soft delete)
|
|
||||||
*/
|
|
||||||
public function testDeleteTest(): void
|
|
||||||
{
|
|
||||||
$model = new TestDefSiteModel();
|
|
||||||
$test = $model->first();
|
|
||||||
|
|
||||||
if ($test) {
|
|
||||||
$deleteData = [
|
|
||||||
'TestSiteID' => $test['TestSiteID']
|
|
||||||
];
|
|
||||||
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->delete('api/tests', $deleteData);
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
$this->assertEquals('success', $response['status']);
|
|
||||||
$this->assertArrayHasKey('EndDate', $response['data']);
|
|
||||||
} else {
|
|
||||||
$this->markTestSkipped('No test data available');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test getting non-existent test returns empty data
|
|
||||||
*/
|
|
||||||
public function testShowNonExistentTest(): void
|
|
||||||
{
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get('api/tests/999999');
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
$this->assertNull($response['data']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test test types are correctly mapped from valueset
|
|
||||||
*/
|
|
||||||
public function testTestTypesAreMapped(): void
|
|
||||||
{
|
|
||||||
$model = new TestDefSiteModel();
|
|
||||||
$tests = $model->findAll();
|
|
||||||
|
|
||||||
$validTypes = ['TEST', 'PARAM', 'CALC', 'GROUP', 'TITLE'];
|
|
||||||
|
|
||||||
foreach ($tests as $test) {
|
|
||||||
if (isset($test['TypeCode'])) {
|
|
||||||
$this->assertContains($test['TypeCode'], $validTypes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test filtering by visible on screen
|
|
||||||
*/
|
|
||||||
public function testIndexFiltersByVisibleScr(): void
|
|
||||||
{
|
|
||||||
$result = $this->withHeaders([
|
|
||||||
'Content-Type' => 'application/json',
|
|
||||||
'Accept' => 'application/json'
|
|
||||||
])->get('api/tests?VisibleScr=1');
|
|
||||||
|
|
||||||
$result->assertStatus(200);
|
|
||||||
$response = $result->getJSON(true);
|
|
||||||
|
|
||||||
foreach ($response['data'] as $test) {
|
|
||||||
$this->assertEquals(1, $test['VisibleScr']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test all test types from seeder are present
|
|
||||||
*/
|
|
||||||
public function testAllTestTypesArePresent(): void
|
|
||||||
{
|
|
||||||
$model = new TestDefSiteModel();
|
|
||||||
$tests = $model->findAll();
|
|
||||||
|
|
||||||
$typeCodes = array_column($tests, 'TypeCode');
|
|
||||||
$uniqueTypes = array_unique($typeCodes);
|
|
||||||
|
|
||||||
// Check that we have at least TEST and PARAM types from seeder
|
|
||||||
$this->assertContains('TEST', $uniqueTypes);
|
|
||||||
$this->assertContains('PARAM', $uniqueTypes);
|
|
||||||
$this->assertContains('CALC', $uniqueTypes);
|
|
||||||
$this->assertContains('GROUP', $uniqueTypes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user