CI에서만 실패하는 E2E 테스트를 어떻게 추적할 것인가

브라우저 자동화 테스트의 가장 큰 문제는 실패 자체보다 실패 당시의 화면, 네트워크, 콘솔, 클릭 위치를 나중에 다시 확인하기 어렵다는 점입니다. 개발자 PC에서는 통과하지만 CI에서는 실패하는 테스트가 특히 시간을 많이 씁니다. Playwright의 Trace Viewer를 운영 기준으로 잡으면 실패한 테스트를 단순 로그가 아니라 재현 가능한 증거 묶음으로 남길 수 있습니다. 핵심은 모든 테스트에서 무조건 trace를 켜는 것이 아니라, 실패 분석에 필요한 순간에만 trace, screenshot, video, HTML report를 남기는 것입니다.

권장 운영 원칙

CI에서는 trace를 on-first-retry로 설정하는 방식을 우선 검토합니다. 첫 실행이 실패하고 재시도할 때 trace를 기록하므로, 정상 테스트의 비용은 줄이고 불안정한 테스트의 증거는 확보할 수 있습니다. 재시도를 쓰지 않는 팀이라면 retain-on-failure가 더 단순합니다. 실패한 테스트의 trace만 보존하고 성공 케이스의 trace는 제거하므로 저장 공간과 업로드 시간을 관리하기 쉽습니다.

  • 로컬 개발: 빠른 피드백을 위해 기본 trace는 최소화하고, 필요한 경우 npx playwright test --trace on으로 특정 상황만 기록합니다.
  • CI 실행: retries: 1trace: 'on-first-retry'를 함께 사용해 불안정한 실패의 두 번째 실행을 남깁니다.
  • 장애 분석: HTML report와 test-results 디렉터리를 artifact로 업로드해 담당자가 CI 화면에서 바로 내려받을 수 있게 합니다.
  • 보안 관리: 인증 토큰, 개인정보, 관리자 화면이 trace에 담길 수 있으므로 artifact 보존 기간과 접근 권한을 제한합니다.

실전 설정 예시

아래 설정은 일반적인 웹 서비스의 E2E 테스트 기준입니다. CI에서는 한 번 재시도하고, 첫 재시도에서 trace를 남기며, 실패 시 screenshot과 video도 함께 보존합니다. 모바일 프로젝트를 하나 추가해 반응형 깨짐도 같은 파이프라인에서 확인하도록 구성했습니다.

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './e2e',
  retries: process.env.CI ? 1 : 0,
  reporter: process.env.CI
    ? [['html', { outputFolder: 'playwright-report', open: 'never' }], ['list']]
    : [['html'], ['list']],
  use: {
    baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
    trace: process.env.CI ? 'on-first-retry' : 'retain-on-failure',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure'
  },
  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'mobile-chrome', use: { ...devices['Pixel 7'] } }
  ],
  webServer: {
    command: 'npm run start',
    url: 'http://localhost:3000',
    reuseExistingServer: !process.env.CI,
    timeout: 120_000
  }
});

/*
GitHub Actions 예시

- name: Run E2E
  run: npx playwright test
  env:
    CI: true
    BASE_URL: http://localhost:3000

- name: Upload Playwright report
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: playwright-report
    path: |
      playwright-report/
      test-results/
    retention-days: 7
*/

Trace Viewer에서 먼저 볼 지점

trace 파일을 열면 전체 테스트를 처음부터 끝까지 다시 보는 대신 실패 직전 액션부터 확인하는 것이 빠릅니다. Actions 탭에서는 어떤 locator가 실행됐는지, 액션이 얼마나 걸렸는지, 클릭 전후 DOM 스냅샷이 어떻게 바뀌었는지 볼 수 있습니다. Screenshots 영역의 필름 스트립은 화면이 어느 시점부터 기대와 달라졌는지 찾는 데 좋습니다. Network 로그는 API 지연, 401/403 응답, CORS 오류, 정적 파일 누락처럼 화면 로그만으로는 놓치기 쉬운 문제를 잡는 데 유용합니다.

  • 클릭 실패라면 locator가 실제로 어떤 요소를 가리켰는지, 클릭 좌표가 가려진 레이어 위였는지 확인합니다.
  • 타임아웃이라면 기다린 대상이 DOM에 없었는지, 있었지만 보이지 않았는지, 애니메이션이나 로딩 상태에 막혔는지 구분합니다.
  • 환경 차이라면 CI의 baseURL, 브라우저 프로젝트, viewport, locale, timezone, feature flag 값을 로컬과 비교합니다.
  • 데이터 문제라면 테스트 시작 전 seed 데이터 생성과 테스트 종료 후 정리 로직이 병렬 실행에서 충돌하지 않는지 확인합니다.

불안정 테스트를 줄이는 작성 습관

trace는 사후 분석 도구이지 불안정한 테스트를 정당화하는 장치가 아닙니다. 테스트가 자주 실패한다면 고정 대기 시간을 늘리기보다 사용자 관점의 안정 조건을 명시해야 합니다. 예를 들어 버튼 클릭 후 네트워크가 끝나기를 막연히 기다리는 대신 결과 목록, 성공 알림, URL 변경, 저장된 값처럼 사용자가 확인할 수 있는 상태를 assertion으로 잡는 편이 좋습니다. 또한 테스트마다 독립적인 데이터를 만들고, 같은 계정이나 같은 주문 번호를 여러 테스트가 공유하지 않게 해야 병렬 실행에서도 결과가 흔들리지 않습니다.

팀 운영에 붙이면 좋은 규칙

trace artifact는 실패를 본 사람과 고치는 사람이 다른 팀에서 특히 효과가 큽니다. QA가 CI 링크와 trace 파일을 이슈에 붙이면 개발자는 화면 녹화, DOM 스냅샷, 네트워크 기록을 한 번에 확인할 수 있습니다. 단, 모든 실패를 같은 우선순위로 보지 말고 원인을 분류해야 합니다. 제품 버그는 기능 담당자가 처리하고, locator 불안정은 테스트 소유자가 고치며, 테스트 데이터 충돌은 fixture나 seed 전략을 바꾸는 식으로 책임 경계를 분명히 해야 재발이 줄어듭니다.

운영 체크리스트

  • CI artifact에는 playwright-report/test-results/를 함께 보존합니다.
  • trace는 기본적으로 실패 분석용으로만 남기고, 전체 테스트 상시 기록은 특별한 조사 기간에만 사용합니다.
  • 보존 기간은 7일에서 14일 사이로 짧게 잡고, 민감한 화면을 테스트할 때는 마스킹 전략을 별도로 둡니다.
  • 반복 실패 테스트는 trace 링크와 함께 이슈로 등록하고, 원인 분류를 locator 문제, 데이터 문제, 환경 문제, 제품 버그로 나눕니다.
  • 수정 후에는 같은 CI 조건에서 재실행해 trace가 새로 남지 않는지 확인합니다.

정리하면 Playwright Trace Viewer 운영의 목표는 테스트 실패를 가끔 깨지는 일로 넘기지 않고, 화면과 코드와 네트워크가 연결된 증거로 남기는 것입니다. trace 기록 시점, artifact 업로드, 보존 기간, 민감정보 관리 기준을 함께 정하면 E2E 테스트는 단순 배포 관문을 넘어 실제 장애 분석 도구로 작동합니다.