UI 검증
화면을 구축하는 것은 첫 번째 단계에 불과합니다. UI 변경 사항은 실제 브라우저에서 구동되고 스크린샷이 PR에 포함될 때 비로소 완료됩니다. 깔끔한 타입 검사, 린트 실행, 단위 테스트 결과는 코드가 컴파일되고 로직이 유효함을 의미합니다. 어떤 것도 패널이 렌더링되거나, 푸터가 디자인에서 의도한 위치에 있는지를 말해주지 않습니다. 브랜치를 직접 실행하지 않는 리뷰어는 스크린샷으로 작업을 평가하며, 그렇지 않으면 평가하지 않습니다.
1. 실제 브라우저에서, 실제 데이터로 구동하세요
모의 객체(mock)가 아닌 실제 (시드된) 데이터베이스를 사용하는 실행 중인 앱을 사용하세요. 단순히 행복 경로(happy path)의 스크린샷만으로는 충분하지 않습니다. 디자인에서 명명한 모든 상태와 명명하지 않은 상태를 모두 살펴보세요:
- 두 테마 모두. 수동으로 작성한 색상은 다크 모드 변형이 잊혀지기 쉬운 부분입니다.
- 모바일과 데스크톱. 레이아웃은 중단점(breakpoint)에서 재정렬되며, 푸터와 툴바는 콘텐츠의 절반이 잘릴 수 있습니다.
- 빈 상태, 로딩 중, 한계 도달, 실패 상태 – 데이터가 채워진 상태만 확인하지 마세요.
- 모든 전환 지점 – 하나의 다이얼로그나 뷰가 닫히고 다른 것이 열리는 모든 지점.
- 추가한 모든 메뉴, 팝오버, 드롭다운을 열어보세요. 한 번도 열지 않은 메뉴는 페이지를 열 때 충돌하는 메뉴와 동일하게 보입니다.
- 진행하면서 브라우저 콘솔과 네트워크 패널에서 오류를 확인하세요.
2. 리뷰 스윕 실행
변경 사항을 저장소에서 사용하는 디자인 및 프레임워크 가이드라인(디자인 시스템, 접근성, 프레임워크 모범 사례)과 비교하여 리뷰하세요. 에이전트가 하위 에이전트를 생성할 수 있다면, 각 가이드라인당 하나의 리뷰어를 더 저렴한 모델에서 병렬로 실행하세요. 이는 패턴 매칭 작업이지 판단 작업이 아닙니다.
- 리뷰어에게 저장소 자체 규칙을 제공하세요. 규칙을 읽지 않은 리뷰어는 문서화된 결정 사항을 위반으로 보고할 수 있습니다.
- 리뷰어에게 보고만 하라고 지시하세요. 그런 다음 실제 확률에 따라 각 결과를 직접 판단하세요. 다른 제품에 해당하는 결과(예: 수십 개의 행으로 제한된 목록에 가상화(virtualisation) 조언)는 거부하세요.
3. PR을 위한 스크린샷 캡처
화면에 대한 설명이 아닌, 화면 자체를 캡처하세요. 캡처하는 것은 실제로 보지 않은 상태를 발견하는 가장 저렴한 방법이기도 합니다.
- 실제 앱을 구동하세요. 각 상태에 도달하는 임시 브라우저 스크립트면 충분합니다. E2E 도구의 시드 헬퍼를 사용하여 일반적인 UI 흐름으로는 도달할 수 없는 상태에 도달하고, 이미지가 생성되면 스크립트를 삭제하세요. 이는 아무것도 단언(assert)하지 않으며 커버리지가 아닙니다.
- 캡처 전에 다시 빌드하세요. 그렇지 않으면 방금 수정한 버그를 스크린샷으로 찍을 수 있습니다.
- 셔터 전에 애니메이션이 끝날 때까지 기다리세요. "보임"은 요소가 레이아웃될 때 해결되지만, 진입 트랜지션이 끝날 때 해결되는 것은 아닙니다. 따라서 단순한 캡처는 배경이 없는 반 투명 다이얼로그를 보여줄 수 있습니다. 유한 애니메이션(스켈레톤 펄스와 같은 무한 애니메이션은 제외)이 끝날 때까지 타임아웃을 설정하고 기다리세요.
- 가능한 경우 사용자가 하는 방식으로 각 상태에 도달하세요. 플래그를 강제로 설정하면 버그를 노출시킬 수 있는 경쟁 조건(race)을 건너뛰게 됩니다.
docs/screenshots/<주제>/에 커밋하세요. 해당 디자인이 있다면 그 디자인 옆에 두세요.- 브랜치가 아닌 커밋 SHA로 참조하세요. 예:
https://github.com/<org>/<repo>/blob/<sha>/<path>?raw=true. 브랜치 URL은 병합 시 브랜치가 삭제되면서 사라지고, PR에는 깨진 이미지만 가득 남게 됩니다.
브라우저를 사용할 수 없는 경우
환경에서 실제로 UI를 실행할 수 없는 경우(브라우저 도구 없음, 자격 증명 누락, 제어할 수 없는 인프라), PR의 테스트 섹션에 그 사실을 명시하세요. 무엇이 막혔고 대신 무엇을 검증했는지 이름을 적어주세요. 침묵은 "검증됨"으로 읽힙니다.
리뷰 수정 사항을 위에 스택된 단계로 제공
이 과정에서 발견된 수정 사항은 기능 위에 새로운 스택된 PR로 작성되어, 빌드와 리뷰 과정이 별도로 검토 가능하도록 유지하세요 (stacked-prs 참조).
이 과정이 잡아내는 것
다음 중 어느 것도 타입 검사기, 린터, 단위 테스트 스위트에서 나오지 않았습니다:
- 페이지와 일치하지 않는 로딩 스켈레톤. 페이지에 없는 툴바를 스켈레톤으로 표시하여 모든 탐색이 두 레이아웃 사이를 이동했습니다. 실제 레이아웃을 행 단위로 미러링하거나, 스켈레톤을 제공하지 마세요.
- 전환 시 두 개의 다이얼로그가 동시에 표시됨. 모든 다이얼로그가 마운트되고
open플래그만 토글되었기 때문입니다. 숨겨짐은 마운트 해제가 아닙니다. - 잘못된 정체성의 깜빡임: 사용자 자신의 행이 한 프레임 동안 자신을 제거하겠다고 제안했습니다. 클라이언트가 첫 번째 렌더링 후에 세션을 읽었기 때문입니다. 서버가 이미 알고 있는 정체성은 페이지와 함께 내려와야 합니다.
- 거짓 빈 상태: 쿼리가 해결되기 전에 "결과를 찾을 수 없음"이 한 프레임 동안 렌더링되었습니다. 0개의 행이 "로딩 중"과 "비어 있음"을 모두 의미했기 때문입니다.
- 비슷하게 보이는 디자인 토큰으로 교체됨. 두 테마 중 하나에서 눈에 띄게 다릅니다.
- 하드코딩된 레이블. 동일한 레이블을 공유 카탈로그에서 읽는 다른 네 개의 호출 사이트 옆에 있습니다.
- 열 때 페이지를 충돌시키는 메뉴. 하위 컴포넌트에 필요하지만 없는 부모가 있었기 때문입니다. 수동 클릭스루가 두 번 놓쳤는데, 아무도 메뉴를 열지 않았기 때문입니다.
- 조용히 건너뛰어진 스펙 항목과 좋은 이유로 삭제되었지만 문서화되지 않은 다른 항목. 디자인에서의 모든 이탈에는 이유를 설명하는 메모가 필요합니다.
- 스스로 모순되는 다이얼로그. 스크린샷을 보고 발견: 알림에 "모든 좌석이 사용 중입니다"라고 표시되지만, 옆에 있는 푸터는 여전히 "좌석 2개 남음"이라고 표시했습니다.