본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 24. 06:20

End-to-End (E2E) 테스트 파이프라인

요약

Playwright와 GitHub Actions를 활용하여 프로덕션 환경에 적합한 End-to-End(E2E) 테스트 파이프라인을 구축하는 방법을 다룹니다. 실제 사용자 흐름을 테스트하고 CI/CD 환경에서 자동화하는 베스트 프랙티스를 제공합니다.

핵심 포인트

  • Playwright를 활용한 React 앱 E2E 테스트 설정
  • GitHub Actions를 이용한 CI 파이프라인 자동화
  • 테스트 실패 시 스크린샷 및 비디오 자동 캡처 설정
  • Cypress 대비 Playwright의 속도 및 멀티 브라우저 강점

Playwright(권장)와 GitHub Actions를 사용하여 실제 팀들이 프로덕션 환경에서 사용하는 것과 같은 실제 End-to-End (E2E) 테스트 파이프라인을 구축해 봅시다. 다음 내용을 다룹니다:

🧪 E2E 테스트란 무엇인가
⚙️ Playwright 설정 (React 앱 예시)
🚀 GitHub Actions CI 파이프라인
📸 실패 시 테스트 리포트 + 스크린샷
🧠 프로덕션 베스트 프랙티스

🧠 0. E2E 테스트란 무엇인가?
E2E (End-to-End) 테스트란 다음을 의미합니다: "실제 사용자가 앱을 사용하는 방식대로 테스트하십시오."
함수를 테스트하는 대신, 다음을 테스트합니다:

  • 버튼 클릭
  • 양식(Form) 채우기
  • 탐색(Navigation)
  • API + UI를 함께 테스트

⚔️ Playwright vs Cypress (빠른 결정)

기능PlaywrightCypress
속도 🚀더 빠름보통
멀티 브라우저 ✅지원함제한적
CI 친화도 ⭐매우 우수좋음
현대적인 앱최선의 선택좋음

👉 우리는 Playwright(2025년 업계 표준)를 사용할 것입니다.

🧱 1. Playwright 설치 (React 프로젝트)

npm init playwright@latest

프롬프트가 나타나면 다음을 선택하세요:

  • JavaScript 또는 TypeScript (TS 권장)
  • 테스트 폴더: tests
  • GitHub Actions: YES

📁 2. 프로젝트 구조

my-app/
├── tests/
│   ├── example.spec.ts
├── playwright.config.ts
├── package.json

🧪 3. 첫 번째 E2E 테스트 (실제 사용자 흐름)
예시: 로그인 흐름 테스트

import { test, expect } from '@playwright/test';

test('사용자가 성공적으로 로그인할 수 있음', async ({ page }) => {
  await page.goto('http://localhost:3000/login');
  await page.fill('input[name="email"]', 'test@example.com');
  await page.fill('input[name="password"]', 'password123');
  await page.click('button[type="submit"]');
  await expect(page).toHaveURL(/dashboard/);
});

🚀 4. 로컬에서 테스트 실행

npx playwright test

UI 모드 실행 (매우 유용함):

npx playwright test --ui

📸 5. 실패 시 자동 스크린샷

Playwright는 다음을 자동으로 캡처합니다:

  • 스크린샷 (screenshots)
  • 비디오 (videos)
  • 트레이스 (traces)

설정(config)에서 활성화:

use: {
  screenshot: 'only-on-failure',
  video: 'retain-on-failure',
  trace: 'on-first-retry'
}

⚙️ 6.

⚙️ 6.

GitHub Actions CI 파이프라인 (E2E 자동화) 📁 .github/workflows/e2e.yml

on:
  push:
    branches: [ main ]
pull_request:
  branches: [ main ]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node
        uses: actions/setup-node@v4
        with:
          node-version: 20
      - name: Install dependencies
        run: npm install
      - name: Install Playwright browsers
        run: npx playwright install --with-deps
      - name: Run Playwright tests
        run: npx playwright test
--- # 🧠 7. CI에서 발생하는 일 
```plaintext id="flow1"
Push 코드 ↓ GitHub Actions 시작 ↓
의존성 설치 ↓ 브라우저 설치 (Chromium, Firefox, WebKit) ↓ E2E 테스트 실행 ↓
통과 → 병합 허용 실패 → PR 차단 + 리포트 표시
📊 8. HTML 테스트 리포트 추가
리포트 활성화:
```ts id="rep1"
reporter: [['html'], ['list']]
CI에서:
```yaml id="rep2"
- name: Upload Playwright report
  uses: actions/upload-artifact@v4
  if: always()
  with:
    name: playwright-report
    path: playwright-report
🌐 9. 실제 배포된 앱 테스트 (PRO 설정)
localhost 대신:
```ts id="prod1"
await page.goto(' https://your-app.vercel.app/login');
👉 이것을 **진정한 프로덕션 E2E 테스트**로 만듭니다.
--- # 🧪 10. 고급 실제 환경 테스트 예시 ---
## 🟢 UI 탐색 테스트 
```ts id="nav1"
test('navigate to dashboard', async ({ page }) => {
  await page.goto('/');
  await page.click('text=Dashboard');
  await expect(page).toHaveURL(/dashboard/);
});
🟡 폼 유효성 검사 테스트 
```ts id="form1"
test('shows error for empty email', async ({ page }) => {
  await page.goto('/login');
  await page.click('button[type="submit"]');
  await expect(page.locator('.error')).toContainText('Email is required');
});
--- 
## 🔵 API + UI 결합 테스트 
```ts id="api1"
test('data loads after API call', async ({ page }) => {
  await page.goto('/dashboard');
  await expect(page.locator('.loading')).toBeHidden();
  await expect(page.locator('.chart')).toBeVisible();
});
🔐 11.

CI 모범 사례 (중요) 

✔ 빌드 후 E2E 실행
```yaml id="bp1"
run: npm run build
run: npm start &

✔ 스테이징 환경 (staging environment) 사용
staging.example.com
production.example.com

✔ 불안정한 테스트 (flaky tests) 재시도

retries: 2
---

# ⚠️ 12. 흔한 실수

### ❌ 동작 (behavior) 대신 구현 (implementation)을 테스트함

나쁜 예:
```ts id="bad1"
expect(component.state).toBe(true)

좋은 예:

expect(page).toHaveText('Welcome')

❌ 안정적인 셀렉터 (selectors) 미사용

사용 예:

data-testid="login-button"

그 다음:

page.getByTestId('login-button')

❌ CI 없이 E2E 실행

항상 GitHub Actions에서 실행하세요


🧠 최종 아키텍처 (architecture)

Push / PR
↓
CI (단위 테스트 (unit tests))
↓
E2E 테스트 (Playwright)
↓
앱 빌드 (Build app)
↓
스테이징/프로덕션 배포 (Deploy to staging/production)
↓
보고서 + 스크린샷 GitHub에 저장

🚀 방금 구축한 것

이제 다음과 같은 것들을 갖추게 되었습니다:
🧪 실제 사용자 시뮬레이션 테스트
🚀 CI/CD 통합 E2E 파이프라인
📸 실패 스크린샷 + 비디오
🌍 프로덕션 준비 완료된 테스트 시스템
🔒 안전한 배포 게이팅 (gating) 시스템

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
1

댓글

0