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); $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, PermissionEnum::SETTINGS_UPDATE); $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); $this->actingAs($user) ->put(route('admin.system.settings.system.update'), validSystemPayload()) ->assertForbidden(); }); test('app_name is required', function () { $user = createSettingUserWithPermission(PermissionEnum::SETTINGS_VIEW, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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, PermissionEnum::SETTINGS_UPDATE); $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'); }); });