E2E Smoke Troubleshooting Checklist
이 체크리스트는 소비 포털의 GitHub Actions E2E smoke test가 실패했을 때 담당자가 처음부터 끝까지 따라가는 실행 절차다. 각 단계의 결과를 기록하면서 진행하고, 원인이 확인되기 전에는 timeout이나 assertion을 임의로 약화하지 않는다.
0. 실패 정보 기록
- [ ] GitHub Actions 실행 URL을 기록했다.
- [ ] 실패한 commit SHA가 조사 대상 commit과 같은지 확인했다.
- [ ] 실패한 job과 step을 확인했다.
- [ ] Install dependencies
- [ ] Install Playwright browser
- [ ] Typecheck
- [ ] Build production bundle
- [ ] Run consumer portal E2E smoke
- [ ] 실패한 테스트 이름과 assertion 문구를 기록했다.
- [ ] 재시도 중 우연히 통과한 것이 아닌지 확인했다.
설치 단계에서 실패하면 E2E 테스트 문제가 아니다. private package 인증, Node/pnpm 버전, lockfile을 먼저 확인한다.
1. CI artifact 확보
E2E step이 실패한 경우 GitHub Actions 실행 화면에서 다음 artifact를 다운로드한다.
- [ ]
playwright-report를 다운로드했다. - [ ]
playwright-test-results를 다운로드했다. - [ ] 실패 screenshot을 확인했다.
- [ ] video가 있으면 마지막 동작 전후 화면을 확인했다.
- [ ]
trace.zip을 확인했다. - [ ] build 결과가 필요하면
consumer-portal-dist를 다운로드했다.
Trace를 열 때:
bash
pnpm exec playwright show-trace path/to/trace.zipTrace Viewer에서:
- [ ] 실패한 action 직전의 DOM을 확인했다.
- [ ] 실패 순간의 screenshot을 확인했다.
- [ ] Console 탭에 React, hydration, Ant Design 오류가 없는지 확인했다.
- [ ] Network 탭에 JS/CSS 404 또는 chunk loading failure가 없는지 확인했다.
- [ ] 현재 URL과 viewport를 확인했다.
2. 로컬 재현 환경 준비
bash
export NODE_AUTH_TOKEN="<GitHub Packages read token>"
pnpm install
pnpm exec playwright install chromiumCI와 같은 순서로 실행한다.
bash
CI=1 pnpm run check
CI=1 pnpm run build
CI=1 pnpm run e2e:smoke- [ ]
NODE_AUTH_TOKEN이 설정되어 있다. - [ ] token에 GitHub Packages read 권한이 있다.
- [ ] Node.js 버전이 CI와 같은 22인가?
- [ ] pnpm 버전이 workflow와 같은 10.4.1인가?
- [ ] Playwright Chromium이 설치되어 있는가?
- [ ] 변경하지 않은 clean working tree에서 재현했는가?
특정 테스트만 재현할 때:
bash
pnpm exec playwright test e2e/portal-foundation.smoke.spec.ts -g "renders the shared shell"
pnpm exec playwright test e2e/portal-foundation.smoke.spec.ts -g "theme controls"
pnpm exec playwright test e2e/portal-foundation.smoke.spec.ts -g "direct navigation"화면을 직접 보면서 조사할 때:
bash
pnpm exec playwright test --headed
PWDEBUG=1 pnpm exec playwright test e2e/portal-foundation.smoke.spec.ts3. 실패 유형별 빠른 분류
| 증상 | 먼저 확인할 것 | 다음 조치 |
|---|---|---|
401 Unauthorized | NODE_AUTH_TOKEN, packages: read | package 인증 수정 |
| TypeScript export 오류 | @hohyun94/portal-foundation version과 public export | package API 호환성 수정 |
| Build 실패 | Vite output과 missing asset | build 로그와 import 수정 |
| heading이 hidden | .pf-shell, .pf-shell-main geometry | screenshot과 computed style 확인 |
/admin URL 실패 | click, pushState, route fallback | navigation과 hosting 설정 확인 |
| dark mode 실패 | html.dark, data-portal-mode | PortalThemeProvider와 policy 확인 |
| console/page error | trace Console 탭 | 최초 runtime error부터 수정 |
| 간헐적 timeout | race, animation, server readiness | 상태 기반 wait로 변경 |
4. 화면이 렌더링되지 않을 때
- [ ]
page.goto("/")이후 최종 URL을 확인했다. - [ ] 대상 heading이 DOM에 존재하는지 확인했다.
- [ ] 대상 element의
display,visibility,opacity를 확인했다. - [ ] 대상 element의 width와 height가 0이 아닌지 확인했다.
- [ ] 부모
.pf-shell,.pf-shell__body,.pf-shell-main,.pf-shell-main__inner의 geometry를 확인했다. - [ ] Ant Design runtime CSS가 Portal Foundation layout을 덮어쓰지 않는지 확인했다.
- [ ] console error와 page error를 함께 수집했다.
임시 진단용 snippet:
ts
const details = await page.getByRole("heading", { name: /공통 기반이 준비되었습니다/ }).evaluate(element => {
const style = getComputedStyle(element);
const rect = element.getBoundingClientRect();
return {
display: style.display,
visibility: style.visibility,
opacity: style.opacity,
width: rect.width,
height: rect.height,
parent: element.parentElement?.className,
};
});
console.log(details);- [ ] 진단 후 임시
console.log를 제거했다.
5. 클릭과 navigation이 실패할 때
- [ ] locator가 semantic role과 accessible name을 사용하는지 확인했다.
- [ ] locator가 실제 DOM에서 unique한지 확인했다.
- [ ] 버튼이 visible하고 enabled인지 확인했다.
- [ ] click 전후 URL을 기록했다.
- [ ]
window.history.pushState이후 React state가 갱신되는지 확인했다. - [ ]
/admin직접 진입도 별도로 확인했다. - [ ] production hosting이
/admin을index.html로 fallback하는지 확인했다. - [ ] browser back/forward가 필요한 앱이라면 해당 동작도 확인했다.
권장 assertion:
ts
await expect(page.getByRole("button", { name: "메뉴 관리 열기" })).toBeVisible();
await page.getByRole("button", { name: "메뉴 관리 열기" }).click();
await expect(page).toHaveURL(/\/admin$/);
await expect(page.getByRole("heading", { name: "메뉴 관리" })).toBeVisible();6. Theme 전환이 실패할 때
- [ ] 사용자 설정 popup을 열었다.
- [ ]
다크control이 visible하고 enabled인지 확인했다. - [ ]
html.darkclass를 확인했다. - [ ]
html[data-portal-mode="dark"]를 확인했다. - [ ]
PortalThemeProvider가PortalShell보다 상위에 있는지 확인했다. - [ ]
applicationPolicy.allowDarkMode가 false가 아닌지 확인했다. - [ ] forced theme 정책이 dark 선택을 막고 있지 않은지 확인했다.
- [ ] localStorage 또는 storage adapter가 이전 theme을 덮어쓰지 않는지 확인했다.
bash
pnpm exec playwright test e2e/portal-foundation.smoke.spec.ts -g "theme controls"7. Console, hydration, Modal 오류가 있을 때
- [ ] 첫 번째 console error부터 조사했다.
- [ ] 마지막에 표시된 연쇄 오류만 보고 원인을 판단하지 않았다.
- [ ] React hydration mismatch가 있는지 확인했다.
- [ ] SSR render에서
window,document,localStorage를 직접 참조하지 않는지 확인했다. - [ ] Modal portal이 SSR에서 열리지 않는지 확인했다.
- [ ] client mount 후 Modal open 상태가 안정적인지 확인했다.
- [ ] focus가 Modal input으로 이동하는지 확인했다.
- [ ] cancel 또는 Escape 후 trigger로 focus가 돌아오는지 확인했다.
8. 실패를 수정한 뒤
- [ ] 실패한 단일 테스트가 통과한다.
- [ ] 전체
pnpm run e2e:smoke가 통과한다. - [ ]
pnpm run check가 통과한다. - [ ]
pnpm run build가 통과한다. - [ ] browser console error가 없다.
- [ ] page error가 없다.
- [ ] desktop viewport에서 통과한다.
- [ ] 필요 시 mobile viewport에서도 통과한다.
- [ ] trace, screenshot, video가 실패 결과로 더 이상 생성되지 않는다.
- [ ] 임시
page.pause(),console.log, broad timeout을 제거했다. - [ ] locator를 지나치게 넓히거나 assertion을
toBeAttached()로 약화하지 않았다. - [ ] 변경 이유와 검증 결과를 PR에 기록했다.
9. 최종 보고 템플릿
문제 해결 후 PR 또는 Slack 보고에 다음 내용을 남긴다.
text
[ E2E smoke 장애 처리 결과 ]
- 실패 테스트:
- 실패 commit:
- 재현 명령:
- 원인:
- 수정 파일:
- 수정 내용:
- 로컬 check:
- 로컬 build:
- 전체 E2E:
- CI 실행 URL:
- 추가 확인 필요: