Skip to content

Playwright E2E Smoke 테스트 디버깅 가이드 ​

이 문서는 소비 포털의 e2e:smoke 테스트가 실패했을 때 원인을 재현하고, CI artifact를 분석하고, 수정 사항을 검증하는 절차를 설명한다. 현재 smoke suite는 공통 Portal Shell 렌더링, 관리자 화면 이동, 계정 설정의 dark mode 전환, /admin 직접 진입, browser console error와 uncaught page error를 검증한다.

1. CI 실패 결과 확인 ​

GitHub Actions의 Consumer portal CI 실행 화면에서 먼저 실패한 step을 확인한다. Typecheck, Build, Run consumer portal E2E smoke 중 어느 단계에서 실패했는지에 따라 조사 범위가 달라진다.

E2E 단계가 실패하면 다음 artifact를 다운로드한다.

Artifact내용우선 확인 대상
playwright-reportHTML report와 테스트별 요약어떤 테스트와 assertion이 실패했는지 확인
playwright-test-results실패 시에만 업로드되는 trace, screenshot, video, error context실제 화면, 네트워크·콘솔·DOM 상태 확인
consumer-portal-dist해당 commit에서 생성된 production bundlebuild 산출물과 로컬 재현 결과 비교

실패한 commit SHA가 로컬에서 확인한 commit과 같은지도 먼저 확인한다. 다른 commit을 조사하면 이미 해결된 실패를 재현하게 될 수 있다.

2. 로컬 재현 준비 ​

소비 포털은 GitHub Packages의 private @hohyun94/portal-foundation package를 사용한다. 로컬 설치 전에 package read 권한이 있는 token을 설정한다.

bash
export NODE_AUTH_TOKEN="<GitHub Packages read token>"
pnpm install
pnpm exec playwright install chromium

CI와 동일한 검증 순서는 다음과 같다.

bash
pnpm run check
pnpm run build
pnpm run e2e:smoke

실패한 테스트만 빠르게 재현하려면 다음과 같이 실행한다.

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"

3. headed mode와 inspector 사용 ​

CI에서만 발생하는지, 브라우저 화면에서도 재현되는지 구분하려면 headed mode를 사용한다.

bash
pnpm exec playwright test --headed

Playwright Inspector를 사용하면 locator, action, DOM 상태를 단계별로 확인할 수 있다.

bash
PWDEBUG=1 pnpm exec playwright test e2e/portal-foundation.smoke.spec.ts

특정 테스트를 일시 정지하면서 확인하려면 테스트에 임시로 await page.pause()를 추가하고 실행한다. 디버깅이 끝난 뒤 page.pause()와 임시 로그는 반드시 제거한다.

4. Trace 분석 ​

실패 artifact의 trace.zip을 다운로드한 뒤 다음 명령으로 연다.

bash
pnpm exec playwright show-trace path/to/trace.zip

Trace Viewer에서 다음 순서로 확인한다.

  1. Actions: 어떤 locator action 직후 실패했는지 확인한다.
  2. Before/After: click 또는 navigation 전후의 DOM과 screenshot을 비교한다.
  3. Console: React error, Ant Design warning, hydration warning을 확인한다.
  4. Network: JS/CSS 404, private package와 무관한 runtime request 실패, navigation 실패를 확인한다.
  5. Metadata: browser version, viewport, URL, retry 여부를 확인한다.

5. 실패 유형별 진단 ​

5.1 Shell heading이 보이지 않는 경우 ​

대표 오류:

text
expect(locator).toBeVisible() failed
Locator: getByRole('heading', ...)

확인 순서:

  1. 페이지 URL이 /인지 확인한다.
  2. page.content() 또는 trace의 DOM snapshot에서 heading이 존재하는지 확인한다.
  3. heading이 존재하지만 hidden이면 부모 layout의 width, height, display, visibility, opacity를 확인한다.
  4. .pf-shell, .pf-shell__body, .pf-shell-main, .pf-shell-main__inner의 computed style을 확인한다.
  5. Ant Design runtime CSS가 Portal Foundation의 grid layout을 덮어쓰는지 확인한다.

임시 진단 코드:

ts
console.log(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,
    rect: rect.toJSON(),
    parent: element.parentElement?.className,
  };
}));

width: 0 또는 height: 0이면 assertion을 약화시키기보다 shell layout integration CSS를 먼저 수정한다. consumer CSS에서 !important override를 추가하기 전에는 Ant Design CSS의 import 순서와 적용 범위를 확인한다.

5.2 관리자 이동 실패 ​

대표 오류:

text
page.toHaveURL(/\/admin$/) failed

확인 순서:

  1. 메뉴 관리 열기 버튼이 실제로 click 되었는지 trace에서 확인한다.
  2. window.history.pushState 이후 React state가 갱신되는지 확인한다.
  3. 버튼이 다른 element에 가려져 있거나 disabled인지 확인한다.
  4. 직접 /admin으로 진입했을 때도 관리자 화면이 렌더링되는지 별도 테스트한다.
  5. 새로고침 후 client-side route가 Vite 또는 production server에서 fallback되는지 확인한다.

현재 앱은 pushState 기반의 간단한 navigation을 사용하므로, 실제 production router를 도입할 경우 route fallback과 browser back/forward 처리를 추가로 검증해야 한다.

5.3 Theme 전환 실패 ​

대표 오류:

text
expected html to have class "dark"

확인 순서:

  1. 사용자 설정 popup이 열렸는지 확인한다.
  2. 다크 radio control이 실제로 선택 가능한지 확인한다.
  3. document.documentElement.dataset.portalMode 값이 dark인지 확인한다.
  4. document.documentElement.classList.contains("dark") 결과를 확인한다.
  5. PortalThemeProvider가 실제로 PortalShell보다 상위에 있는지 확인한다.
  6. applicationPolicy.allowDarkMode === false 또는 forced theme 정책이 적용된 것은 아닌지 확인한다.

임시 진단 코드:

ts
console.log(await page.evaluate(() => ({
  className: document.documentElement.className,
  portalMode: document.documentElement.dataset.portalMode,
  portalBackground: document.documentElement.dataset.portalBackground,
})));

5.4 직접 /admin 진입 실패 ​

대표 오류:

text
page.goto("/admin") succeeded, but the admin heading was not found

Vite dev server는 history fallback을 제공하지만 실제 hosting 환경은 다를 수 있다. 다음을 확인한다.

  • web server가 /admin을 index.html로 fallback하는지
  • static hosting rewrite 설정이 있는지
  • client-side currentPath()가 pathname을 읽는 시점이 올바른지
  • /admin에서 필요한 localStorage와 menu seed가 초기화되는지

5.5 Browser console 또는 page error 발생 ​

smoke 테스트는 browser console의 error와 pageerror를 수집한다. 실패 메시지에는 다음이 포함될 수 있다.

  • React rendering exception
  • hydration mismatch
  • missing export 또는 undefined component
  • chunk loading failure
  • CSS 또는 asset 404
  • Ant Design runtime exception

오류를 무시하기 위해 consoleErrors assertion을 제거하지 않는다. 오류가 예상 가능한 third-party warning이라면 원인을 먼저 제거하거나, 정말 불가피한 경우에만 정확한 message prefix를 기록하고 이유를 주석으로 남긴다.

6. SSR 및 hydration 관련 조사 ​

소비 포털에 SSR을 추가하거나 SSR 결과를 사용하는 hosting으로 전환할 경우 다음을 별도 확인한다.

ts
const serverMarkup = renderToString(<App />);
container.innerHTML = serverMarkup;
hydrateRoot(container, <App />);

확인 항목:

  • 서버와 client의 초기 theme 값이 같은지
  • window, document, localStorage를 render phase에서 직접 참조하지 않는지
  • Modal portal이 server render에서 열리지 않는지
  • client mount 뒤 focus와 open 상태가 안정적으로 전환되는지
  • hydration 직후 console에 mismatch warning이 없는지

Portal Foundation의 PortalExploreDialog는 client mount guard와 SSR 테스트를 포함하지만, 소비 포털이 추가하는 wrapper·theme storage·auth provider도 함께 검증해야 한다.

7. Private package와 dependency 문제 ​

다음 오류는 E2E 문제가 아니라 설치 단계 문제일 가능성이 높다.

text
401 Unauthorized
No authorization header was set

확인 순서:

  1. NODE_AUTH_TOKEN이 GitHub Packages read 권한을 가진 token인지 확인한다.
  2. workflow job에 packages: read permission이 있는지 확인한다.
  3. .npmrc의 scope registry가 https://npm.pkg.github.com인지 확인한다.
  4. package version 0.6.80이 실제 registry에 게시되어 있는지 확인한다.
  5. lockfile이 오래된 package version을 가리키지 않는지 확인한다.

이 문제를 E2E assertion 수정으로 해결하려고 하지 않는다.

8. CI와 로컬 차이 ​

CI에서만 실패하면 다음 환경 차이를 확인한다.

항목CI 기준
OSUbuntu latest
Node22
pnpm10.4.1
BrowserPlaywright Chromium
ViewportDesktop Chrome 기본 viewport
Web serverpnpm dev --host 127.0.0.1 --port 4173
RetryCI에서 최대 2회

로컬도 동일한 조건으로 실행한다.

bash
CI=1 pnpm exec playwright test --config=playwright.config.ts

화면 크기 의존 문제가 의심되면 Playwright config에 임의의 viewport를 추가하기 전에 소비 포털이 지원해야 하는 실제 viewport를 명확히 정한다.

9. 수정 후 검증 체크리스트 ​

수정 후 다음 명령이 모두 통과해야 한다.

bash
pnpm run check
pnpm run build
pnpm run e2e:smoke

추가로 확인한다.

  • 실패를 재현하던 단일 test가 통과한다.
  • 전체 smoke suite가 통과한다.
  • browser console error와 page error가 없다.
  • trace·screenshot·video artifact가 더 이상 실패 결과로 생성되지 않는다.
  • 임시 page.pause(), console.log, broad timeout 증가가 제거되었다.
  • 변경이 layout integration 문제라면 desktop과 mobile viewport를 모두 확인했다.
  • CI workflow가 사용하는 GITHUB_TOKEN package 권한이 유지된다.

10. 재발 방지 원칙 ​

E2E test를 통과시키기 위해 locator를 지나치게 약하게 만들거나 무조건 timeout을 늘리지 않는다. 사용자가 실제로 보는 semantic role, accessible name, URL, theme attribute를 기준으로 assertion을 유지한다. layout 문제는 screenshot과 computed style로 원인을 확인한 뒤 consumer integration CSS 또는 Portal Foundation component에서 수정한다. 반복적으로 발견되는 문제는 smoke test 또는 unit/contract test로 승격해 동일한 regression이 다시 발생하지 않도록 한다.