markTestSkipped( 'sirsoft-ecommerce 모듈이 활성 디렉토리에 설치되지 않은 환경 — ' .'본 테스트는 module:seed → entity 시더 → ja 자동 동기 production 경로를 검증하므로 ' .'php artisan module:install sirsoft-ecommerce 후 재실행 (또는 CI 환경에서 자동 통과)' ); } // module:seed 가 outer transaction 외부에서 commit 한 데이터 정리 DB::table('language_packs') ->where('target_identifier', 'sirsoft-ecommerce') ->where('locale', 'ja') ->delete(); DB::table('ecommerce_shipping_types')->where('id', '>', 0)->delete(); DB::table('ecommerce_shipping_carriers')->where('id', '>', 0)->delete(); DB::table('ecommerce_claim_reasons')->where('id', '>', 0)->delete(); // 본 테스트는 lang pack 활성 hook 이 LanguagePack::resolveDirectory() → // base_path('lang-packs/{identifier}/seed/*.json') 을 읽어 ja 키를 주입하는 경로를 검증한다. // 활성 디렉토리가 부재한 dev 환경(사용자가 language-pack:install 미실행) 에서도 테스트가 동작하도록, // _bundled 원본을 활성 경로에 복사한다 (RefreshDatabase 가 파일시스템에 영향을 주지 않으므로 영구). $bundledDir = base_path('lang-packs/_bundled/g7-module-sirsoft-ecommerce-ja'); $activeDir = base_path('lang-packs/g7-module-sirsoft-ecommerce-ja'); if (\Illuminate\Support\Facades\File::isDirectory($bundledDir) && ! \Illuminate\Support\Facades\File::isDirectory($activeDir)) { \Illuminate\Support\Facades\File::copyDirectory($bundledDir, $activeDir); } app()->forgetInstance(LanguagePackRegistry::class); } public function test_module_lang_pack_activation_triggers_shipping_types_seeder(): void { $this->ensureSeeded(); $pack = $this->createEcommerceJaLanguagePack(LanguagePackStatus::Inactive); $pack->update([ 'status' => LanguagePackStatus::Active->value, 'activated_at' => now(), ]); $this->refreshLanguagePackRegistry(); HookManager::doAction('core.language_packs.activated', $pack->fresh()); $this->assertJaKeyPresentInTable('ecommerce_shipping_types'); } public function test_module_lang_pack_activation_triggers_shipping_carriers_seeder(): void { $this->ensureSeeded(); $pack = $this->createEcommerceJaLanguagePack(LanguagePackStatus::Inactive); $pack->update([ 'status' => LanguagePackStatus::Active->value, 'activated_at' => now(), ]); $this->refreshLanguagePackRegistry(); HookManager::doAction('core.language_packs.activated', $pack->fresh()); $this->assertJaKeyPresentInTable('ecommerce_shipping_carriers'); } public function test_module_lang_pack_activation_triggers_claim_reasons_seeder(): void { $this->ensureSeeded(); $pack = $this->createEcommerceJaLanguagePack(LanguagePackStatus::Inactive); $pack->update([ 'status' => LanguagePackStatus::Active->value, 'activated_at' => now(), ]); $this->refreshLanguagePackRegistry(); HookManager::doAction('core.language_packs.activated', $pack->fresh()); $this->assertJaKeyPresentInTable('ecommerce_claim_reasons'); } public function test_user_overridden_ko_is_preserved_while_ja_auto_synced(): void { $this->ensureSeeded(); DB::table('ecommerce_shipping_types') ->where('code', 'parcel') ->update([ 'name' => json_encode(['ko' => '사용자 수정 ko', 'en' => 'Parcel']), 'user_overrides' => json_encode(['name.ko']), ]); $pack = $this->createEcommerceJaLanguagePack(LanguagePackStatus::Inactive); $pack->update([ 'status' => LanguagePackStatus::Active->value, 'activated_at' => now(), ]); $this->refreshLanguagePackRegistry(); HookManager::doAction('core.language_packs.activated', $pack->fresh()); $row = DB::table('ecommerce_shipping_types')->where('code', 'parcel')->first(['name']); $name = json_decode($row->name, true); $this->assertEquals('사용자 수정 ko', $name['ko'] ?? null, 'ko 사용자 수정 보존'); $this->assertNotNull($name['ja'] ?? null, 'ja 자동 동기화'); } private function ensureSeeded(): void { // RefreshDatabase 환경 — 시더 클래스 직접 호출 (outer transaction 안에서) $this->runSeeder(ShippingTypeSeeder::class); $this->runSeeder(ShippingCarrierSeeder::class); $this->runSeeder(ClaimReasonSeeder::class); } private function runSeeder(string $seederClass): void { $seeder = app($seederClass); // Seeder->run() 안에서 $this->command->info() 호출 가능하도록 dummy command 주입 $command = new \Illuminate\Console\Command(); $command->setOutput(new \Illuminate\Console\OutputStyle( new \Symfony\Component\Console\Input\ArrayInput([]), new BufferedOutput(), )); $seeder->setCommand($command); $seeder->run(); } private function assertJaKeyPresentInTable(string $table): void { $rows = DB::table($table)->get(['id', 'name']); $this->assertNotEmpty($rows, "{$table} 시더가 row 를 생성해야 함"); foreach ($rows as $row) { $name = json_decode($row->name, true) ?: []; $this->assertArrayHasKey('ja', $name, "{$table} row#{$row->id} 의 name 에 ja 키 누락"); } } private function createEcommerceJaLanguagePack(LanguagePackStatus $status): LanguagePack { return LanguagePack::create([ 'identifier' => 'g7-module-sirsoft-ecommerce-ja', 'vendor' => 'g7', 'name' => 'Ecommerce JA Language Pack', 'version' => '1.0.0-beta.1', 'scope' => LanguagePackScope::Module->value, 'target_identifier' => 'sirsoft-ecommerce', 'locale' => 'ja', 'locale_name' => 'Japanese', 'locale_native_name' => '日本語', 'text_direction' => 'ltr', 'is_protected' => false, 'manifest' => [ 'identifier' => 'g7-module-sirsoft-ecommerce-ja', 'scope' => 'module', 'target_identifier' => 'sirsoft-ecommerce', 'locale' => 'ja', ], 'status' => $status->value, 'source_type' => LanguagePackSourceType::Bundled->value, 'installed_at' => now(), 'activated_at' => $status === LanguagePackStatus::Active ? now() : null, ]); } private function refreshLanguagePackRegistry(): void { app()->forgetInstance(LanguagePackRegistry::class); $registry = app(LanguagePackRegistry::class); config([ 'app.supported_locales' => $registry->getActiveCoreLocales(), 'app.locale_names' => $registry->getLocaleNames(), 'app.translatable_locales' => $registry->getActiveCoreLocales(), ]); } }