store/tests/Feature/Admin/System/SettingTest.php

617 lines
24 KiB
PHP

<?php
use App\Enums\Permission as PermissionEnum;
use App\Models\User;
use Database\Seeders\RolePermissionSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->seed(RolePermissionSeeder::class);
Storage::fake('public');
});
// ─── Helper ───────────────────────────────────────────────
function createSettingUserWithPermission(PermissionEnum ...$permissions): User
{
$user = User::factory()->create();
$user->givePermissionTo(
array_merge(
[PermissionEnum::DASHBOARD_VIEW->value],
array_map(fn (PermissionEnum $p) => $p->value, $permissions)
)
);
$user->forgetCachedPermissions();
return $user;
}
function validSystemPayload(): array
{
return [
'app_name' => 'DST Collection',
'about_app' => 'Tentang aplikasi kami',
'email' => 'info@dstcollection.com',
'phone' => '081234567890',
'address' => 'Jl. Merdeka No. 1',
];
}
function validMarketplaceFeeRule(): array
{
return [
'scope' => 'product',
'value_type' => 'percent',
'value' => 5.0,
];
}
function allMarketplaceFeeFields(): array
{
$fields = [
'tiktok_shop_platform_commission',
'tiktok_shop_logistics_service_fee',
'tiktok_shop_dynamic_commission',
'tiktok_shop_order_processing_fee',
'tiktok_shop_affiliate',
'tiktok_shop_pre_order_service_fee',
'shopee_admin_fee',
'shopee_program_fee',
'shopee_shipping_savings',
'shopee_premium',
'shopee_service_fee',
'shopee_order_processing_fee',
'shopee_ams_commission_fee',
'shopee_pre_order',
'shopee_live_extra',
];
return collect($fields)->mapWithKeys(fn (string $key) => [$key => validMarketplaceFeeRule()])->all();
}
// ─── Index ────────────────────────────────────────────────
describe('Setting Index', function () {
test('authenticated user with permission can view settings page', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM);
$this->actingAs($user)
->get(route('admin.system.settings.index'))
->assertOk();
});
test('guest is redirected to login', function () {
$this->get(route('admin.system.settings.index'))
->assertRedirect(route('login'));
});
test('user without permission is forbidden', function () {
$user = User::factory()->create();
$this->actingAs($user)
->get(route('admin.system.settings.index'))
->assertForbidden();
});
});
// ─── Update System ────────────────────────────────────────
describe('Setting Update System', function () {
test('authenticated user with permission can update system settings', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['logo'] = UploadedFile::fake()->image('logo.jpg', 100, 100);
$payload['favicon'] = UploadedFile::fake()->image('favicon.png', 32, 32);
$payload['login_cover'] = UploadedFile::fake()->image('login-cover.jpg', 800, 600);
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertRedirect(route('admin.system.settings.index'));
$this->assertDatabaseHas('settings', [
'group' => 'system',
'name' => 'app_name',
]);
});
test('guest cannot update system settings', function () {
$this->put(route('admin.system.settings.system.update'), validSystemPayload())
->assertRedirect(route('login'));
});
test('user without update permission is forbidden', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM);
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), validSystemPayload())
->assertForbidden();
});
test('app_name is required', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['app_name'] = '';
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertSessionHasErrors('app_name');
});
test('app_name must not exceed 100 characters', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['app_name'] = str_repeat('a', 101);
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertSessionHasErrors('app_name');
});
test('email must be valid', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['email'] = 'not-an-email';
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertSessionHasErrors('email');
});
test('email is required', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['email'] = '';
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertSessionHasErrors('email');
});
test('phone must be valid phone number', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['phone'] = '123invalid';
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertSessionHasErrors('phone');
});
test('phone is required', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['phone'] = '';
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertSessionHasErrors('phone');
});
test('about_app is required', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['about_app'] = '';
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertSessionHasErrors('about_app');
});
test('address is required', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['address'] = '';
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertSessionHasErrors('address');
});
test('logo must be an image when provided', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['logo'] = UploadedFile::fake()->create('document.pdf', 100);
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertSessionHasErrors('logo');
});
test('favicon must be an image when provided', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SYSTEM, PermissionEnum::SETTINGS_UPDATE_SYSTEM);
$payload = validSystemPayload();
$payload['favicon'] = UploadedFile::fake()->create('document.pdf', 100);
$this->actingAs($user)
->put(route('admin.system.settings.system.update'), $payload)
->assertSessionHasErrors('favicon');
});
});
// ─── Update Social Media ──────────────────────────────────
describe('Setting Update Social Media', function () {
test('authenticated user can update social media settings', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SOCIAL_MEDIA, PermissionEnum::SETTINGS_UPDATE_SOCIAL_MEDIA);
$this->actingAs($user)
->put(route('admin.system.settings.social_media.update'), [
'instagram_url' => 'https://instagram.com/dstcollection',
'facebook_url' => 'https://facebook.com/dstcollection',
'tiktok_url' => 'https://tiktok.com/@dstcollection',
])
->assertRedirect(route('admin.system.settings.index'));
$this->assertDatabaseHas('settings', [
'group' => 'social_media',
'name' => 'instagram_url',
]);
});
test('guest cannot update social media settings', function () {
$this->put(route('admin.system.settings.social_media.update'), [
'instagram_url' => 'https://instagram.com/test',
])->assertRedirect(route('login'));
});
test('user without update permission is forbidden', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SOCIAL_MEDIA);
$this->actingAs($user)
->put(route('admin.system.settings.social_media.update'), [
'instagram_url' => 'https://instagram.com/test',
])
->assertForbidden();
});
test('social media urls can be null', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SOCIAL_MEDIA, PermissionEnum::SETTINGS_UPDATE_SOCIAL_MEDIA);
$this->actingAs($user)
->put(route('admin.system.settings.social_media.update'), [
'instagram_url' => null,
'facebook_url' => null,
'tiktok_url' => null,
])
->assertRedirect(route('admin.system.settings.index'));
$this->assertDatabaseHas('settings', [
'group' => 'social_media',
'name' => 'instagram_url',
]);
});
test('instagram_url must be a valid url', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SOCIAL_MEDIA, PermissionEnum::SETTINGS_UPDATE_SOCIAL_MEDIA);
$this->actingAs($user)
->put(route('admin.system.settings.social_media.update'), [
'instagram_url' => 'not-a-url',
])
->assertSessionHasErrors('instagram_url');
});
test('facebook_url must be a valid url', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SOCIAL_MEDIA, PermissionEnum::SETTINGS_UPDATE_SOCIAL_MEDIA);
$this->actingAs($user)
->put(route('admin.system.settings.social_media.update'), [
'facebook_url' => 'not-a-url',
])
->assertSessionHasErrors('facebook_url');
});
test('tiktok_url must be a valid url', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_SOCIAL_MEDIA, PermissionEnum::SETTINGS_UPDATE_SOCIAL_MEDIA);
$this->actingAs($user)
->put(route('admin.system.settings.social_media.update'), [
'tiktok_url' => 'not-a-url',
])
->assertSessionHasErrors('tiktok_url');
});
});
// ─── Update Marketplace ───────────────────────────────────
describe('Setting Update Marketplace', function () {
test('authenticated user can update marketplace settings', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_MARKETPLACE, PermissionEnum::SETTINGS_UPDATE_MARKETPLACE);
$payload = allMarketplaceFeeFields();
$this->actingAs($user)
->put(route('admin.system.settings.marketplace.update'), $payload)
->assertRedirect(route('admin.system.settings.index'));
$this->assertDatabaseHas('settings', [
'group' => 'marketplace',
'name' => 'tiktok_shop_platform_commission',
]);
});
test('guest cannot update marketplace settings', function () {
$this->put(route('admin.system.settings.marketplace.update'), allMarketplaceFeeFields())
->assertRedirect(route('login'));
});
test('user without update permission is forbidden', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_MARKETPLACE);
$this->actingAs($user)
->put(route('admin.system.settings.marketplace.update'), allMarketplaceFeeFields())
->assertForbidden();
});
test('marketplace fee scope must be valid enum', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_MARKETPLACE, PermissionEnum::SETTINGS_UPDATE_MARKETPLACE);
$payload = allMarketplaceFeeFields();
$payload['tiktok_shop_platform_commission']['scope'] = 'invalid';
$this->actingAs($user)
->put(route('admin.system.settings.marketplace.update'), $payload)
->assertSessionHasErrors('tiktok_shop_platform_commission.scope');
});
test('marketplace fee value_type must be valid enum', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_MARKETPLACE, PermissionEnum::SETTINGS_UPDATE_MARKETPLACE);
$payload = allMarketplaceFeeFields();
$payload['tiktok_shop_platform_commission']['value_type'] = 'invalid';
$this->actingAs($user)
->put(route('admin.system.settings.marketplace.update'), $payload)
->assertSessionHasErrors('tiktok_shop_platform_commission.value_type');
});
test('marketplace fee value must be numeric', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_MARKETPLACE, PermissionEnum::SETTINGS_UPDATE_MARKETPLACE);
$payload = allMarketplaceFeeFields();
$payload['tiktok_shop_platform_commission']['value'] = 'not-a-number';
$this->actingAs($user)
->put(route('admin.system.settings.marketplace.update'), $payload)
->assertSessionHasErrors('tiktok_shop_platform_commission.value');
});
test('marketplace fee percent value must not exceed 100', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_MARKETPLACE, PermissionEnum::SETTINGS_UPDATE_MARKETPLACE);
$payload = allMarketplaceFeeFields();
$payload['tiktok_shop_platform_commission']['value_type'] = 'percent';
$payload['tiktok_shop_platform_commission']['value'] = 150.0;
$this->actingAs($user)
->put(route('admin.system.settings.marketplace.update'), $payload)
->assertSessionHasErrors('tiktok_shop_platform_commission.value');
});
test('marketplace flat fee must not have decimals', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_MARKETPLACE, PermissionEnum::SETTINGS_UPDATE_MARKETPLACE);
$payload = allMarketplaceFeeFields();
$payload['shopee_admin_fee']['value_type'] = 'flat';
$payload['shopee_admin_fee']['value'] = 1500.5;
$this->actingAs($user)
->put(route('admin.system.settings.marketplace.update'), $payload)
->assertSessionHasErrors('shopee_admin_fee.value');
});
});
// ─── Update HR ────────────────────────────────────────────
describe('Setting Update HR', function () {
test('authenticated user can update HR settings', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HR, PermissionEnum::SETTINGS_UPDATE_HR);
$this->actingAs($user)
->put(route('admin.system.settings.hr.update'), [
'scheduled_check_in_time' => '09:00',
'scheduled_check_out_time' => '18:00',
'late_penalty_amount' => 50000,
'absent_penalty_amount' => 100000,
])
->assertRedirect(route('admin.system.settings.index'));
$this->assertDatabaseHas('settings', [
'group' => 'hr',
'name' => 'scheduled_check_in_time',
]);
$this->assertDatabaseHas('settings', [
'group' => 'hr',
'name' => 'late_penalty_amount',
]);
});
test('guest cannot update HR settings', function () {
$this->put(route('admin.system.settings.hr.update'), [
'scheduled_check_in_time' => '09:00',
'scheduled_check_out_time' => '18:00',
'late_penalty_amount' => 0,
'absent_penalty_amount' => 0,
])->assertRedirect(route('login'));
});
test('user without update permission is forbidden', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HR);
$this->actingAs($user)
->put(route('admin.system.settings.hr.update'), [
'scheduled_check_in_time' => '09:00',
'scheduled_check_out_time' => '18:00',
'late_penalty_amount' => 0,
'absent_penalty_amount' => 0,
])
->assertForbidden();
});
test('scheduled_check_in_time is required', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HR, PermissionEnum::SETTINGS_UPDATE_HR);
$this->actingAs($user)
->put(route('admin.system.settings.hr.update'), [
'scheduled_check_in_time' => '',
'scheduled_check_out_time' => '18:00',
'late_penalty_amount' => 0,
'absent_penalty_amount' => 0,
])
->assertSessionHasErrors('scheduled_check_in_time');
});
test('scheduled_check_in_time must match HH:MM format', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HR, PermissionEnum::SETTINGS_UPDATE_HR);
$this->actingAs($user)
->put(route('admin.system.settings.hr.update'), [
'scheduled_check_in_time' => '9:00',
'scheduled_check_out_time' => '18:00',
'late_penalty_amount' => 0,
'absent_penalty_amount' => 0,
])
->assertSessionHasErrors('scheduled_check_in_time');
});
test('scheduled_check_out_time is required', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HR, PermissionEnum::SETTINGS_UPDATE_HR);
$this->actingAs($user)
->put(route('admin.system.settings.hr.update'), [
'scheduled_check_in_time' => '09:00',
'scheduled_check_out_time' => '',
'late_penalty_amount' => 0,
'absent_penalty_amount' => 0,
])
->assertSessionHasErrors('scheduled_check_out_time');
});
test('late_penalty_amount must be integer', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HR, PermissionEnum::SETTINGS_UPDATE_HR);
$this->actingAs($user)
->put(route('admin.system.settings.hr.update'), [
'scheduled_check_in_time' => '09:00',
'scheduled_check_out_time' => '18:00',
'late_penalty_amount' => 'not-a-number',
'absent_penalty_amount' => 0,
])
->assertSessionHasErrors('late_penalty_amount');
});
test('late_penalty_amount must not be negative', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HR, PermissionEnum::SETTINGS_UPDATE_HR);
$this->actingAs($user)
->put(route('admin.system.settings.hr.update'), [
'scheduled_check_in_time' => '09:00',
'scheduled_check_out_time' => '18:00',
'late_penalty_amount' => -1000,
'absent_penalty_amount' => 0,
])
->assertSessionHasErrors('late_penalty_amount');
});
test('absent_penalty_amount must be integer', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HR, PermissionEnum::SETTINGS_UPDATE_HR);
$this->actingAs($user)
->put(route('admin.system.settings.hr.update'), [
'scheduled_check_in_time' => '09:00',
'scheduled_check_out_time' => '18:00',
'late_penalty_amount' => 0,
'absent_penalty_amount' => 'not-a-number',
])
->assertSessionHasErrors('absent_penalty_amount');
});
});
// ─── Update Homepage ──────────────────────────────────────
describe('Setting Update Homepage', function () {
test('authenticated user can update homepage settings', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HOMEPAGE, PermissionEnum::SETTINGS_UPDATE_HOMEPAGE);
$this->actingAs($user)
->put(route('admin.system.settings.homepage.update'), [])
->assertRedirect(route('admin.system.settings.index'));
});
test('guest cannot update homepage settings', function () {
$this->put(route('admin.system.settings.homepage.update'), [])
->assertRedirect(route('login'));
});
test('user without update permission is forbidden', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HOMEPAGE);
$this->actingAs($user)
->put(route('admin.system.settings.homepage.update'), [])
->assertForbidden();
});
test('hero_image must be an image when provided', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HOMEPAGE, PermissionEnum::SETTINGS_UPDATE_HOMEPAGE);
$this->actingAs($user)
->put(route('admin.system.settings.homepage.update'), [
'hero_image' => UploadedFile::fake()->create('document.pdf', 100),
])
->assertSessionHasErrors('hero_image');
});
test('about_image must be an image when provided', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HOMEPAGE, PermissionEnum::SETTINGS_UPDATE_HOMEPAGE);
$this->actingAs($user)
->put(route('admin.system.settings.homepage.update'), [
'about_image' => UploadedFile::fake()->create('document.pdf', 100),
])
->assertSessionHasErrors('about_image');
});
test('gallery_images must be an array of images', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HOMEPAGE, PermissionEnum::SETTINGS_UPDATE_HOMEPAGE);
$this->actingAs($user)
->put(route('admin.system.settings.homepage.update'), [
'gallery_images' => ['not-a-file'],
])
->assertSessionHasErrors('gallery_images.0');
});
test('gallery_images must not exceed 10 items', function () {
$user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW_HOMEPAGE, PermissionEnum::SETTINGS_UPDATE_HOMEPAGE);
$images = [];
for ($i = 0; $i < 11; $i++) {
$images[] = UploadedFile::fake()->image("photo-{$i}.jpg");
}
$this->actingAs($user)
->put(route('admin.system.settings.homepage.update'), [
'gallery_images' => $images,
])
->assertSessionHasErrors('gallery_images');
});
});