C.W.K.
Stream
Lesson 04 of 04 · published

CI, Sharding, 그리고 Blob-Merge 패턴

~18 min · playwright-advanced, ci, sharding

Level 0테스트 호기심
0 XP0/32 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"30분 E2E suite 가 3 × 10분 병렬 shard 로 쪼개져. 같은 coverage, wall-clock 시간 1/3."

왜 Sharding

CI 피드백 시간은 feature. 개발자가 merge 전 초록 기다리고; 긴 CI = 느린 팀. E2E 테스트가 제품 성숙하면서 unit 테스트보다 빠르게 자라, 잘 모양 잡힌 suite 도 결국 '너무 느림' 벽 때림. Sharding 이 표준 답: 테스트 세트를 N 조각으로 쪼개고, 각 조각을 별개 CI 머신에서 병렬 돌리고, 결과 병합.

Playwright 에 sharding 내장. --shard=1/3"발견된 테스트의 첫 1/3 돌려." --shard=2/3 가 두 번째. 각자 다른 shard arg 가진 CI job 셋 스폰하고, 병렬화 완료.

Blob Reporter — 누락된 조각

Sharded run 이 N 별개 리포트 생성. Blob reporter (--reporter=blob) 가 shard 당 compact 바이너리 리포트 작성. 최종 'merge' job 이 모든 blob 다운로드해서 npx playwright merge-reports 통해 하나의 HTML 리포트로 병합. 팀이 N 별개 대신 통합된 리포트 하나 봐.

이게 표준 CI 파이프라인 모양:

  1. Test job (N 의 matrix) — 각자 npx playwright test --shard=$INDEX/$TOTAL --reporter=blob 돌리고, 자기 blob 업로드.
  2. Merge job — 모든 test job 에 의존, 모든 blob 다운로드, npx playwright merge-reports --reporter=html ./all-blob-reports 실행.
  3. Upload job — 병합된 HTML 리포트를 artifact 로 업로드.

GitHub Actions setup

GitHub Actions matrix 전략이 이걸 깨끗하게 만들어: matrix: { shard: [1, 2, 3] } 선언하면 병렬 job 셋 얻고, 각자 자기 shard 번호를 ${{ matrix.shard }} 로 받음. Merge job 이 모든 matrix leg 기다리려 needs: [test] 사용.

Suite 가 필요할 만큼 느려질 때까지 shard 하지 마. Blob-merge 춤이 orchestration 복잡성 추가. 10분 미만 suite 엔 sharding 이 승리 없는 오버헤드. 30분 이상 suite 엔 'CI 기다렸어' 와 'CI 도는 거 잊었어' 사이 차이.

Retry vs 재현성

CI 가 retry 가 값어치하는 곳이기도 해. (process.env.CI 통해 CI 전용) retries: 2 설정이 진짜 flake 가리지 않고 진짜 네트워크 blip 잡아 — Playwright 가 retry 된 테스트를 리포트에서 'flaky' 로 마크해서 CI 가 초록일 때도 비율 봐. Flaky 비율 기어오르면 반응할 숫자 있어.

항상 업로드할 Artifact

다른 거 뭘 업로드하든 두 가지 필수:

  • HTML 리포트 (shard 병합 후) — 실패 brows 용.
  • Trace .zip 파일 (test-results/ 에서) — 특정 실패 time-travel 용.

Retention 을 ~30일로 설정해서 flake 재출현 시 run 사이 비교 가능.

로컬 vs CI 설정

가장 깔끔한 CI config 는 process.env.CI 기반으로 knob 전환:

  • Worker: CI 에 1 (경쟁 적음), 로컬에 '50%' (머신 사용).
  • Retry: CI 에 2 (네트워크 jitter 잡음), 로컬에 0 (flake 즉시 봄).
  • Reporter: CI 에 'blob' (sharding 용), 로컬에 'html' (brows 용).
  • Trace: 'on-first-retry' (둘 다 같음 — CI 실패 포렌식 캡처).

Code

GitHub Actions — sharded + merged·yaml
# .github/workflows/playwright.yml — sharded + merged
name: Playwright Tests
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    timeout-minutes: 30
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false       # let all shards finish even if one fails
      matrix:
        shard: [1, 2, 3]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: lts/*
      - name: Install dependencies
        run: npm ci
      - name: Install Playwright browsers
        run: npx playwright install --with-deps

      - name: Run shard ${{ matrix.shard }}/3
        run: npx playwright test --shard=${{ matrix.shard }}/3 --reporter=blob

      - name: Upload blob report
        uses: actions/upload-artifact@v4
        if: ${{ !cancelled() }}
        with:
          name: blob-report-${{ matrix.shard }}
          path: blob-report
          retention-days: 7

  merge:
    needs: [test]
    if: ${{ !cancelled() }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: lts/*
      - run: npm ci

      - name: Download all blob reports
        uses: actions/download-artifact@v4
        with:
          path: all-blob-reports
          pattern: blob-report-*
          merge-multiple: true

      - name: Merge into one HTML report
        run: npx playwright merge-reports --reporter=html ./all-blob-reports

      - name: Upload merged HTML report
        uses: actions/upload-artifact@v4
        with:
          name: playwright-report
          path: playwright-report
          retention-days: 30
로컬 vs CI — `process.env.CI` 로 knob 전환·typescript
// playwright.config.ts — environment-aware
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './e2e',
  fullyParallel: true,
  forbidOnly: !!process.env.CI,         // fail CI if .only slips through
  workers: process.env.CI ? 1 : '50%',  // 1 per shard in CI
  retries: process.env.CI ? 2 : 0,      // catch network jitter, not flakes

  reporter: process.env.CI
    ? [['blob']]                        // blob for sharding + merging
    : [['html', { open: 'never' }]],    // browseable locally

  use: {
    baseURL: process.env.BASE_URL ?? 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },

  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox',  use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit',   use: { ...devices['Desktop Safari'] } },
  ],
});
CLI 에서 sharding — 로컬에서와 CI 에서·bash
# Local — single process, watchable
npx playwright test

# Local — simulate sharding for debugging
npx playwright test --shard=1/3   # run only the first shard locally
npx playwright test --shard=2/3
npx playwright test --shard=3/3

# Local — merge the blobs you produced into one HTML report
npx playwright merge-reports --reporter=html ./blob-report-1 ./blob-report-2 ./blob-report-3

# CI — uses the shard arg from the matrix
npx playwright test --shard=${SHARD}/${TOTAL_SHARDS} --reporter=blob
Sharded + merged run 의 모양·text
# Workflow result you should see in the GitHub Actions UI

┌──────────────┐
│ test (1/3)   │ Running shard 1 of 3 ............ 9m 42s ✅
├──────────────┤
│ test (2/3)   │ Running shard 2 of 3 ............ 9m 18s ✅
├──────────────┤
│ test (3/3)   │ Running shard 3 of 3 ............10m 04s ✅
└──────────────┘
          │
          ▼
┌──────────────┐
│ merge        │ Downloading 3 blobs, merging .... 0m 47s ✅
└──────────────┘

Total wall time: ~11 minutes  (vs ~30 minutes serial)
Artifacts: playwright-report (browseable HTML), blob-report-{1,2,3}

Click the failing test in the merged report → click 'Trace' → time-travel through the failure.

External links

Exercise

프로젝트의 CI 가 오늘 Playwright 테스트 돌리면 총 wall 시간 봐. 5분 미만이면 sharding 이 오버헤드 — 이 연습 skip. 10분 넘으면 3-shard 패턴 setup: CI 를 matrix 전략 쓰도록 업데이트, CI 에서 blob reporter 로 전환, merge job 추가. 새 wall 시간 측정 — 옛 시간의 ~1/3 봐야. 병합된 HTML 리포트가 end-to-end 작동하는지 확인 (실패에 클릭, 그것의 trace 봄).
Hint
Merge job 이 'no blob reports found' 로 실패하면 다운로드 패턴이 매칭 안 하는 거. Artifact 이름이 shard 당 unique 해야 함 (blob-report-${{ matrix.shard }}), 다운로드 패턴이 한 폴더로 통합하려 merge-multiple: true 필요.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.