diff --git a/resources/views/informasi/potensi/create.blade.php b/resources/views/informasi/potensi/create.blade.php
index 10094ea7e..27bdda51a 100644
--- a/resources/views/informasi/potensi/create.blade.php
+++ b/resources/views/informasi/potensi/create.blade.php
@@ -21,7 +21,7 @@
{!! html()->form('POST', route('informasi.potensi.store'))->acceptsFiles()->id('form-potensi')->class(
'form-horizontal
- form-label-left',
+ form-label-left',
)->open() !!}
@if (count($errors) > 0)
diff --git a/resources/views/informasi/prosedur/create.blade.php b/resources/views/informasi/prosedur/create.blade.php
index fcf9cadf9..da37cd2dc 100644
--- a/resources/views/informasi/prosedur/create.blade.php
+++ b/resources/views/informasi/prosedur/create.blade.php
@@ -21,7 +21,7 @@
{!! html()->form('POST', route('informasi.prosedur.store'))->acceptsFiles()->id('form-prosedur')->class(
'form-horizontal
- form-label-left',
+ form-label-left',
)->open() !!}
@if (count($errors) > 0)
diff --git a/resources/views/informasi/regulasi/create.blade.php b/resources/views/informasi/regulasi/create.blade.php
index 37654c12c..7220655f4 100644
--- a/resources/views/informasi/regulasi/create.blade.php
+++ b/resources/views/informasi/regulasi/create.blade.php
@@ -19,7 +19,7 @@
{!! html()->form('POST', route('informasi.regulasi.store'))->id('form-regulasi')->class(
'form-horizontal
- form-label-left',
+ form-label-left',
)->acceptsFiles()->open() !!}
diff --git a/resources/views/informasi/sinergi_program/create.blade.php b/resources/views/informasi/sinergi_program/create.blade.php
index 9d38c6886..9d163bccf 100644
--- a/resources/views/informasi/sinergi_program/create.blade.php
+++ b/resources/views/informasi/sinergi_program/create.blade.php
@@ -19,7 +19,7 @@
{!! html()->form('POST', route('informasi.sinergi-program.store'))->acceptsFiles()->id('form-sinergi-program')->class(
'form-horizontal
- form-label-left',
+ form-label-left',
)->open() !!}
diff --git a/resources/views/informasi/sinergi_program/edit.blade.php b/resources/views/informasi/sinergi_program/edit.blade.php
index 13b94aa68..1d68ce2ac 100644
--- a/resources/views/informasi/sinergi_program/edit.blade.php
+++ b/resources/views/informasi/sinergi_program/edit.blade.php
@@ -32,7 +32,7 @@
{!! html()->form('PUT', route('informasi.sinergi-program.update', $sinergi->id))->id('form-sinergi-program')->class(
'form-horizontal
- form-label-left',
+ form-label-left',
)->acceptsFiles()->open() !!}
diff --git a/resources/views/pesan/masuk/index.blade.php b/resources/views/pesan/masuk/index.blade.php
index 86e144b3f..ea30f8041 100644
--- a/resources/views/pesan/masuk/index.blade.php
+++ b/resources/views/pesan/masuk/index.blade.php
@@ -46,7 +46,7 @@
{!! html()->form('POST', route('pesan.arsip.multiple'))->class(
'form-group
- inline',
+ inline',
)->id('form-multiple-arsip-pesan')->open() !!}
{!! html()->hidden('array_id')->id('array_multiple_id_arsip') !!}
@@ -54,7 +54,7 @@
{!! html()->form('POST', route('pesan.read.multiple'))->class(
'form-group
- inline',
+ inline',
)->id('form-multiple-read-pesan')->open() !!}
{!! html()->hidden('array_id')->id('array_multiple_id') !!}
@@ -88,7 +88,8 @@
- {{ $pesan->custom_date }} |
+ {{ $pesan->custom_date }}
+
@endforeach
diff --git a/resources/views/pesan/read_pesan.blade.php b/resources/views/pesan/read_pesan.blade.php
index 840e2f9f8..812f96554 100644
--- a/resources/views/pesan/read_pesan.blade.php
+++ b/resources/views/pesan/read_pesan.blade.php
@@ -28,7 +28,7 @@
@if ($pesan->diarsipkan === 0)
{!! html()->form('POST', route('pesan.arsip.post'))->class(
'form-group
- inline',
+ inline',
)->id('form-arisp-pesan')->open() !!}
{!! html()->hidden('id', $pesan->id) !!}
@@ -77,11 +77,11 @@
diff --git a/resources/views/setting/aplikasi/form.blade.php b/resources/views/setting/aplikasi/form.blade.php
index 169cc7aa9..1ff106022 100644
--- a/resources/views/setting/aplikasi/form.blade.php
+++ b/resources/views/setting/aplikasi/form.blade.php
@@ -28,7 +28,7 @@
{!! html()->select('value', [
'OpenStreetMap' => 'OpenStreetMap',
'OpenStreetMap H.O.T.' => 'OpenStreetMap
- H.O.T.',
+ H.O.T.',
'Mapbox Streets' => 'Mapbox Streets',
'Mapbox Satellite' => 'Mapbox Satellite',
'Mapbox Satellite-Streets' => 'Mapbox Satellite-Streets',
diff --git a/resources/views/setting/slide/form.blade.php b/resources/views/setting/slide/form.blade.php
index 51e89ca4d..585e43f14 100644
--- a/resources/views/setting/slide/form.blade.php
+++ b/resources/views/setting/slide/form.blade.php
@@ -9,7 +9,7 @@
{!! html()->textarea('deskripsi')->class('textarea')->style(
'width: 100%; height: 200px; font-size: 14px;
- line-height: 18px; border: 1px solid #dddddd; padding: 10px;',
+ line-height: 18px; border: 1px solid #dddddd; padding: 10px;',
)->placeholder('deskripsi')->value(old('deskripsi', isset($slide) ? $slide->deskripsi : '')) !!}
diff --git a/routes/web.php b/routes/web.php
index f16e6e8cb..c888b6ce1 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -519,7 +519,7 @@
Route::group(['prefix' => 'data-desa', 'middleware' => ['action_permission:access.data.data_desa']], function () {
Route::put('update/{id}', ['as' => 'data.data-desa.update', 'uses' => 'DataDesaController@update']);
Route::get('/', ['as' => 'data.data-desa.index', 'uses' => 'DataDesaController@index']);
- Route::get('getdata', ['as' => 'data.data-desa.getdata', 'uses' => 'DataDesaController@getDataDesa']);
+ Route::match(['GET', 'POST'], 'getdata', ['as' => 'data.data-desa.getdata', 'uses' => 'DataDesaController@getDataDesa']);
Route::get('getdata/ajax', ['as' => 'data.data-desa.getdataajax', 'uses' => 'DataDesaController@getDataDesaAjax']);
Route::post('getdesa', ['as' => 'data.data-desa.getdesa', 'uses' => 'DataDesaController@getDesaKecamatan']);
Route::get('peta/{id}', ['as' => 'data.data-desa.peta', 'uses' => 'DataDesaController@peta']);
@@ -533,7 +533,7 @@
// Data Sarana
Route::group(['prefix' => 'data-sarana', 'excluded_middleware' => 'xss_sanitization', 'middleware' => ['action_permission:access.data.data_sarana']], function () {
Route::get('/', ['as' => 'data.data-sarana.index', 'uses' => 'DataSaranaController@index']);
- Route::get('getdata', ['as' => 'data.data-sarana.getdata', 'uses' => 'DataSaranaController@getData']);
+ Route::match(['GET', 'POST'], 'getdata', ['as' => 'data.data-sarana.getdata', 'uses' => 'DataSaranaController@getData']);
Route::get('create', ['as' => 'data.data-sarana.create', 'uses' => 'DataSaranaController@create']);
Route::post('store', ['as' => 'data.data-sarana.store', 'uses' => 'DataSaranaController@store']);
Route::get('edit/{id}', ['as' => 'data.data-sarana.edit', 'uses' => 'DataSaranaController@edit']);
@@ -545,9 +545,11 @@
// Jabatan
Route::resource('jabatan', 'JabatanController', ['as' => 'data'])->middleware(['action_permission:access.data.jabatan'])->except(['show']);
+ Route::post('jabatan', ['as' => 'data.jabatan.getdata.post', 'uses' => 'JabatanController@index'])->middleware(['action_permission:access.data.jabatan']);
// Pengurus
Route::post('pengurus/lock/{id}/{status}', ['as' => 'data.pengurus.lock', 'uses' => 'PengurusController@lock'])->middleware(['action_permission:access.data.pengurus']);
+ Route::post('pengurus/getdata', ['as' => 'data.pengurus.getdata.post', 'uses' => 'PengurusController@index'])->middleware(['action_permission:access.data.pengurus']);
Route::resource('pengurus', 'PengurusController', ['as' => 'data'])->middleware(['action_permission:access.data.pengurus'])->except(['show']);
Route::get('pengurus/bagan', ['as' => 'data.pengurus.bagan', 'uses' => 'PengurusController@bagan'])->middleware(['action_permission:access.data.pengurus']);
Route::get('pengurus/ajax-bagan', ['as' => 'data.pengurus.ajax-bagan', 'uses' => 'PengurusController@ajaxBagan'])->middleware(['action_permission:access.data.pengurus']);
@@ -566,7 +568,7 @@
// Penduduk
Route::group(['prefix' => 'penduduk', 'middleware' => ['action_permission:access.data.penduduk']], function () {
Route::get('/', ['as' => 'data.penduduk.index', 'uses' => 'PendudukController@index']);
- Route::get('getdata', ['as' => 'data.penduduk.getdata', 'uses' => 'PendudukController@getPenduduk']);
+ Route::match(['GET', 'POST'], 'getdata', ['as' => 'data.penduduk.getdata', 'uses' => 'PendudukController@getPenduduk']);
Route::get('show/{id}', ['as' => 'data.penduduk.show', 'uses' => 'PendudukController@show']);
Route::get('import', ['as' => 'data.penduduk.import', 'uses' => 'PendudukController@import']);
Route::post('import-excel', ['as' => 'data.penduduk.import-excel', 'uses' => 'PendudukController@importExcel']);
@@ -577,7 +579,7 @@
// Keluarga
Route::group(['prefix' => 'keluarga', 'middleware' => ['action_permission:access.data.keluarga']], function () {
Route::get('/', ['as' => 'data.keluarga.index', 'uses' => 'KeluargaController@index']);
- Route::get('getdata', ['as' => 'data.keluarga.getdata', 'uses' => 'KeluargaController@getKeluarga']);
+ Route::match(['GET', 'POST'], 'getdata', ['as' => 'data.keluarga.getdata', 'uses' => 'KeluargaController@getKeluarga']);
Route::get('show/{id}', ['as' => 'data.keluarga.show', 'uses' => 'KeluargaController@show']);
Route::get('export-excel', ['as' => 'data.keluarga.export-excel', 'uses' => 'KeluargaController@exportExcel']);
});
@@ -585,15 +587,15 @@
// Data Suplemen
Route::group(['prefix' => 'data-suplemen', 'middleware' => ['action_permission:access.data.data_suplemen']], function () {
Route::get('/', ['as' => 'data.data-suplemen.index', 'uses' => 'SuplemenController@index']);
- Route::get('getdata', ['as' => 'data.data-suplemen.getdata', 'uses' => 'SuplemenController@getDataSuplemen']);
- Route::get('getsuplementerdata', ['as' => 'data.data-suplemen.getsuplementerdata', 'uses' => 'SuplemenController@getDataSuplemenTerdata']);
+ Route::match(['GET', 'POST'], 'getdata', ['as' => 'data.data-suplemen.getdata', 'uses' => 'SuplemenController@getDataSuplemen']);
+ Route::match(['GET', 'POST'], 'getsuplementerdata', ['as' => 'data.data-suplemen.getsuplementerdata', 'uses' => 'SuplemenController@getDataSuplemenTerdata']);
Route::get('show/{id}', ['as' => 'data.data-suplemen.show', 'uses' => 'SuplemenController@show']);
Route::get('create', ['as' => 'data.data-suplemen.create', 'uses' => 'SuplemenController@create']);
Route::post('store', ['as' => 'data.data-suplemen.store', 'uses' => 'SuplemenController@store']);
Route::get('edit/{id}', ['as' => 'data.data-suplemen.edit', 'uses' => 'SuplemenController@edit']);
Route::put('update/{id}', ['as' => 'data.data-suplemen.update', 'uses' => 'SuplemenController@update']);
Route::delete('destroy/{id}', ['as' => 'data.data-suplemen.destroy', 'uses' => 'SuplemenController@destroy']);
- Route::get('getsuplementerdata/{id_suplemen}', ['as' => 'data.data-suplemen.getsuplementerdata', 'uses' => 'SuplemenController@getDataSuplemenTerdata']);
+ Route::match(['GET', 'POST'], 'getsuplementerdata/{id_suplemen}', ['as' => 'data.data-suplemen.getsuplementerdata', 'uses' => 'SuplemenController@getDataSuplemenTerdata']);
Route::get('createdetail/{id_suplemen}', ['as' => 'data.data-suplemen.createdetail', 'uses' => 'SuplemenController@createDetail']);
Route::get('getpenduduk/{id_desa}/{id_suplemen}', ['as' => 'data.data-suplemen.getpenduduk', 'uses' => 'SuplemenController@getPenduduk']);
Route::post('storedetail', ['as' => 'data.data-suplemen.storedetail', 'uses' => 'SuplemenController@storeDetail']);
@@ -607,7 +609,7 @@
// Laporan Penduduk
Route::group(['prefix' => 'laporan-penduduk', 'middleware' => ['action_permission:access.data.laporan_penduduk']], function () {
Route::get('/', ['as' => 'data.laporan-penduduk.index', 'uses' => 'LaporanPendudukController@index']);
- Route::get('getdata', ['as' => 'data.laporan-penduduk.getdata', 'uses' => 'LaporanPendudukController@getData']);
+ Route::match(['GET', 'POST'], 'getdata', ['as' => 'data.laporan-penduduk.getdata', 'uses' => 'LaporanPendudukController@getData']);
Route::delete('destroy/{id}', ['as' => 'data.laporan-penduduk.destroy', 'uses' => 'LaporanPendudukController@destroy']);
Route::get('download{id}', ['as' => 'data.laporan-penduduk.download', 'uses' => 'LaporanPendudukController@download']);
Route::get('import', ['as' => 'data.laporan-penduduk.import', 'uses' => 'LaporanPendudukController@import']);
@@ -619,7 +621,7 @@
// AKI & AKB
Route::group(['prefix' => 'aki-akb', 'middleware' => ['action_permission:access.data.aki_akb']], function () {
Route::get('/', ['as' => 'data.aki-akb.index', 'uses' => 'AKIAKBController@index']);
- Route::get('getdata', ['as' => 'data.aki-akb.getdata', 'uses' => 'AKIAKBController@getDataAKIAKB']);
+ Route::post('getdata', ['as' => 'data.aki-akb.getdata', 'uses' => 'AKIAKBController@getDataAKIAKB']);
Route::get('edit/{id}', ['as' => 'data.aki-akb.edit', 'uses' => 'AKIAKBController@edit']);
Route::put('update/{id}', ['as' => 'data.aki-akb.update', 'uses' => 'AKIAKBController@update']);
Route::delete('destroy/{id}', ['as' => 'data.aki-akb.destroy', 'uses' => 'AKIAKBController@destroy']);
@@ -631,7 +633,7 @@
// Imunisasi
Route::group(['prefix' => 'imunisasi', 'middleware' => ['action_permission:access.data.imunisasi']], function () {
Route::get('/', ['as' => 'data.imunisasi.index', 'uses' => 'ImunisasiController@index']);
- Route::get('getdata', ['as' => 'data.imunisasi.getdata', 'uses' => 'ImunisasiController@getDataAKIAKB']);
+ Route::post('getdata', ['as' => 'data.imunisasi.getdata', 'uses' => 'ImunisasiController@getDataAKIAKB']);
Route::get('edit/{id}', ['as' => 'data.imunisasi.edit', 'uses' => 'ImunisasiController@edit']);
Route::put('update/{id}', ['as' => 'data.imunisasi.update', 'uses' => 'ImunisasiController@update']);
Route::delete('destroy/{id}', ['as' => 'data.imunisasi.destroy', 'uses' => 'ImunisasiController@destroy']);
@@ -643,7 +645,7 @@
// Epidemi Penyakit
Route::group(['prefix' => 'epidemi-penyakit', 'middleware' => ['action_permission:access.data.epidemi_penyakit']], function () {
Route::get('/', ['as' => 'data.epidemi-penyakit.index', 'uses' => 'EpidemiPenyakitController@index']);
- Route::get('getdata', ['as' => 'data.epidemi-penyakit.getdata', 'uses' => 'EpidemiPenyakitController@getDataAKIAKB']);
+ Route::post('getdata', ['as' => 'data.epidemi-penyakit.getdata', 'uses' => 'EpidemiPenyakitController@getDataAKIAKB']);
Route::get('edit/{id}', ['as' => 'data.epidemi-penyakit.edit', 'uses' => 'EpidemiPenyakitController@edit']);
Route::put('update/{id}', ['as' => 'data.epidemi-penyakit.update', 'uses' => 'EpidemiPenyakitController@update']);
Route::delete('destroy/{id}', ['as' => 'data.epidemi-penyakit.destroy', 'uses' => 'EpidemiPenyakitController@destroy']);
diff --git a/tests/Feature/DataTablesPostMethodTest.php b/tests/Feature/DataTablesPostMethodTest.php
new file mode 100644
index 000000000..b90944ff2
--- /dev/null
+++ b/tests/Feature/DataTablesPostMethodTest.php
@@ -0,0 +1,354 @@
+ajax())
+const AJAX_HEADERS = ['X-Requested-With' => 'XMLHttpRequest'];
+
+// Payload minimal DataTables server-side (mirip yang dikirim browser via POST)
+function datatablePostPayload(array $extra = []): array
+{
+ return array_merge([
+ 'draw' => 1,
+ 'start' => 0,
+ 'length' => 10,
+ 'search' => ['value' => '', 'regex' => 'false'],
+ 'columns[0][data]' => 'aksi',
+ 'columns[0][name]' => 'aksi',
+ 'columns[0][searchable]' => 'false',
+ 'columns[0][orderable]' => 'false',
+ 'columns[0][search][value]' => '',
+ 'order[0][column]' => '1',
+ 'order[0][dir]' => 'asc',
+ ], $extra);
+}
+
+beforeEach(function () {
+ $this->withoutMiddleware([
+ Authenticate::class,
+ RoleMiddleware::class,
+ PermissionMiddleware::class,
+ CompleteProfile::class,
+ GlobalShareMiddleware::class,
+ ]);
+
+ // Nonaktifkan mode database gabungan agar tidak redirect ke view berbeda
+ SettingAplikasi::updateOrCreate(
+ ['key' => 'sinkronisasi_database_gabungan'],
+ ['value' => '0']
+ );
+});
+
+// =============================================================================
+// 1. DATA DESA
+// =============================================================================
+describe('DataTables Data Desa via POST', function () {
+
+ test('endpoint getdata menolak GET dengan URL kosong (tetap backward-compatible)', function () {
+ $response = $this->getJson(
+ route('data.data-desa.getdata'),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure(['draw', 'recordsTotal', 'recordsFiltered', 'data']);
+ });
+
+ test('endpoint getdata menerima POST dan mengembalikan struktur DataTables', function () {
+ DataDesa::factory()->create([
+ 'desa_id' => '3301010099001',
+ 'nama' => 'Desa Test POST',
+ ]);
+
+ $response = $this->postJson(
+ route('data.data-desa.getdata'),
+ datatablePostPayload(),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure([
+ 'draw',
+ 'recordsTotal',
+ 'recordsFiltered',
+ 'data',
+ ]);
+ });
+
+ test('POST ke getdata mengembalikan kolom yang diharapkan', function () {
+ DataDesa::factory()->create([
+ 'desa_id' => '3301010099002',
+ 'nama' => 'Desa Kolom Test',
+ ]);
+
+ $response = $this->postJson(
+ route('data.data-desa.getdata'),
+ datatablePostPayload(),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $data = $response->json('data');
+ $this->assertNotEmpty($data);
+
+ $firstRow = $data[0];
+ $this->assertArrayHasKey('desa_id', $firstRow);
+ $this->assertArrayHasKey('nama', $firstRow);
+ $this->assertArrayHasKey('aksi', $firstRow);
+ });
+
+ test('POST dengan draw parameter dikembalikan kembali dalam response', function () {
+ $response = $this->postJson(
+ route('data.data-desa.getdata'),
+ datatablePostPayload(['draw' => 5]),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonPath('draw', 5);
+ });
+});
+
+// =============================================================================
+// 2. DATA SARANA
+// =============================================================================
+describe('DataTables Data Sarana via POST', function () {
+
+ test('endpoint getdata menerima POST dan mengembalikan struktur DataTables', function () {
+ $desa = DataDesa::factory()->create(['desa_id' => '3301010099010']);
+ DataSarana::factory()->create([
+ 'desa_id' => $desa->desa_id,
+ 'kategori' => KategoriSarana::PUSKESMAS,
+ ]);
+
+ $response = $this->postJson(
+ route('data.data-sarana.getdata'),
+ datatablePostPayload(),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure([
+ 'draw',
+ 'recordsTotal',
+ 'recordsFiltered',
+ 'data',
+ ]);
+ });
+
+ test('POST dengan filter desa_id memfilter data dengan benar', function () {
+ $desa1 = DataDesa::factory()->create(['desa_id' => '3301010099011']);
+ $desa2 = DataDesa::factory()->create(['desa_id' => '3301010099012']);
+
+ DataSarana::factory()->create([
+ 'desa_id' => $desa1->desa_id,
+ 'nama' => 'Sarana Desa 1',
+ 'kategori' => KategoriSarana::PUSKESMAS,
+ ]);
+ DataSarana::factory()->create([
+ 'desa_id' => $desa2->desa_id,
+ 'nama' => 'Sarana Desa 2',
+ 'kategori' => KategoriSarana::POSYANDU,
+ ]);
+
+ $response = $this->postJson(
+ route('data.data-sarana.getdata'),
+ datatablePostPayload(['desa_id' => $desa1->desa_id]),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $data = $response->json('data');
+
+ // Hanya data dari desa1 yang dikembalikan
+ foreach ($data as $row) {
+ $this->assertEquals($desa1->nama, $row['desa']);
+ }
+ });
+
+ test('GET pada getdata masih berfungsi (backward-compatible)', function () {
+ $response = $this->getJson(
+ route('data.data-sarana.getdata'),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure(['draw', 'recordsTotal', 'recordsFiltered', 'data']);
+ });
+});
+
+// =============================================================================
+// 3. PERANGKAT KECAMATAN — PENGURUS
+// =============================================================================
+describe('DataTables Pengurus via POST', function () {
+
+ test('endpoint dedicated POST getdata mengembalikan struktur DataTables', function () {
+ Jabatan::factory()->jabatanLainnya()->create(['nama' => 'Staff Test']);
+ Pengurus::factory()->create(['status' => 1]);
+
+ $response = $this->postJson(
+ route('data.pengurus.getdata.post'),
+ datatablePostPayload(['status' => '1']),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure([
+ 'draw',
+ 'recordsTotal',
+ 'recordsFiltered',
+ 'data',
+ ]);
+ });
+
+ test('POST dengan status aktif hanya mengembalikan pengurus aktif', function () {
+ Jabatan::factory()->jabatanLainnya()->create(['nama' => 'Staf Aktif Test']);
+ Pengurus::factory()->create(['status' => 1]);
+ Pengurus::factory()->create(['status' => 0]);
+
+ $response = $this->postJson(
+ route('data.pengurus.getdata.post'),
+ datatablePostPayload(['status' => '1']),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $data = $response->json('data');
+
+ // Semua item yang dikembalikan harus aktif (status label 'Aktif')
+ foreach ($data as $row) {
+ $this->assertStringContainsString('Aktif', $row['status']);
+ $this->assertStringNotContainsString('Tidak Aktif', $row['status']);
+ }
+ });
+
+ test('index via GET masih mengembalikan view HTML (bukan ajax)', function () {
+ $response = $this->get(route('data.pengurus.index'));
+
+ $response->assertStatus(200);
+ $response->assertViewIs('data.pengurus.index');
+ });
+});
+
+// =============================================================================
+// 4. PERANGKAT KECAMATAN — JABATAN
+// =============================================================================
+describe('DataTables Jabatan via POST', function () {
+
+ test('route POST jabatan mengembalikan struktur DataTables', function () {
+ Jabatan::factory()->jabatanLainnya()->create();
+
+ $response = $this->postJson(
+ route('data.jabatan.getdata.post'),
+ datatablePostPayload(),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure([
+ 'draw',
+ 'recordsTotal',
+ 'recordsFiltered',
+ 'data',
+ ]);
+ });
+
+ test('POST ke jabatan mengembalikan kolom nama dan tupoksi', function () {
+ Jabatan::factory()->jabatanLainnya()->create([
+ 'nama' => 'Staf Umum Test',
+ 'tupoksi' => 'Menangani urusan umum',
+ ]);
+
+ $response = $this->postJson(
+ route('data.jabatan.getdata.post'),
+ datatablePostPayload(),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $data = $response->json('data');
+ $this->assertNotEmpty($data);
+
+ $firstRow = $data[0];
+ $this->assertArrayHasKey('nama', $firstRow);
+ $this->assertArrayHasKey('tupoksi', $firstRow);
+ $this->assertArrayHasKey('aksi', $firstRow);
+ });
+
+ test('index via GET masih mengembalikan view HTML (bukan ajax)', function () {
+ $response = $this->get(route('data.jabatan.index'));
+
+ $response->assertStatus(200);
+ $response->assertViewIs('data.jabatan.index');
+ });
+
+ test('GET index dengan ajax header mengembalikan data DataTables', function () {
+ Jabatan::factory()->jabatanLainnya()->create();
+
+ $response = $this->getJson(
+ route('data.jabatan.index'),
+ AJAX_HEADERS
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure([
+ 'draw',
+ 'recordsTotal',
+ 'recordsFiltered',
+ 'data',
+ ]);
+ });
+});
diff --git a/tests/Feature/KependudukanDataTablesPostTest.php b/tests/Feature/KependudukanDataTablesPostTest.php
new file mode 100644
index 000000000..8d2b5c205
--- /dev/null
+++ b/tests/Feature/KependudukanDataTablesPostTest.php
@@ -0,0 +1,186 @@
+ 'XMLHttpRequest'];
+
+function datatablePostPayloadKependudukan(array $extra = []): array
+{
+ return array_merge([
+ 'draw' => 1,
+ 'start' => 0,
+ 'length' => 10,
+ 'search' => ['value' => '', 'regex' => 'false'],
+ 'columns[0][data]' => 'aksi',
+ 'columns[0][name]' => 'aksi',
+ 'columns[0][searchable]' => 'false',
+ 'columns[0][orderable]' => 'false',
+ 'columns[0][search][value]' => '',
+ 'order[0][column]' => '1',
+ 'order[0][dir]' => 'asc',
+ ], $extra);
+}
+
+beforeEach(function () {
+ $this->withoutMiddleware([
+ Authenticate::class,
+ RoleMiddleware::class,
+ PermissionMiddleware::class,
+ CompleteProfile::class,
+ GlobalShareMiddleware::class,
+ ]);
+
+ SettingAplikasi::updateOrCreate(
+ ['key' => 'sinkronisasi_database_gabungan'],
+ ['value' => '0']
+ );
+});
+
+describe('DataTables Menu Kependudukan via POST', function () {
+
+ test('Penduduk endpoint menerima POST dan mengembalikan struktur DataTables', function () {
+ $response = $this->postJson(
+ route('data.penduduk.getdata'),
+ datatablePostPayloadKependudukan(),
+ AJAX_HEADERS_KEPENDUDUKAN
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure([
+ 'draw',
+ 'recordsTotal',
+ 'recordsFiltered',
+ 'data',
+ ]);
+ });
+
+ test('Keluarga endpoint menerima POST dan mengembalikan struktur DataTables', function () {
+ $response = $this->postJson(
+ route('data.keluarga.getdata'),
+ datatablePostPayloadKependudukan(),
+ AJAX_HEADERS_KEPENDUDUKAN
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure([
+ 'draw',
+ 'recordsTotal',
+ 'recordsFiltered',
+ 'data',
+ ]);
+ });
+
+ test('Data Suplemen getdata endpoint menerima POST dan mengembalikan struktur DataTables', function () {
+ $response = $this->postJson(
+ route('data.data-suplemen.getdata'),
+ datatablePostPayloadKependudukan(),
+ AJAX_HEADERS_KEPENDUDUKAN
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure([
+ 'draw',
+ 'recordsTotal',
+ 'recordsFiltered',
+ 'data',
+ ]);
+ });
+
+ test('Data Suplemen getsuplementerdata endpoint menerima POST', function () {
+ $suplemen = Suplemen::create([
+ 'nama' => 'Suplemen Test POST',
+ 'slug' => 'suplemen-test-post',
+ 'sasaran' => 1,
+ 'keterangan' => 'Testing POST method'
+ ]);
+
+ $response = $this->postJson(
+ route('data.data-suplemen.getsuplementerdata', $suplemen->id),
+ datatablePostPayloadKependudukan(),
+ AJAX_HEADERS_KEPENDUDUKAN
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure([
+ 'draw',
+ 'recordsTotal',
+ 'recordsFiltered',
+ 'data',
+ ]);
+ });
+
+ test('Laporan Penduduk endpoint menerima POST dan mengembalikan struktur DataTables', function () {
+ $response = $this->postJson(
+ route('data.laporan-penduduk.getdata'),
+ datatablePostPayloadKependudukan(),
+ AJAX_HEADERS_KEPENDUDUKAN
+ );
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure([
+ 'draw',
+ 'recordsTotal',
+ 'recordsFiltered',
+ 'data',
+ ]);
+ });
+
+ test('Semua endpoint getdata Kependudukan tetap backward-compatible dengan GET', function () {
+ $endpoints = [
+ route('data.penduduk.getdata'),
+ route('data.keluarga.getdata'),
+ route('data.data-suplemen.getdata'),
+ route('data.laporan-penduduk.getdata'),
+ ];
+
+ foreach ($endpoints as $url) {
+ $response = $this->getJson($url, AJAX_HEADERS_KEPENDUDUKAN);
+ $response->assertStatus(200);
+ $response->assertJsonStructure(['draw', 'recordsTotal', 'recordsFiltered', 'data']);
+ }
+ });
+});
diff --git a/tests/Feature/Kesehatan/AkiAkbCrudTest.php b/tests/Feature/Kesehatan/AkiAkbCrudTest.php
index 8f8cd9f2a..e62d40326 100644
--- a/tests/Feature/Kesehatan/AkiAkbCrudTest.php
+++ b/tests/Feature/Kesehatan/AkiAkbCrudTest.php
@@ -35,10 +35,31 @@
use App\Models\DataDesa;
use Tests\CrudTestCase;
+const AJAX_HEADERS_AKI_AKB = ['X-Requested-With' => 'XMLHttpRequest'];
+
beforeEach(function () {
// Test setup if needed
});
+function datatablePostPayloadAkiAkb(array $extra = []): array
+{
+ return array_merge([
+ 'draw' => 1,
+ 'start' => 0,
+ 'length' => 10,
+ 'search' => ['value' => '', 'regex' => 'false'],
+ 'columns' => [
+ ['data' => 'aksi', 'name' => 'aksi', 'searchable' => 'false', 'orderable' => 'false', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'nama_desa', 'name' => 'desa_id', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'aki', 'name' => 'aki', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'akb', 'name' => 'akb', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'bulan', 'name' => 'bulan', 'searchable' => 'false', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'tahun', 'name' => 'tahun', 'searchable' => 'false', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ],
+ 'order' => [['column' => 1, 'dir' => 'desc']],
+ ], $extra);
+}
+
describe('AKI AKB CRUD', function () {
test('index displays aki akb list view', function () {
$response = $this->get(route('data.aki-akb.index'));
@@ -121,7 +142,7 @@
$desa = DataDesa::factory()->create();
AkiAkb::factory()->count(3)->create(['desa_id' => $desa->desa_id]);
- $response = $this->get(route('data.aki-akb.getdata'));
+ $response = $this->postJson(route('data.aki-akb.getdata'), datatablePostPayloadAkiAkb(), AJAX_HEADERS_AKI_AKB);
$response->assertStatus(200);
$response->assertJsonStructure([
diff --git a/tests/Feature/Kesehatan/ImunisasiCrudTest.php b/tests/Feature/Kesehatan/ImunisasiCrudTest.php
index 0d8115d07..8365d6941 100644
--- a/tests/Feature/Kesehatan/ImunisasiCrudTest.php
+++ b/tests/Feature/Kesehatan/ImunisasiCrudTest.php
@@ -35,10 +35,30 @@
use App\Models\Imunisasi;
use Tests\CrudTestCase;
+const AJAX_HEADERS_IMUNISASI = ['X-Requested-With' => 'XMLHttpRequest'];
+
beforeEach(function () {
// Test setup if needed
});
+function datatablePostPayloadImunisasi(array $extra = []): array
+{
+ return array_merge([
+ 'draw' => 1,
+ 'start' => 0,
+ 'length' => 10,
+ 'search' => ['value' => '', 'regex' => 'false'],
+ 'columns' => [
+ ['data' => 'aksi', 'name' => 'aksi', 'searchable' => 'false', 'orderable' => 'false', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'nama_desa', 'name' => 'desa_id', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'cakupan_imunisasi', 'name' => 'cakupan_imunisasi', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'bulan', 'name' => 'bulan', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'tahun', 'name' => 'tahun', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ],
+ 'order' => [['column' => 1, 'dir' => 'asc']],
+ ], $extra);
+}
+
describe('Imunisasi CRUD', function () {
test('index displays imunisasi list view', function () {
$response = $this->get(route('data.imunisasi.index'));
@@ -59,7 +79,8 @@
});
test('edit displays edit form', function () {
- $imunisasi = Imunisasi::factory()->create();
+ $desa = DataDesa::factory()->create();
+ $imunisasi = Imunisasi::factory()->create(['desa_id' => $desa->desa_id]);
$response = $this->get(route('data.imunisasi.edit', $imunisasi->id));
@@ -70,7 +91,8 @@
});
test('update updates imunisasi successfully', function () {
- $imunisasi = Imunisasi::factory()->create();
+ $desa = DataDesa::factory()->create();
+ $imunisasi = Imunisasi::factory()->create(['desa_id' => $desa->desa_id]);
$updateData = [
'cakupan_imunisasi' => 95,
@@ -90,7 +112,8 @@
});
test('update fails with invalid data', function () {
- $imunisasi = Imunisasi::factory()->create();
+ $desa = DataDesa::factory()->create();
+ $imunisasi = Imunisasi::factory()->create(['desa_id' => $desa->desa_id]);
$invalidData = [
'cakupan_imunisasi' => '',
@@ -102,7 +125,8 @@
});
test('destroy deletes imunisasi successfully', function () {
- $imunisasi = Imunisasi::factory()->create();
+ $desa = DataDesa::factory()->create();
+ $imunisasi = Imunisasi::factory()->create(['desa_id' => $desa->desa_id]);
$response = $this->delete(route('data.imunisasi.destroy', $imunisasi->id));
@@ -118,7 +142,7 @@
$desa = DataDesa::factory()->create();
Imunisasi::factory()->count(3)->create(['desa_id' => $desa->desa_id]);
- $response = $this->get(route('data.imunisasi.getdata'));
+ $response = $this->postJson(route('data.imunisasi.getdata'), datatablePostPayloadImunisasi(), AJAX_HEADERS_IMUNISASI);
$response->assertStatus(200);
$response->assertJsonStructure([
diff --git a/tests/Feature/Kesehatan/KesehatanDataTablesPostTest.php b/tests/Feature/Kesehatan/KesehatanDataTablesPostTest.php
new file mode 100644
index 000000000..6a40cc080
--- /dev/null
+++ b/tests/Feature/Kesehatan/KesehatanDataTablesPostTest.php
@@ -0,0 +1,121 @@
+ 'XMLHttpRequest'];
+
+function datatablePostPayloadKesehatan(array $columns, string $direction = 'asc', array $extra = []): array
+{
+ return array_merge([
+ 'draw' => 1,
+ 'start' => 0,
+ 'length' => 10,
+ 'search' => ['value' => '', 'regex' => 'false'],
+ 'columns' => $columns,
+ 'order' => [['column' => 1, 'dir' => $direction]],
+ ], $extra);
+}
+
+describe('DataTables Menu Kesehatan via POST', function () {
+ test('AKI AKB getdata menerima POST dan mengembalikan struktur DataTables', function () {
+ $desa = DataDesa::factory()->create();
+ AkiAkb::factory()->create(['desa_id' => $desa->desa_id]);
+
+ $response = $this->postJson(route('data.aki-akb.getdata'), datatablePostPayloadKesehatan([
+ ['data' => 'aksi', 'name' => 'aksi', 'searchable' => 'false', 'orderable' => 'false', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'nama_desa', 'name' => 'desa_id', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'aki', 'name' => 'aki', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'akb', 'name' => 'akb', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'bulan', 'name' => 'bulan', 'searchable' => 'false', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'tahun', 'name' => 'tahun', 'searchable' => 'false', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ], 'desc'), AJAX_HEADERS_KESEHATAN);
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure(['draw', 'recordsTotal', 'recordsFiltered', 'data']);
+ });
+
+ test('Imunisasi getdata menerima POST dan mengembalikan struktur DataTables', function () {
+ $desa = DataDesa::factory()->create();
+ Imunisasi::factory()->create(['desa_id' => $desa->desa_id]);
+
+ $response = $this->postJson(route('data.imunisasi.getdata'), datatablePostPayloadKesehatan([
+ ['data' => 'aksi', 'name' => 'aksi', 'searchable' => 'false', 'orderable' => 'false', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'nama_desa', 'name' => 'desa_id', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'cakupan_imunisasi', 'name' => 'cakupan_imunisasi', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'bulan', 'name' => 'bulan', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'tahun', 'name' => 'tahun', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ]), AJAX_HEADERS_KESEHATAN);
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure(['draw', 'recordsTotal', 'recordsFiltered', 'data']);
+ });
+
+ test('Epidemi Penyakit getdata menerima POST dan mengembalikan struktur DataTables', function () {
+ $desa = DataDesa::factory()->create();
+ $jenisPenyakit = JenisPenyakit::factory()->create();
+ EpidemiPenyakit::factory()->create([
+ 'desa_id' => $desa->desa_id,
+ 'penyakit_id' => $jenisPenyakit->id,
+ ]);
+
+ $response = $this->postJson(route('data.epidemi-penyakit.getdata'), datatablePostPayloadKesehatan([
+ ['data' => 'aksi', 'name' => 'aksi', 'searchable' => 'false', 'orderable' => 'false', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'nama_desa', 'name' => 'desa_id', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'penyakit.nama', 'name' => 'penyakit.nama', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'jumlah_penderita', 'name' => 'jumlah_penderita', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'bulan', 'name' => 'bulan', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ['data' => 'tahun', 'name' => 'tahun', 'searchable' => 'true', 'orderable' => 'true', 'search' => ['value' => '', 'regex' => 'false']],
+ ]), AJAX_HEADERS_KESEHATAN);
+
+ $response->assertStatus(200);
+ $response->assertJsonStructure(['draw', 'recordsTotal', 'recordsFiltered', 'data']);
+ });
+
+ test('endpoint getdata kesehatan tidak lagi menerima GET', function () {
+ $endpoints = [
+ route('data.aki-akb.getdata'),
+ route('data.imunisasi.getdata'),
+ route('data.epidemi-penyakit.getdata'),
+ ];
+
+ foreach ($endpoints as $url) {
+ $this->getJson($url, AJAX_HEADERS_KESEHATAN)->assertStatus(405);
+ }
+ });
+});