*/ protected array $requiredExtensions = [ 'plugins/sirsoft-gdpr', ]; private TemplateService $templateService; private Template $template; protected function setUp(): void { parent::setUp(); $this->templateService = app(TemplateService::class); // 실제 활성 템플릿 — serveLanguage 가 status=Active + template.json 을 요구한다. $this->templateService->installTemplate('sirsoft-admin_basic'); $this->template = Template::where('identifier', 'sirsoft-admin_basic')->first(); $this->templateService->activateTemplate($this->template->id); Cache::flush(); } public function test_serve_language_response_includes_custom_translation_key(): void { TemplateCustomTranslation::create([ 'template_id' => $this->template->id, 'layout_name' => 'home', 'translation_key' => 'custom.home.1', 'values' => ['ko' => '커스텀안녕', 'en' => 'custom hello'], 'status' => 'active', 'lock_version' => 0, ]); $response = $this->getJson('/api/templates/sirsoft-admin_basic/lang/ko.json'); $response->assertStatus(200); // 점 경로 custom.home.1 이 응답 트리에 병합되어 ko 값으로 해석됨 $response->assertJsonPath('custom.home.1', '커스텀안녕'); } public function test_serve_language_resolves_locale_specific_value(): void { TemplateCustomTranslation::create([ 'template_id' => $this->template->id, 'layout_name' => 'home', 'translation_key' => 'custom.home.1', 'values' => ['ko' => '커스텀안녕', 'en' => 'custom hello'], 'status' => 'active', 'lock_version' => 0, ]); $response = $this->getJson('/api/templates/sirsoft-admin_basic/lang/en.json'); $response->assertStatus(200); $response->assertJsonPath('custom.home.1', 'custom hello'); } public function test_orphaned_custom_key_not_served(): void { TemplateCustomTranslation::create([ 'template_id' => $this->template->id, 'layout_name' => 'home', 'translation_key' => 'custom.home.1', 'values' => ['ko' => '고아', 'en' => 'orphan'], 'status' => 'orphaned', 'lock_version' => 0, ]); $response = $this->getJson('/api/templates/sirsoft-admin_basic/lang/ko.json'); $response->assertStatus(200); $this->assertNull(data_get($response->json(), 'custom.home.1')); } public function test_cache_invalidation_serves_fresh_keys_on_new_cache_version(): void { // 초기 응답 (v0) — 커스텀 키 없음, 캐시에 저장됨 $first = $this->getJson('/api/templates/sirsoft-admin_basic/lang/ko.json?v=0'); $first->assertStatus(200); $this->assertNull(data_get($first->json(), 'custom.home.1')); // 커스텀 키 생성 → Service 가 ext.cache_version 을 bump app(TemplateCustomTranslationService::class)->createKey( $this->template->id, 'home', 'ko', '신규키', ); $newVersion = (int) app(CacheInterface::class)->get('ext.cache_version', 0); $this->assertGreaterThan(0, $newVersion); // 새 캐시 버전으로 재요청 → 캐시 미스 → 커스텀 키 포함된 신선한 응답 $second = $this->getJson("/api/templates/sirsoft-admin_basic/lang/ko.json?v={$newVersion}"); $second->assertStatus(200); $second->assertJsonPath('custom.home.1', '신규키'); } public function test_stale_cache_version_still_serves_old_snapshot(): void { // v0 응답을 먼저 캐시에 적재 (커스텀 키 없음) $this->getJson('/api/templates/sirsoft-admin_basic/lang/ko.json?v=0')->assertStatus(200); TemplateCustomTranslation::create([ 'template_id' => $this->template->id, 'layout_name' => 'home', 'translation_key' => 'custom.home.1', 'values' => ['ko' => '나중', 'en' => 'later'], 'status' => 'active', 'lock_version' => 0, ]); // 동일 v0 재요청 → 캐시 히트 → 옛 스냅샷(커스텀 키 부재) $cached = $this->getJson('/api/templates/sirsoft-admin_basic/lang/ko.json?v=0'); $cached->assertStatus(200); $this->assertNull(data_get($cached->json(), 'custom.home.1')); } }