Files
HMDesign/docs/sw/sw-test-regression-baseline-2026-10-20.md
T

170 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SW 테스트 정합성 개선 — Storybook 회귀 기준선 유지 (2026-10-20)
> 범위: 테스트 코드와 이 문서만 다룹니다. `@hm-design/sw` 제품 코드·공개 API·Storybook Story·디자인은 바꾸지 않았습니다.
> 브랜치 `fix/test-home-menu-integration`, 기준 main `553e4df`(Merge `feature/sw-package`). 과거 QA 증거 폴더는 수정하지 않았습니다.
> 실행 환경: Node.js 22.23.2 / npm 10.9.8, Chrome 155.0.8059.85(headless), Playwright 1.62.1(Codex 런타임, `playwright-runtime.mjs` 탐색 순서 5번).
## 1. 결과 요약
같은 `storybook-static`(Node 22.23.2로 `npm run build-storybook`, 패키지 build 포함)에서 수정 전 테스트(`553e4df` 버전)와 현재 테스트를 각각 실행했습니다.
| 테스트 | 수정 전 (`553e4df`) | 수정 후 (`20ed2f2`) | 관련 Commit |
|---|---|---|---|
| `home-menu-integration.browser.mjs` | 22/23 (FAIL 1) | **23/23** | `7fd7342` |
| `overview.browser.mjs` | 51/54 (FAIL 3) | **54/54** | `522ecbd`, `20ed2f2` |
| `overview.browser.mjs … overlays` | 17/20 (같은 FAIL 3) | **20/20** | `522ecbd`, `20ed2f2` |
| `storybook-unused-removal.browser.mjs` | 88/93 (FAIL 5) | **93/93** | `20ed2f2` |
모든 FAIL은 과거 시점 값에 고정된 단언이었고, 기능(브라우저 동작) 실패는 없었습니다. 수정은 단언을 지우거나 건너뛰지 않고, 기준선은 그대로 둔 채 **승인된 이후 변경만** 명시적으로 허용하는 방식입니다.
## 2. Home Menu 기존 실패 1건 (`7fd7342`)
- 실패 항목: `without homeMenu: logo click calls onHomeClick, renders no menu, no aria-expanded`
- 실제 오류: `sw-header--overview`의 로고를 누르자 `[SWHeader Overview] homeMenuOpen(true, home)`이 기록되고 홈 메뉴가 열림.
- 원인: `170a5c2`(홈 메뉴 Header 통합, 사용자 요청)부터 Overview가 `homeMenu`를 전달합니다(`docs/sw/sw-header-usage.md` "Overview의 로고도 같은 홈 메뉴"). 테스트가 "homeMenu 없는 Header"의 대상으로 Overview를 계속 열고 있었습니다.
- 해결: 대상만 `sw-header--logo-slot`의 첫 Header(`figmaArgs` + `callbacks`, `homeMenu` 없음)로 바꾸고, Callback 판정 문자열을 그 Header의 로그(`[SWHeader] home`)로 맞췄습니다. "메뉴 없음 · `aria-expanded` 없음 · `onHomeClick`만 호출" 단언은 그대로입니다.
## 3. Overview 기존 실패 3건 (`522ecbd`, `20ed2f2`)
기준선은 `50bf5bd`와 그 시점의 `before-index.json`으로 유지합니다.
| 실패 항목(수정 전) | 원인 | 해결 |
|---|---|---|
| `24 retained Story IDs, names and tags; only approved Dropdown retirements` | 이후 승인된 삭제(속성창 5개, 미사용 9개), Popup 이동, `verification` 태그, 홈 메뉴·통합 개선 Story 추가로 SW/Header가 20개가 됨 | 24개에서 승인된 삭제·이동을 빼고 승인된 태그를 적용한 뒤 승인된 추가 ID를 더한 **20개**와 ID·이름·태그가 정확히 같아야 PASS. 이동한 Story는 title이 `SW/Popup`인지 확인 |
| `retained non-Overview declarations byte-identical` | `ResponsiveMore`(170a5c2), `WindowMoveMotion`·`KGuide`(2b0e1a2) 변경, 미사용 Story 선언 삭제, `PropertyPanelCompare`의 `sw-property-panel.stories.tsx` 이동 | 변경 선언은 **승인 Commit의 내용과 byte 단위로 같을 때만** 허용, 삭제는 승인된 삭제 ID일 때만, 이동 선언은 새 파일에서 승인 Commit 내용과 비교. 그 밖의 선언은 계속 `50bf5bd`와 동일해야 함 |
| `package production source untouched except the integrated-improvement files` | `50bf5bd` 이후 승인되어 main에 병합된 `packages/sw/src` 변경 | `approvedMainCommit`(553e4df)과 비교해 통합 개선 파일 외 차이가 없어야 PASS. `50bf5bd` 이후 차이 개수는 `sinceBaseline`으로 기록만 함 |
`20ed2f2`에서는 위 목록(태그·추가 ID·승인 선언·이동 선언)을 `storybook-inventory.mjs`로 옮겨 Overview와 미사용 검사가 같은 목록을 쓰게 했습니다. Overlays 모드는 같은 앞부분 검사를 공유하므로 같은 3건이 함께 해결됩니다.
## 4. Storybook 미사용 검사 기존 실패 5건 (`20ed2f2`)
기준선은 `c8e5fbe`의 `full-index-before.json`으로 유지합니다.
| 실패 항목(수정 전) | 해결 |
|---|---|
| `19 -> 10 retained SW/Header Stories, 338 -> 329 total plus only the integrated-improvement Stories` | 338 → 329와 19 → 10은 그대로 단언. 이후 추가는 `approvedAddedStoryIds`(통합 개선·홈 메뉴·Footer·Viewer·Theme)와 **정확히 같은 집합**일 때만 PASS. 승인되지 않은 추가(`unapproved`)·누락(`missing`)을 결과에 기록 |
| `retained SW IDs, names, titles, tags and order unchanged` | 유지 10개의 ID·이름·title·tags·순서를 비교하되, 승인된 `verification` 태그와 Popup 이동만 반영 |
| `every non-removed index entry identical (docs and other packages included)` | SW 밖 항목은 값·순서 모두 동일, 유지 SW 항목은 승인 변경만 반영해 동일, SW 블록은 Center Graphic 바로 뒤에 연속(2b0e1a2 storySort) |
| `retained exports (Stories and ComposedDemo) byte-identical` | 변경·추가 Export는 승인 Commit 내용과 같을 때만, 이동 Export는 새 파일에서 비교, 나머지는 `c8e5fbe`와 동일 |
| `other packages, Overview, Dropdown CSF, assets and Storybook config untouched` | 같은 경로가 `approvedMainCommit`과 달라서는 안 됨(통합 개선 파일 제외). `c8e5fbe` 이후 차이는 `sinceBaseline`으로 기록 |
## 5. 관련 Commit
| Commit | 내용 | 파일 |
|---|---|---|
| `7fd7342` | test(sw): align home menu integration with current stories | `home-menu-integration.browser.mjs` |
| `522ecbd` | test(sw): align overview regression checks with approved changes | `overview.browser.mjs` |
| `20ed2f2` | test(sw): align storybook inventory checks with approved changes | `storybook-inventory.mjs`, `overview.browser.mjs`, `storybook-unused-removal.browser.mjs` |
### 5.1 승인 목록에 반영된 Story 변경 이력
모두 사용자 요청으로 진행되어 main `553e4df`에 포함된 Commit입니다(`git merge-base --is-ancestor`로 확인).
| Commit | 변경 | `storybook-inventory.mjs` 항목 |
|---|---|---|
| `50bf5bd` | 정리 1단계: Story 5개 삭제 | `retiredStage1Ids` |
| `9482d45`, `c705a1f` | Dropdown 4개 통합, `composed-controls` → Dropdown(SW/Header 바로 아래) | `retiredDropdownIds`, `retainedInventory` |
| `c8e5fbe` | 속성창 중복 5개 삭제, 4개 비교로 통합 | `retiredPropertyPanelIds` |
| `5faa1f1` | 미사용 SW Header 시연 9개 삭제 | `retiredUnusedDemoIds` |
| `55179b4`, `e8409ef` | 통합 개선 0.2.0 Story 추가, Options를 SW/Header로 통합 | `integratedStoryIds` |
| `170a5c2` 등 홈 메뉴 병합 | SW/Home Menu → SW/Header(`home-menu`, `home-menu-*`), Overview·ResponsiveMore 변경 | `homeMenuSidebarIds`, `movedHomeMenuIds`, `approvedHeaderDeclarations` |
| `6cf8854`, `7f42923`, `41e963a` | SW Footer, Viewer, Theme Story 추가 | `footerStoryIds`, `viewerStoryIds`, `themeStoryIds` |
| `7f42923` | SW/Tool Story 메뉴 삭제(`SWToolButton`·`SWToolGroup`은 공개 유지) | `retiredToolIds` |
| `126a35d` | Footer `기본 Footer`·`States` Story 삭제(전체 Footer 섹션으로 통합) | `retiredFooterIds` |
| `2b0e1a2` | 사이드바 단순화: `verification` 태그 2개, Property Panel 비교 SW/Popup 이동, 홈 메뉴 Figma 비교·중복 Variant 6개 삭제 | `verificationTaggedIds`, `movedToPopupIds`, `movedHeaderDeclarations`, `retiredHomeMenuCompareIds` |
## 6. 변조 검증
수정한 단언이 "무조건 PASS"가 아닌지 확인하려고 현재 테스트(`20ed2f2`)에 일부러 승인되지 않은 변경을 넣고 실행한 뒤 원상 복구했습니다. 복구는 백업 파일로 했고 매번 `git diff`가 비어 있음(소스) 또는 `index.json` SHA-256 일치(빌드 산출물)를 확인했습니다.
### 6.1 Story 목록 변조 (`storybook-static/index.json`, 재빌드 없음)
| 시나리오 | Overview | Overlays | 미사용 검사 | Home Menu |
|---|---|---|---|---|
| 승인되지 않은 SW/Header Story 추가 | 53/54 — 목록 검사 FAIL | 19/20 — 목록 FAIL | 31/34 — 개수·전체 항목 FAIL, 가짜 Story 렌더 중단 | 23/23 (목록 비검사) |
| 유지 Story(`logo-slot`) 삭제 | 53/54 — 목록 FAIL | 19/20 — 목록 FAIL | 89/92 — 개수·유지 항목·전체 항목 FAIL | 중단(Logo Slot Header 대기 시간 초과) |
| 유지 Story에 `verification` 태그 추가 | 53/54 | 19/20 | 91/93 — 유지 항목·전체 항목 FAIL | 23/23 |
| 유지 Story(`document-dropdown`) title 이동 | 53/54 | 19/20 | 90/92 — 유지 항목·전체 항목 FAIL | 23/23 |
| 유지 Story(`responsive-more`) 이름 변경 | 53/54 | 19/20 | 91/93 — 유지 항목·전체 항목 FAIL | 23/23 |
### 6.2 소스 변조 (작업 트리, 재빌드 없음, 한 번에 4건)
| 변조 | 검출 |
|---|---|
| 유지 선언 `LogoSlot`의 섹션 제목 변경 | Overview·Overlays 선언 검사 FAIL(`LogoSlot`), 미사용 검사 Export 검사 FAIL(`changed: LogoSlot`) |
| 승인 선언 `ResponsiveMore`(170a5c2)를 승인 내용과 다르게 변경 | 같은 두 검사에서 `ResponsiveMore` FAIL — 승인 목록은 Commit 내용에 고정되며 와일드카드가 아님 |
| 통합 개선 목록 밖 패키지 파일(`sw-footer/SWFooterParts.tsx`) 변경 | Overview·Overlays 소스 검사 FAIL(`unapproved`), 미사용 검사 경로 검사 FAIL |
| `.storybook/main.ts` 변경 | 미사용 검사 경로 검사 FAIL(`unexpected`). Overview는 이 경로를 원래 검사하지 않음 |
결과: Overview 52/54, Overlays 18/20, 미사용 검사 91/93, Home Menu 23/23. 다른 검사는 그대로 PASS였습니다.
### 6.3 동작 변조 (Story 수정 후 재빌드)
`sw-header--logo-slot` 첫 Header에 `homeMenu={{ sections: OVERVIEW_HOME_MENU }}`를 임시로 넣고 Storybook을 다시 build했습니다. Home Menu는 **22/23**으로 `without homeMenu: logo click calls onHomeClick, renders no menu, no aria-expanded`만 FAIL(로고 클릭 시 `onHomeClick` 기록 없음)이었습니다. 원본으로 되돌린 뒤 다시 build했고, 그 빌드에서 §7을 실행했습니다.
## 7. 회귀 테스트 결과 (Node 22.23.2, 수정 후)
| 테스트 | 결과 |
|---|---|
| `npm run build-storybook`(prebuild: theme defaults 확인, 5개 패키지 build) | PASS |
| `home-menu-integration` | 23/23 |
| `overview` | 54/54 |
| `overview … overlays` | 20/20 |
| `storybook-unused-removal` | 93/93 |
| `npm run check:ai-docs` | PASS (2 shared files × 4 packages, catalog·링크 일치) |
| `node packages/sw/tests/ai-docs.check.mjs` | 46/46 |
같은 빌드에서 이번 범위 밖의 기존 테스트 4종은 아직 과거 기준으로 실패합니다(§10).
## 8. Story 추가·삭제·이동 시 승인 목록 관리
승인 목록은 `packages/sw/tests/storybook-inventory.mjs` 하나에서 관리합니다. Story 변경을 사용자가 승인한 같은 변경(또는 바로 뒤 테스트 정렬 변경)에서 아래 목록을 갱신하고, 각 항목 옆 주석에 승인 Commit과 사유를 적습니다. 값은 실제 Story ID·선언 이름·Commit SHA(전체 40자)만 씁니다.
| 변경 | 갱신할 항목 |
|---|---|
| SW Story 추가 | 해당 영역 목록(`footerStoryIds`, `viewerStoryIds`, `themeStoryIds`, `homeMenuSidebarIds`, `integratedStoryIds` 등)에 ID 추가 → `approvedAddedStoryIds`에 자동 포함. 새 영역이면 새 목록을 만들고 `approvedAddedStoryIds`에 연결 |
| SW Story 삭제 | `retired…Ids` 목록에 ID 추가(예: `retiredFooterIds`, `retiredHomeMenuCompareIds`), 추가 목록에서 제외되는지 확인. `sw-header.stories.tsx`의 Story를 지우면 Overview 선언 검사는 `retiredPropertyPanelIds`·`retiredUnusedDemoIds`의 삭제만, 미사용 검사의 Export 검사는 그 스크립트의 `removedExports` 9개만 허용하므로 새 삭제는 두 검사도 함께 갱신해야 함 |
| Story 이동(title 변경, ID 유지) | `movedToPopupIds` 같은 이동 목록과 `withApprovedEntryChanges`의 변환(title·importPath), 선언이 다른 파일로 가면 `movedHeaderDeclarations`(새 파일, 승인 Commit) |
| 태그 변경(`verification` 등) | `verificationTaggedIds`(또는 해당 변환을 `withApprovedEntryChanges`에 추가) |
| `sw-header.stories.tsx` 선언 변경·추가 | `approvedHeaderDeclarations`에 `선언 이름: 승인 Commit`. 검사는 현재 선언이 그 Commit의 내용과 byte 단위로 같은지 봄 |
| Story ID 변경 | ID 변경은 삭제 + 추가로 다룸(이전 ID는 `retired…`, 새 ID는 추가 목록). 승인 없이 ID를 바꾸지 않음 |
원칙:
- 승인되지 않은 Story·제품 소스 변경을 목록에 넣어 테스트를 통과시키지 않습니다. 목록은 사용자 승인 기록입니다.
- 기준선 파일(`before-index.json`, `full-index-before.json`)과 과거 QA 폴더는 고치지 않습니다. 새 실행은 항상 새 증거 폴더에 저장합니다(기본 경로로 실행하면 일부 스크립트가 과거 증거를 덮어씀).
- 목록을 바꾼 뒤에는 Storybook을 다시 build하고 Overview(두 모드)·미사용 검사를 실행해 PASS를 확인합니다. 가능하면 §6.1처럼 가짜 Story 하나를 넣어 FAIL이 나는지도 확인합니다.
## 9. 향후 main 병합 시 기준 갱신 절차
`approvedMainCommit`은 "Story와 제품 소스 변경이 모두 승인된 main 병합"을 가리키며, Overview·미사용 검사는 보호 경로(Overview: `packages/sw/src`, 미사용 검사: SW ai/package 파일, 다른 패키지, Overview, Dropdown CSF, assets, `.storybook`)가 이 Commit과 같아야 PASS입니다(통합 개선 파일 제외). 역할과 갱신 조건은 같은 파일의 주석에도 적었습니다.
> **자동 변경 금지:** main에 새 HEAD가 생겼다는 이유만으로 `approvedMainCommit`을 바꾸지 않습니다. 이 값을 자동으로 갱신하는 스크립트·Workflow는 없으며, 아래 절차를 거친 검토된 테스트 전용 Commit에서만 바뀝니다. 현재 값은 `553e4df`(`553e4df4a865aaf6514b1c2b86cb2e3e9a658e5f`)이며 이 문서 작성 시점에 변경하지 않았습니다.
1. 병합할 브랜치의 Story·제품 소스 변경이 Commit 단위로 모두 사용자 승인을 받았는지 확인합니다. 승인되지 않은 변경이 있으면 기준을 옮기지 않습니다.
2. 병합 전 브랜치에서 §8의 승인 목록을 갱신하고, 테스트가 PASS인지 확인합니다.
3. main에 병합합니다. Squash·Rebase 병합이면 SHA가 바뀌므로 `approvedHeaderDeclarations`·`movedHeaderDeclarations`의 Commit을 main에 실제로 들어간 SHA로 다시 맞춥니다.
4. 병합 Commit의 전체 SHA로 `approvedMainCommit`을 바꾸는 **테스트 전용 Commit**을 만듭니다. 이 Commit은 보호 경로를 건드리지 않습니다.
5. Node 22.23.2에서 `npm run build-storybook` 후 Home Menu, Overview(두 모드), 미사용 검사를 새 증거 폴더로 실행합니다. 하나라도 FAIL이면 기준을 옮기지 말고 원인(미승인 변경 또는 목록 누락)을 확인합니다.
6. 실행 결과와 갱신 사유를 `docs/sw/`의 보고서에 남깁니다. 기존 보고서와 증거는 고치지 않습니다.
## 10. 남은 문제
- 이번 범위 밖 기존 테스트 4종은 같은 빌드에서 과거 기준으로 실패합니다(수정 전 측정, 이 Commit에서 고치지 않음): `dropdown-consolidation` 223/228(목록·선언·경로 5건), `storybook-cleanup-stage1` 29/34(목록·선언·경로 4건 + 삭제된 `sw-header--dynamic-controls`에서 중단), `detail-buttons verify`(삭제된 `sw-header--composition`에서 중단), `property-panel-comparison verify` 50/52(목록 2건) 후 삭제된 `sw-header--property-panel`에서 예외 종료. 별도 작업으로 다룹니다.
- 통합 개선 파일 예외: Overview·미사용 검사는 `integratedChangedFiles`가 `approvedMainCommit`과 달라도 허용합니다(그 파일은 통합 개선 suite가 검증). 그 suite를 함께 실행하지 않으면 이 파일들의 미승인 변경은 두 검사로는 드러나지 않습니다.
- 과거 QA 폴더를 기본 증거 경로로 쓰는 스크립트가 있습니다. 반드시 새 증거 폴더를 지정해야 합니다.
## 11. 재현
```bash
npm run build-storybook
node packages/sw/tests/home-menu-integration.browser.mjs <새 폴더>/home
node packages/sw/tests/overview.browser.mjs <before-index.json을 복사한 새 폴더>
node packages/sw/tests/overview.browser.mjs <before-index.json을 복사한 새 폴더> overlays
node packages/sw/tests/storybook-unused-removal.browser.mjs <새 폴더>/unused
npm run check:ai-docs
node packages/sw/tests/ai-docs.check.mjs
```
Overview는 증거 폴더의 `before-index.json`을 읽으므로 `docs/sw/storybook-overview-qa/before-index.json`을 새 폴더에 복사한 뒤 실행합니다. 이번 실행의 결과 JSON·로그는 저장소 밖 임시 폴더에 두었고(`*.log`는 Git 제외 대상), 주요 수치는 위 표에 옮겼습니다.