문서 목차
이 페이지에서목차

골든 게이트

coui 교체는 앱 코드를 한 줄도 안 바꿔도 화면을 바꾼다. 컴파일·단위 테스트로는 못 잡으므로 렌더를 이미지로 고정해 두는 골든이 유일한 안전망이다. 1~6절은 Flutter 앱(flutter_test 골든), 7절은 Jaspr 웹 앱이다.

coui 교체는 앱 코드를 한 줄도 안 바꿔도 화면을 바꾼다. 컴파일·단위 테스트로는 못 잡으므로 렌더를 이미지로 고정해 두는 골든이 유일한 안전망이다. 1~6절은 Flutter 앱(flutter_test 골든), 7절은 Jaspr 웹 앱이다.

1. 층위#

한 번에 다 만들 필요는 없지만, 올리기 전에 최소 L1 은 있어야 한다.

층대상잡는 것
L0토큰 스냅샷(색·간격·반경·타이포 값을 JSON 등으로)토큰 값·의미 변화(이름은 같은데 값이 바뀜)
L1컴포넌트 골든(변형·크기·상태 매트릭스)배율·floor·기본값 변화
L2 컴포넌트 크기·기하 assert(geometry.json 류) 픽셀 비교가 놓치는 크기·위치 변화의 원인 파악
L3대표 화면 골든조합에서만 드러나는 변화

안전망을 만들었으면 의도적으로 값을 몇 개 바꿔(변이) 골든이 실제로 실패하는지 확인한다.

2. 결정성 조건#

  • 같은 조건으로 2회 연속 동일해야 기준선으로 쓴다.
  • 실제 앱 폰트를 로드한다. 폴백 폰트 골든은 폰트 회귀를 못 잡는다(폰트가 제대로 해석되는지 따로 assert 하는 테스트를 둔다).
  • 앱과 같은 배율·논리 폭으로 마운트한다. 태블릿 가로 등 앱이 지원하는 폭이 여럿이면 매트릭스로.
  • 그림자를 검증할 셀은 debugDisableShadows = false(flutter_test 기본은 그림자 끔).
  • 네트워크 아이콘은 번들 등록 후 찍는다(안 그러면 빈 박스가 기준선이 된다).

3. 핀을 올린 뒤#

  1. 골든 보유 패키지 전부를 돌린다. 바꾼 파일이 있는 패키지만 돌리지 않는다.
    • 찾기: find . -type d -path '*/test/golden' -not -path '*/.dart_tool/*'(프로젝트 규약이 다르면 프로필 값을 쓴다)
    • 실행: 패키지마다 flutter test test/golden
    • 파일명(*golden*_test.dart)으로 찾지 않는다 — 토큰 스냅샷·폰트 해석 테스트처럼 이름에 golden 이 없는 파일을 놓친다.
  2. 먼저 갱신 없이 돌려 실패 목록을 받는다.
  3. base 브랜치 상태로 되돌린 같은 검사를 돌려 "이번 변경분"과 "원래 깨져 있던 것"을 가른다.
  4. 의도한 차이만 --update-goldens 로 재생성하고, 바뀐 PNG 를 전후 나란히 본다. 기하 스냅샷이 있으면 위치·크기가 안 바뀌었는지 diff 로 확인한다.
  5. 재생성 이유를 승인 기록(프로필이 가리키는 장부 또는 PR 본문)에 남긴다: 무엇이, 왜, 어느 coui 버전 때문에.

PR CI 가 꺼져 있거나 골든을 CI 에서 안 돌리는 저장소에서는 이 단계를 빼먹으면 기본 브랜치가 조용히 빨개진다.

4. 셀 작성 규칙#

  • 기본값을 검증하는 셀은 그 값을 명시하지 않는다. 기본 테마 셀이 테두리색을 직접 넘기면 전역 기본값 회귀를 통과시킨다.
  • 셀 이름에 무엇을 고정하는지 드러낸다(card_default_theme, button_primary_sm_disabled).
  • 한 셀이 여러 원인으로 깨질 수 있으면 나눈다 — 실패 원인을 좁히기 위해서다.

5. SDK 만 올릴 때#

Flutter SDK 상향만으로도 안티에일리어싱·포커스 캐럿 등에서 미세한 차이가 난다. coui 교체와 섞이지 않게 SDK 를 먼저 따로 올리고, 그때 생긴 차이를 별도로 승인 기록한다. 채널 차이 기준(예: 2/255 이상 픽셀 비율)으로 허용 오차를 두는 게이트라면 임계값을 장부에 적는다.

6. 자동 재생성 봇이 있는 저장소#

골든을 자동으로 재생성해 PR 을 여는 봇이 있으면 편하지만, 시각 회귀가 "PNG 갱신"으로 묻힐 수 있다. 봇 PR 의 이미지 diff 는 사람이 본다.

7. 웹 앱(coui_web)#

flutter_test 골든은 Jaspr 웹 앱에 없다. 16절의 원칙(올리기 전 안전망, 2회 연속 동일, 전수 실행, base 대조, 승인 기록)은 같고 수단만 다르다. coui_flutter 를 웹으로 빌드하는 앱은 16절 그대로다.

층수단잡는 것못 잡는 것
W0 테마 출력 스냅샷(tailwindConfig·cssVariables 출력을 파일로) 토큰·설정 변화 렌더
W1 SSR 마크업 스냅샷(주요 페이지를 testServer 로 렌더해 정규화한 body HTML·클래스 토큰 집합) 마크업·클래스·inline 스타일 변화 픽셀·폰트 메트릭·레이아웃·아이콘
W2헤드리스 Chrome 캡처 A/B실제 렌더아래 조건을 안 지키면 환경 차이가 섞인다

W1 정규화 — 일부 컴포넌트가 내는 co-<컴포넌트>-<해시> 생성 id 와 그 id 를 쓰는 <style> 셀렉터를 자리표시자로 치환한다(또는 그 인스턴스에 id 를 명시한다). 테마 색 모드는 명시한다. 두 번 렌더해 같을 때만 결정적으로 본다.

W2 결정성 조건

  • 같은 기계·같은 Chrome 에서 옛 핀 → 새 핀 순서로 찍는다. Chrome 버전을 기록하고 OS 가 다른 캡처를 섞지 않는다.
  • 뷰포트와 devicePixelRatio 를 고정한다.
  • 애니메이션·전환을 끈다: *, *::before, *::after { animation: none !important; transition: none !important; }.
  • document.fonts.ready 를 기다리고, 아이콘은 뷰포트에 들어온 뒤 렌더되므로 대상까지 스크롤하거나 SVG 가 생길 때까지 기다린다(외부 요청을 막을 거라면 아이콘 데이터를 미리 싣는다).
  • 동적 데이터·인증 화면은 fixture 로 고정한다.
  • 판정 임계값은 5절과 같은 수준(예: 채널 차 2/255 이상인 픽셀 비율)으로 두고 장부에 적는다. 렌더러가 다른 비교(Flutter↔웹 패리티)용 느슨한 임계값을 옮기지 않는다 — 작은 색 토큰 변화(예: 테두리 토큰 교체)가 "같음"으로 판정된다.

/cc-jaspr-web:regression 으로 캡처를 돌릴 수 있다. 쓸 때 확인할 것: 애니메이션 동결 CSS 가 ::before/::after 까지 덮는지, 허용치 단위(색 차이 ΔE 등)가 장부의 임계값과 같은 뜻인지.

핀을 올린 뒤 — W0·W1 을 갱신 없이 diff 한다. coui 저장소에 웹 렌더 기준선이 있으면(목표 태그에서 경로 확인) 두 태그 사이 웹 기준선 diff 로 바뀐 컴포넌트를 먼저 추리고, 그 컴포넌트를 쓰는 화면을 W2 로 본다. CSS 를 미리 컴파일하는 앱은 CSS 를 재생성한 뒤 W2 를 찍는다.

검색어를 입력하면 문서를 찾습니다.

↑ ↓ 이동 · Enter 열기Esc 닫기