forked from admin/services_core
big update base struktur tahap 1
This commit is contained in:
@@ -0,0 +1,329 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\MenuGroup;
|
||||
use App\Models\MenuList;
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class MenuAccessTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_staff_only_receives_viewable_menus_for_active_tenant(): void
|
||||
{
|
||||
[$user, $tenant] = $this->staffWithTicketPermission();
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$response = $this->withHeader('X-Tenant-ID', $tenant->id)
|
||||
->getJson('/api/me/menus');
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertJsonPath('data.tenant_id', $tenant->id)
|
||||
->assertJsonPath('data.access_level', 'staff')
|
||||
->assertJsonPath('data.menus.0.slug', 'ticketing-ticket');
|
||||
}
|
||||
|
||||
public function test_user_cannot_select_a_tenant_they_do_not_belong_to(): void
|
||||
{
|
||||
[$user] = $this->staffWithTicketPermission();
|
||||
$otherTenant = Tenant::create([
|
||||
'tenant_code' => 'OTHER',
|
||||
'tenant_name' => 'Other Tenant',
|
||||
]);
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->withHeader('X-Tenant-ID', $otherTenant->id)
|
||||
->getJson('/api/me/menus')
|
||||
->assertForbidden()
|
||||
->assertJsonPath('message', 'User tidak memiliki akses ke tenant yang dipilih.');
|
||||
}
|
||||
|
||||
public function test_tenant_owner_cannot_promote_a_user_to_master_admin(): void
|
||||
{
|
||||
[$owner, $tenant] = $this->staffWithTicketPermission('tenant_owner');
|
||||
$target = User::factory()->create(['access_level' => 'staff']);
|
||||
$target->userTenants()->create([
|
||||
'tenant_id' => $tenant->id,
|
||||
'is_default' => true,
|
||||
]);
|
||||
|
||||
$usersMenu = MenuList::create([
|
||||
'name' => 'Data Pengguna',
|
||||
'slug' => 'users-user',
|
||||
'url' => '/users',
|
||||
'is_active' => true,
|
||||
]);
|
||||
$group = $owner->userMenuGroups()->first()->menuGroup;
|
||||
$group->menus()->attach($usersMenu->id, [
|
||||
'can_view' => true,
|
||||
'can_update' => true,
|
||||
]);
|
||||
Sanctum::actingAs($owner);
|
||||
|
||||
$this->withHeader('X-Tenant-ID', $tenant->id)
|
||||
->patchJson("/api/users/{$target->id}", [
|
||||
'access_level' => 'master_admin',
|
||||
])
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors('access_level');
|
||||
}
|
||||
|
||||
public function test_index_response_uses_the_same_paginator_contract_as_tickets(): void
|
||||
{
|
||||
$master = User::factory()->create([
|
||||
'is_master' => true,
|
||||
'access_level' => 'master_admin',
|
||||
]);
|
||||
Tenant::create([
|
||||
'tenant_code' => 'PAGINATED',
|
||||
'tenant_name' => 'Pagination Test',
|
||||
]);
|
||||
Sanctum::actingAs($master);
|
||||
|
||||
$this->getJson('/api/tenants?per_page=10')
|
||||
->assertOk()
|
||||
->assertJsonStructure([
|
||||
'success',
|
||||
'code',
|
||||
'message',
|
||||
'data' => [
|
||||
'current_page',
|
||||
'data',
|
||||
'first_page_url',
|
||||
'from',
|
||||
'last_page',
|
||||
'last_page_url',
|
||||
'links',
|
||||
'next_page_url',
|
||||
'path',
|
||||
'per_page',
|
||||
'prev_page_url',
|
||||
'to',
|
||||
'total',
|
||||
],
|
||||
])
|
||||
->assertJsonPath('data.current_page', 1)
|
||||
->assertJsonPath('data.per_page', 10)
|
||||
->assertJsonPath('data.data.0.tenant_code', 'PAGINATED');
|
||||
}
|
||||
|
||||
public function test_index_query_parameters_are_validated(): void
|
||||
{
|
||||
$master = User::factory()->create([
|
||||
'is_master' => true,
|
||||
'access_level' => 'master_admin',
|
||||
]);
|
||||
Sanctum::actingAs($master);
|
||||
|
||||
$this->getJson('/api/tenants?page=0&per_page=101&status=unknown')
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors(['page', 'per_page', 'status']);
|
||||
}
|
||||
|
||||
public function test_tenant_owner_only_receives_tenants_assigned_to_the_user(): void
|
||||
{
|
||||
[$owner, $assignedTenant] = $this->staffWithTicketPermission('tenant_owner');
|
||||
$secondAssignedTenant = Tenant::create([
|
||||
'tenant_code' => 'OWNER-SECOND',
|
||||
'tenant_name' => 'Second Assigned Tenant',
|
||||
]);
|
||||
$owner->userTenants()->create([
|
||||
'tenant_id' => $secondAssignedTenant->id,
|
||||
'is_default' => false,
|
||||
]);
|
||||
$otherTenant = Tenant::create([
|
||||
'tenant_code' => 'OWNER-OTHER',
|
||||
'tenant_name' => 'Unassigned Tenant',
|
||||
]);
|
||||
Sanctum::actingAs($owner);
|
||||
|
||||
$response = $this->withHeader('X-Tenant-ID', $assignedTenant->id)
|
||||
->getJson('/api/tenants?per_page=100')
|
||||
->assertOk();
|
||||
|
||||
$tenantIds = collect($response->json('data.data'))->pluck('id');
|
||||
|
||||
$this->assertTrue($tenantIds->contains($assignedTenant->id));
|
||||
$this->assertTrue($tenantIds->contains($secondAssignedTenant->id));
|
||||
$this->assertFalse($tenantIds->contains($otherTenant->id));
|
||||
|
||||
$this->withHeader('X-Tenant-ID', $assignedTenant->id)
|
||||
->getJson("/api/tenants/{$secondAssignedTenant->id}")
|
||||
->assertOk();
|
||||
|
||||
$this->withHeader('X-Tenant-ID', $assignedTenant->id)
|
||||
->getJson("/api/tenants/{$otherTenant->id}")
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_authenticated_user_can_view_and_update_only_their_own_profile(): void
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'name' => 'Nama Lama',
|
||||
'access_level' => 'staff',
|
||||
]);
|
||||
Sanctum::actingAs($user);
|
||||
|
||||
$this->getJson('/api/me/profile')
|
||||
->assertOk()
|
||||
->assertJsonPath('data.id', $user->id)
|
||||
->assertJsonPath('data.access_level', 'staff');
|
||||
|
||||
$this->putJson('/api/me/profile', [
|
||||
'name' => 'Nama Baru',
|
||||
'username' => 'nama.baru',
|
||||
'email' => $user->email,
|
||||
'whatsapp_number' => '08123456789',
|
||||
'access_level' => 'master_admin',
|
||||
'is_master' => true,
|
||||
'user_profile' => [
|
||||
'nik' => '1234567890',
|
||||
'address' => 'Alamat baru',
|
||||
],
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonPath('data.name', 'Nama Baru')
|
||||
->assertJsonPath('data.user_profile.nik', '1234567890')
|
||||
->assertJsonPath('data.access_level', 'staff')
|
||||
->assertJsonPath('data.is_master', false);
|
||||
|
||||
$user->refresh();
|
||||
$this->assertSame('staff', $user->access_level->value);
|
||||
$this->assertFalse($user->is_master);
|
||||
}
|
||||
|
||||
public function test_tenant_owner_creates_and_only_lists_groups_in_the_active_tenant(): void
|
||||
{
|
||||
[$owner, $tenant] = $this->staffWithTicketPermission('tenant_owner');
|
||||
$otherTenant = Tenant::create([
|
||||
'tenant_code' => 'OTHER-GROUP',
|
||||
'tenant_name' => 'Other Group Tenant',
|
||||
]);
|
||||
$otherTenantGroup = MenuGroup::create([
|
||||
'tenant_id' => $otherTenant->id,
|
||||
'name' => 'Other Tenant Group',
|
||||
'is_active' => true,
|
||||
]);
|
||||
$globalSystemGroup = MenuGroup::create([
|
||||
'tenant_id' => null,
|
||||
'name' => 'Global System Group',
|
||||
'is_system' => true,
|
||||
'is_active' => true,
|
||||
]);
|
||||
$menu = MenuList::create([
|
||||
'name' => 'Group Menus',
|
||||
'slug' => 'users-group-menus',
|
||||
'url' => '/group-menus',
|
||||
'is_active' => true,
|
||||
]);
|
||||
$owner->userMenuGroups()->first()->menuGroup->menus()->attach($menu->id, [
|
||||
'can_view' => true,
|
||||
'can_create' => true,
|
||||
]);
|
||||
Sanctum::actingAs($owner);
|
||||
|
||||
$this->withHeader('X-Tenant-ID', $tenant->id)
|
||||
->postJson('/api/menu-groups', [
|
||||
'name' => 'Teknisi Tenant',
|
||||
'description' => 'Akses teknisi',
|
||||
'is_active' => true,
|
||||
])
|
||||
->assertCreated()
|
||||
->assertJsonPath('data.tenant_id', $tenant->id)
|
||||
->assertJsonPath('data.is_system', false)
|
||||
->assertJsonPath('data.tenant.id', $tenant->id);
|
||||
|
||||
$response = $this->withHeader('X-Tenant-ID', $tenant->id)
|
||||
->getJson('/api/menu-groups?per_page=100')
|
||||
->assertOk();
|
||||
|
||||
$this->assertNotContains(
|
||||
'Other Tenant Group',
|
||||
collect($response->json('data.data'))->pluck('name')->all()
|
||||
);
|
||||
$this->assertNotContains(
|
||||
'Global System Group',
|
||||
collect($response->json('data.data'))->pluck('name')->all()
|
||||
);
|
||||
|
||||
$this->withHeader('X-Tenant-ID', $tenant->id)
|
||||
->getJson("/api/menu-groups/{$otherTenantGroup->id}")
|
||||
->assertForbidden();
|
||||
|
||||
$this->withHeader('X-Tenant-ID', $tenant->id)
|
||||
->getJson("/api/menu-groups/{$globalSystemGroup->id}")
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
public function test_master_admin_can_create_global_and_tenant_menu_groups(): void
|
||||
{
|
||||
$master = User::factory()->create([
|
||||
'is_master' => true,
|
||||
'access_level' => 'master_admin',
|
||||
]);
|
||||
$tenant = Tenant::create([
|
||||
'tenant_code' => 'MASTER-SCOPE',
|
||||
'tenant_name' => 'Master Scope Tenant',
|
||||
]);
|
||||
Sanctum::actingAs($master);
|
||||
|
||||
$this->postJson('/api/menu-groups', [
|
||||
'name' => 'Global System Group',
|
||||
'is_active' => true,
|
||||
'tenant_id' => null,
|
||||
])
|
||||
->assertCreated()
|
||||
->assertJsonPath('data.tenant_id', null)
|
||||
->assertJsonPath('data.is_system', true);
|
||||
|
||||
$this->postJson('/api/menu-groups', [
|
||||
'name' => 'Tenant Scoped Group',
|
||||
'is_active' => true,
|
||||
'tenant_id' => $tenant->id,
|
||||
])
|
||||
->assertCreated()
|
||||
->assertJsonPath('data.tenant_id', $tenant->id)
|
||||
->assertJsonPath('data.is_system', false)
|
||||
->assertJsonPath('data.tenant.tenant_name', 'Master Scope Tenant');
|
||||
}
|
||||
|
||||
private function staffWithTicketPermission(string $level = 'staff'): array
|
||||
{
|
||||
$tenant = Tenant::create([
|
||||
'tenant_code' => fake()->unique()->bothify('TEN-###'),
|
||||
'tenant_name' => fake()->company(),
|
||||
]);
|
||||
$user = User::factory()->create(['access_level' => $level]);
|
||||
$user->userTenants()->create([
|
||||
'tenant_id' => $tenant->id,
|
||||
'is_default' => true,
|
||||
]);
|
||||
$menu = MenuList::create([
|
||||
'name' => 'Tiket',
|
||||
'slug' => 'ticketing-ticket',
|
||||
'url' => '/tickets',
|
||||
'is_active' => true,
|
||||
]);
|
||||
$group = MenuGroup::create([
|
||||
'tenant_id' => $tenant->id,
|
||||
'name' => 'Staff '.$tenant->id,
|
||||
'is_active' => true,
|
||||
]);
|
||||
$group->menus()->attach($menu->id, [
|
||||
'can_view' => true,
|
||||
'can_update' => true,
|
||||
]);
|
||||
$user->userMenuGroups()->create([
|
||||
'menu_group_id' => $group->id,
|
||||
'tenant_id' => $tenant->id,
|
||||
]);
|
||||
|
||||
return [$user, $tenant];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\NasMikrotik;
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use App\Services\Nas\NasResourceService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
class NasResourceServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_tenant_user_only_lists_nas_data_from_the_active_tenant(): void
|
||||
{
|
||||
$tenant = Tenant::create(['tenant_code' => 'NAS-A', 'tenant_name' => 'NAS A']);
|
||||
$otherTenant = Tenant::create(['tenant_code' => 'NAS-B', 'tenant_name' => 'NAS B']);
|
||||
$user = User::factory()->create(['access_level' => 'tenant_owner']);
|
||||
$user->userTenants()->create(['tenant_id' => $tenant->id, 'is_default' => true]);
|
||||
|
||||
NasMikrotik::create([
|
||||
'tenant_id' => $tenant->id,
|
||||
'name' => 'Router A',
|
||||
'connection_type' => 'api',
|
||||
'host' => '10.0.0.1',
|
||||
]);
|
||||
NasMikrotik::create([
|
||||
'tenant_id' => $otherTenant->id,
|
||||
'name' => 'Router B',
|
||||
'connection_type' => 'api',
|
||||
'host' => '10.0.0.2',
|
||||
]);
|
||||
|
||||
$result = app(NasResourceService::class)->list(
|
||||
'mikrotik',
|
||||
['per_page' => 100],
|
||||
$user,
|
||||
$tenant->id
|
||||
);
|
||||
|
||||
$this->assertSame(['Router A'], $result->getCollection()->pluck('name')->all());
|
||||
}
|
||||
|
||||
public function test_mikrotik_credentials_are_encrypted_and_blank_update_preserves_them(): void
|
||||
{
|
||||
$tenant = Tenant::create(['tenant_code' => 'NAS-SECRET', 'tenant_name' => 'NAS Secret']);
|
||||
$master = User::factory()->create(['is_master' => true, 'access_level' => 'master_admin']);
|
||||
$service = app(NasResourceService::class);
|
||||
|
||||
$mikrotik = $service->create('mikrotik', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'name' => 'Secure Router',
|
||||
'connection_type' => 'radius',
|
||||
'host' => '10.10.10.1',
|
||||
'radius_secret' => 'plain-secret',
|
||||
], $master, null);
|
||||
|
||||
$this->assertNotSame('plain-secret', $mikrotik->getRawOriginal('radius_secret'));
|
||||
$this->assertSame('plain-secret', $mikrotik->radius_secret);
|
||||
|
||||
$service->update('mikrotik', $mikrotik, [
|
||||
'name' => 'Secure Router Updated',
|
||||
'radius_secret' => '',
|
||||
], $master);
|
||||
|
||||
$this->assertSame('plain-secret', $mikrotik->fresh()->radius_secret);
|
||||
}
|
||||
|
||||
public function test_nas_route_resolves_its_resource_configuration(): void
|
||||
{
|
||||
$tenant = Tenant::create(['tenant_code' => 'NAS-ROUTE', 'tenant_name' => 'NAS Route']);
|
||||
$master = User::factory()->create(['is_master' => true, 'access_level' => 'master_admin']);
|
||||
Sanctum::actingAs($master);
|
||||
|
||||
$this->postJson('/api/nas/mikrotiks', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'name' => 'Route Router',
|
||||
'connection_type' => 'api',
|
||||
'host' => '192.168.88.1',
|
||||
])
|
||||
->assertCreated()
|
||||
->assertJsonPath('data.name', 'Route Router')
|
||||
->assertJsonPath('data.connection_type', 'api');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Enums\UserAccessLevel;
|
||||
use App\Models\StoredFile;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
|
||||
class StoredFileApiTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_user_can_upload_an_image_and_set_it_as_profile_photo(): void
|
||||
{
|
||||
Storage::fake('minio');
|
||||
|
||||
$user = User::factory()->create([
|
||||
'access_level' => UserAccessLevel::CUSTOMER,
|
||||
'is_master' => false,
|
||||
]);
|
||||
|
||||
$uploadResponse = $this->actingAs($user)
|
||||
->post('/api/files', [
|
||||
'file' => UploadedFile::fake()->create('avatar.png', 100, 'image/png'),
|
||||
'category' => 'profile',
|
||||
])
|
||||
->assertCreated()
|
||||
->assertJsonPath('success', true)
|
||||
->assertJsonPath('data.category', 'profile');
|
||||
|
||||
$fileId = $uploadResponse->json('data.id');
|
||||
|
||||
$this->actingAs($user)
|
||||
->putJson('/api/me/profile', [
|
||||
'name' => $user->name,
|
||||
'username' => $user->username,
|
||||
'email' => $user->email,
|
||||
'profile_photo_file_id' => $fileId,
|
||||
'user_profile' => null,
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonPath('data.profile_photo.id', $fileId);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'profile_photo_file_id' => $fileId,
|
||||
]);
|
||||
|
||||
$storedFile = StoredFile::findOrFail($fileId);
|
||||
Storage::disk('minio')->assertExists($storedFile->object_key);
|
||||
}
|
||||
|
||||
public function test_user_cannot_use_another_users_file_as_profile_photo(): void
|
||||
{
|
||||
$owner = User::factory()->create();
|
||||
$otherUser = User::factory()->create();
|
||||
$file = StoredFile::create([
|
||||
'uuid' => fake()->uuid(),
|
||||
'uploaded_by' => $owner->id,
|
||||
'disk' => 'minio',
|
||||
'bucket' => 'file',
|
||||
'object_key' => 'profiles/test.png',
|
||||
'original_name' => 'test.png',
|
||||
'extension' => 'png',
|
||||
'mime_type' => 'image/png',
|
||||
'size' => 100,
|
||||
'category' => 'profile',
|
||||
'visibility' => 'private',
|
||||
]);
|
||||
|
||||
$this->actingAs($otherUser)
|
||||
->putJson('/api/me/profile', [
|
||||
'name' => $otherUser->name,
|
||||
'username' => $otherUser->username,
|
||||
'email' => $otherUser->email,
|
||||
'profile_photo_file_id' => $file->id,
|
||||
'user_profile' => null,
|
||||
])
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors('profile_photo_file_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Enums\UserAccessLevel;
|
||||
use App\Models\User;
|
||||
use App\Models\WilayahDesa;
|
||||
use App\Models\WilayahKabupaten;
|
||||
use App\Models\WilayahKecamatan;
|
||||
use App\Models\WilayahProvinsi;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class WilayahApiTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_master_admin_can_create_hierarchical_regions_and_get_full_address(): void
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'is_master' => true,
|
||||
'access_level' => UserAccessLevel::MASTER_ADMIN,
|
||||
]);
|
||||
|
||||
$provinsiId = $this->actingAs($user)
|
||||
->postJson('/api/wilayah/provinsi', ['kode' => '11', 'nama' => 'Aceh'])
|
||||
->assertCreated()
|
||||
->json('data.id');
|
||||
|
||||
$kabupatenId = $this->postJson('/api/wilayah/kabupaten', [
|
||||
'kode' => '11.01',
|
||||
'nama' => 'Kabupaten Simeulue',
|
||||
'provinsi_id' => $provinsiId,
|
||||
])->assertCreated()->json('data.id');
|
||||
|
||||
$kecamatanId = $this->postJson('/api/wilayah/kecamatan', [
|
||||
'kode' => '11.01.01',
|
||||
'nama' => 'Teupah Selatan',
|
||||
'kabupaten_id' => $kabupatenId,
|
||||
])->assertCreated()->json('data.id');
|
||||
|
||||
$desaId = $this->postJson('/api/wilayah/desa', [
|
||||
'kode' => '11.01.01.2001',
|
||||
'nama' => 'Latiung',
|
||||
'kecamatan_id' => $kecamatanId,
|
||||
])->assertCreated()->json('data.id');
|
||||
|
||||
$this->getJson("/api/wilayah/alamat-lengkap?desa_id={$desaId}")
|
||||
->assertOk()
|
||||
->assertJsonPath('data.desa.nama', 'Latiung')
|
||||
->assertJsonPath('data.kecamatan.nama', 'Teupah Selatan')
|
||||
->assertJsonPath('data.kabupaten.nama', 'Kabupaten Simeulue')
|
||||
->assertJsonPath('data.provinsi.nama', 'Aceh')
|
||||
->assertJsonPath(
|
||||
'data.alamat_wilayah',
|
||||
'Desa/Kelurahan Latiung, Kecamatan Teupah Selatan, Kabupaten Simeulue, Provinsi Aceh'
|
||||
);
|
||||
}
|
||||
|
||||
public function test_child_region_requires_its_direct_parent(): void
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'is_master' => true,
|
||||
'access_level' => UserAccessLevel::MASTER_ADMIN,
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->postJson('/api/wilayah/desa', [
|
||||
'kode' => '01',
|
||||
'nama' => 'Desa Tanpa Kecamatan',
|
||||
])
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors('kecamatan_id');
|
||||
}
|
||||
|
||||
public function test_parent_with_children_cannot_be_deleted(): void
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'is_master' => true,
|
||||
'access_level' => UserAccessLevel::MASTER_ADMIN,
|
||||
]);
|
||||
$provinsi = WilayahProvinsi::create(['kode' => '12', 'nama' => 'Sumatera Utara']);
|
||||
$kabupaten = WilayahKabupaten::create([
|
||||
'provinsi_id' => $provinsi->id,
|
||||
'kode' => '12.01',
|
||||
'nama' => 'Tapanuli Tengah',
|
||||
]);
|
||||
$kecamatan = WilayahKecamatan::create([
|
||||
'kabupaten_id' => $kabupaten->id,
|
||||
'kode' => '12.01.01',
|
||||
'nama' => 'Barus',
|
||||
]);
|
||||
WilayahDesa::create([
|
||||
'kecamatan_id' => $kecamatan->id,
|
||||
'kode' => '12.01.01.2001',
|
||||
'nama' => 'Kampung Mudik',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->deleteJson("/api/wilayah/provinsi/{$provinsi->id}")
|
||||
->assertUnprocessable()
|
||||
->assertJsonValidationErrors('wilayah');
|
||||
|
||||
$this->assertDatabaseHas('wilayah_provinsi', ['id' => $provinsi->id]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user