diff --git a/plugins/_bundled/sirsoft-gdpr/CHANGELOG.md b/plugins/_bundled/sirsoft-gdpr/CHANGELOG.md index 8908bc1b..11705fd0 100644 --- a/plugins/_bundled/sirsoft-gdpr/CHANGELOG.md +++ b/plugins/_bundled/sirsoft-gdpr/CHANGELOG.md @@ -33,6 +33,7 @@ - 관리자 환경설정의 「운영 주체」·「쿠키 배너 노출」·「배너 위치」 필드에서 안내 문구가 길어질 때 입력·토글 컨트롤이 옆이 아닌 아래 줄로 밀려나던 문제를 바로잡았습니다. - 비회원(게스트) 방문자의 쿠키 동의 식별자가 위·변조에 노출되던 문제를 바로잡았습니다 — 다른 방문자의 쿠키 동의 상태를 임의로 조회·변경할 수 없도록 서명을 적용했습니다. 이 조치로 이번 업데이트 이전에 발급된 비회원 쿠키 배너 상태는 1회에 한해 초기화되며, 이미 배너를 닫았던 비회원 방문자는 다음 방문 시 배너를 다시 보게 됩니다(회원 동의 이력은 영향 없음). - 비회원으로 쿠키 배너를 닫은 뒤 동의 이력이 없는 다른 계정으로 로그인하면 배너가 계속 숨겨져 있던 문제를 바로잡았습니다 — 이제 로그인한 계정 기준으로 다시 판단해 배너가 정상적으로 노출됩니다. +- 관리자 환경설정의 「운영 주체」·「쿠키 동의 배너」·「자동 차단 정책」 카드 제목과 차단 도메인 안내 문구가 빨간색(경고 색상)으로 표시되던 문제를 바로잡았습니다 — 일반 안내에도 경고 색상이 쓰여 어색하게 강조되던 부분을 다른 관리자 화면과 동일한 색상으로 정리했습니다. ## [1.0.1] - 2026-07-16 diff --git a/plugins/_bundled/sirsoft-gdpr/resources/js/__tests__/layouts/admin_plugin_settings.test.tsx b/plugins/_bundled/sirsoft-gdpr/resources/js/__tests__/layouts/admin_plugin_settings.test.tsx index 54c239f4..e5fb9dc0 100644 --- a/plugins/_bundled/sirsoft-gdpr/resources/js/__tests__/layouts/admin_plugin_settings.test.tsx +++ b/plugins/_bundled/sirsoft-gdpr/resources/js/__tests__/layouts/admin_plugin_settings.test.tsx @@ -144,9 +144,37 @@ describe('admin/plugin_settings.json — 3 카드 (operator / cookie_banner / au expect(className).toContain('grid-3col-responsive'); }); - it('section-heading-md 는 더 이상 필드 2단 배치 컨테이너로 오용되지 않는다 (텍스트 스타일 전용 클래스)', () => { - const layoutJson = JSON.stringify(root); - expect(layoutJson).not.toContain('"className":"section-heading-md"'); + it('section-heading-md 는 필드 2단 배치 컨테이너로 오용되지 않는다 (해당 4개 필드 컨테이너 한정 검증)', () => { + // 카드 제목(H3)은 section-heading-md 를 정당하게 사용하므로(카드 제목 색상 + // 수정 회귀 가드 참조), 전체 레이아웃 문자열이 아니라 필드 컨테이너 4개만 검증한다. + for (const fieldId of ['field_legal_entity_name', 'field_data_storage_location', 'field_banner_enabled', 'field_banner_position']) { + const field = findById(root, fieldId); + const className = String((field?.props as { className?: string } | undefined)?.className ?? ''); + expect(className).not.toBe('section-heading-md'); + } + }); + }); + + /** + * 카드 제목(H3) 색상 회귀 가드 — text-error-strong(에러/경고 전용 시맨틱, red 계열)이 + * 일반 카드 제목에 오용되어 "운영 주체", "쿠키 동의 배너", "자동 차단 정책" 제목이 빨간색으로 + * 표시되던 결함. 정상 카드 제목 색상은 section-heading-md(중립 톤). + */ + describe('카드 제목 색상 — text-error-strong 오용 회귀 가드', () => { + it.each(['card_operator_header', 'card_cookie_banner_header', 'card_auto_blocking_policy_header'])( + '%s 의 H3 제목이 section-heading-md 를 사용한다 (에러 색상 아님)', + (headerId) => { + const header = findById(root, headerId); + const json = JSON.stringify(header); + expect(json).toContain('"className":"section-heading-md"'); + expect(json).not.toContain('text-error-strong'); + } + ); + + it('차단 도메인 안내 박스(정보 톤)의 소제목도 에러 색상을 사용하지 않는다', () => { + const box = findById(root, 'blocked_domains_warnings_box'); + const json = JSON.stringify(box); + expect(json).not.toContain('text-error-strong'); }); }); @@ -350,8 +378,10 @@ describe('admin/plugin_settings.json — 3 카드 (operator / cookie_banner / au expect(serialized).not.toContain('blocked_domains.preblocker_active'); expect(serialized).not.toContain('blocked_domains.self_hosted_attr'); expect(serialized).not.toContain('blocked_domains.static_html_limitation'); - // 타이틀 강조 — 시맨틱 text-error-strong 로 제목 강조 (#399 시맨틱 통일) - expect(serialized).toContain('text-error-strong'); + // 타이틀 — 안내 박스(정보 톤, circle-info)의 소제목이므로 에러 강조색이 아닌 중립 톤 사용 + // (text-error-strong 은 에러/경고 전용 시맨틱이며 일반 안내 제목에 오용되던 결함을 바로잡음) + expect(serialized).not.toContain('text-error-strong'); + expect(serialized).toContain('text-gray-900'); // 옛 badge 키는 lang 과 박스에서 모두 제거됨 expect(serialized).not.toContain('blocked_domains.warnings_badge'); // 기존 옛 항목 키 미사용 diff --git a/plugins/_bundled/sirsoft-gdpr/resources/layouts/admin/plugin_settings.json b/plugins/_bundled/sirsoft-gdpr/resources/layouts/admin/plugin_settings.json index 4751ca4d..9edbe227 100644 --- a/plugins/_bundled/sirsoft-gdpr/resources/layouts/admin/plugin_settings.json +++ b/plugins/_bundled/sirsoft-gdpr/resources/layouts/admin/plugin_settings.json @@ -259,7 +259,7 @@ "type": "basic", "name": "H3", "props": { - "className": "text-error-strong" + "className": "section-heading-md" }, "text": "$t:sirsoft-gdpr.settings.section.operator" }, @@ -502,7 +502,7 @@ "type": "basic", "name": "H3", "props": { - "className": "text-error-strong" + "className": "section-heading-md" }, "text": "$t:sirsoft-gdpr.settings.section.cookie_banner" }, @@ -1541,7 +1541,7 @@ "type": "basic", "name": "H3", "props": { - "className": "text-error-strong" + "className": "section-heading-md" }, "text": "$t:sirsoft-gdpr.settings.section.auto_blocking" }, @@ -1641,7 +1641,7 @@ "type": "basic", "name": "H4", "props": { - "className": "text-error-strong" + "className": "text-sm font-medium text-gray-900 dark:text-white" }, "text": "$t:sirsoft-gdpr.settings.fields.blocked_domains.warnings_title" } diff --git a/plugins/_bundled/sirsoft-gdpr/tests/Playwright/specs/admin/policy-version-snapshot-link.spec.ts b/plugins/_bundled/sirsoft-gdpr/tests/Playwright/specs/admin/policy-version-snapshot-link.spec.ts index 73927d64..8f707a5f 100644 --- a/plugins/_bundled/sirsoft-gdpr/tests/Playwright/specs/admin/policy-version-snapshot-link.spec.ts +++ b/plugins/_bundled/sirsoft-gdpr/tests/Playwright/specs/admin/policy-version-snapshot-link.spec.ts @@ -1,8 +1,9 @@ /** * E2E: 관리자 환경설정 > 쿠키 배너 > 정책 버전 > 보기 — 본문 페이지 링크 (#509 체크리스트 12번) + * + 관리자 환경설정 카드 제목 색상 회귀 가드 (PO 스크린샷 발견) * * @scenario admin_gdpr_policy_version_snapshot_open_policy_page_link - * @effects snapshot_modal_opens, policy_page_link_href_matches_page_module_url_pattern + * @effects snapshot_modal_opens, policy_page_link_href_matches_page_module_url_pattern, card_title_not_error_color * * 배경: 정책 버전 snapshot 모달의 본문 페이지 링크가 `/{{slug}}` 로 조합되어 페이지 모듈 * (sirsoft-page) 의 실제 URL 패턴 `/page/{slug}` 와 불일치, 클릭 시 404 가 발생하던 결함. @@ -10,16 +11,22 @@ * 포함되므로 (GdprPolicyVersionMigrationSmokeTest 참조), 별도 설정 저장 없이도 v배지 클릭 → * 모달의 본문 페이지 링크 href 를 검증할 수 있다. * + * 또한 카드 제목(H3)이 에러/경고 전용 시맨틱(text-error-strong, red 계열)을 오용해 + * "운영 주체" 등 일반 카드 제목이 빨간색으로 표시되던 결함을 PO 가 스크린샷으로 발견해 + * section-heading-md(중립 톤)로 수정 — 실제 렌더링된 색상을 브라우저에서 검증한다. + * * 검증: * 1. 환경설정 화면에서 v배지 옆 "본문 보기" 버튼 클릭 시 snapshot 모달이 열린다 * 2. 모달의 본문 페이지 링크 href 가 `/page/{slug}` 형식으로 조합되어 페이지 모듈 URL 패턴과 일치한다 * (프리픽스 누락으로 `/{slug}` 형태가 되는 결함 패턴이 재발하지 않았는지 회귀 가드) + * 3. 「운영 주체 / 개인정보처리방침」 카드 제목이 에러 색상(red 계열)이 아닌 중립 톤으로 렌더링된다 */ import { test, expect, authenticatePage } from '../../fixtures/gdpr-auth'; const CARD_COOKIE_BANNER = '#card_cookie_banner'; const SNAPSHOT_VIEW_BUTTON = '#policy_version_current_snapshot_view_button'; const OPEN_POLICY_PAGE_LINK = '#policy_version_snapshot_open_policy_page_link'; +const CARD_OPERATOR_HEADER = '#card_operator_header h3'; /** 관리자 GDPR 환경설정 진입 후 쿠키 배너 탭(정책 버전 UI 포함)으로 스크롤 이동 */ async function gotoGdprSettings(page: import('@playwright/test').Page): Promise { @@ -51,3 +58,21 @@ test('#509 - 정책 버전 snapshot 모달의 본문 페이지 링크가 /page/{ expect(href).toMatch(/^\/page\/.+/); expect(href).not.toMatch(/^\/(?!page\/)/); }); + +// @scenario tab=card_operator, permitted=yes +// @effects card_title_not_error_color +test('#509 - 관리자 환경설정 카드 제목이 에러 색상(빨간색)으로 표시되지 않는다', async ({ page, privacyManageToken }) => { + await authenticatePage(page, privacyManageToken); + await gotoGdprSettings(page); + + const header = page.locator(CARD_OPERATOR_HEADER); + await expect(header).toBeVisible({ timeout: 10_000 }); + + const color = await header.evaluate((el) => getComputedStyle(el).color); + // text-error-strong(text-red-800/dark:text-red-200) 이 남아있다면 rgb 값의 R 채널이 + // G/B 채널보다 뚜렷이 높은 붉은 계열로 계산된다. 정상(중립 톤)은 R≈G≈B. + const rgbMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/); + expect(rgbMatch).not.toBeNull(); + const [, r, g, b] = rgbMatch as unknown as [string, string, string, string]; + expect(Number(r) - Math.max(Number(g), Number(b))).toBeLessThan(40); +});