엔드‑투‑엔드(E2E) 테스트 파이프라인
출처: Dev.to
실제 프로덕션에서 팀이 사용하는 End-to-End (E2E) 테스트 파이프라인을 Playwright(추천)와 GitHub Actions를 이용해 구축해 보겠습니다.
다음 내용을 보여드릴게요:
🧪 E2E 테스트가 무엇인지
⚙️ Playwright 설정 (React 앱 예시)
🚀 GitHub Actions CI 파이프라인
📸 실패 시 테스트 보고서 + 스크린샷
🧠 프로덕션 베스트 프랙티스
E2E (End-to-End) 테스트란
“실제 사용자가 앱을 사용하는 것처럼 테스트한다.”는 의미입니다.
함수 단위 테스트가 아니라 다음을 테스트합니다:
- 버튼 클릭
- 폼 입력
- 페이지 이동
- API와 UI를 함께
| Feature | Playwright | Cypress |
|---|---|---|
| Speed | 🚀 Faster | 보통 |
| Multi-browser | ✅ Yes | 제한적 |
| CI friendly | ⭐ Excellent | Good |
| Modern apps | ⭐ Best choice | Good |
👉 Playwright를 사용할 겁니다 (2025년 업계 표준)
# 프롬프트가 뜨면 다음을 선택하세요:
# * JavaScript 또는 TypeScript (TS 권장)
# * Tests 폴더: `tests`
# * GitHub Actions: YES
📁 2. 프로젝트 구조
my-app/
├── tests/
│ ├── example.spec.ts
├── playwright.config.ts
├── package.json
test('user can login successfully', async ({ page }) => {
await page.goto('http://localhost:3000/login');
await page.fill('input[name="email"]', 'test@example.com');
await page.click('button[type="submit"]');
await expect(page).toHaveURL(/dashboard/);
});
🚀 4. 로컬에서 테스트 실행
npx playwright test
UI 모드 열기 (매우 유용):
npx playwright test --ui
📸 5. 실패 시 자동 스크린샷
Playwright는 자동으로 다음을 캡처합니다:
- 스크린샷
- 비디오
- 트레이스
설정 파일에 아래와 같이 활성화하세요:
use: {
screenshot: 'only-on-failure',
video: 'retain-on-failure',
trace: 'on-first-retry'
}
.github/workflows/e2e.yml
on:
jobs:
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에서 일어나는 일
코드 푸시
↓
GitHub Actions 시작
↓
의존성 설치
↓
브라우저 설치 (Chromium, Firefox, WebKit)
↓
E2E 테스트 실행
↓
통과 → 머지 허용
실패 → PR 차단 + 보고서 표시
보고서 활성화:
reporter: [['html', { open: 'never' }]],
CI에서 다음을 수행합니다:
- name: Upload Playwright report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
path: playwright-report
localhost 대신:
await page.goto('https://your-app.vercel.app/login');
👉 이렇게 하면 진정한 프로덕션 E2E 테스트가 됩니다.
🧪 10. 실제 상황에 적용한 고급 테스트 예시
🟢 UI 네비게이션 테스트
test('navigate to dashboard', async ({ page }) => {
await page.goto('/');
await page.click('text=Dashboard');
await expect(page).toHaveURL(/dashboard/);
});
await expect(page.locator('.error')).toContainText('Email is required');
🔵 API + UI 결합 테스트
test('data loads after API call', async ({ page }) => {
await page.goto('/dashboard');
await expect(page.locator('.loading')).toBeHidden();
await expect(page.locator('.chart')).toBeVisible();
});
run: npm run build
run: npm start &
✔ 스테이징 환경 사용
staging.example.comproduction.example.com
// 필요 시 환경 변수 등을 활용해 URL을 동적으로 지정
⚠️ 12. 흔히 저지르는 실수
❌ 구현이 아닌 행동을 테스트함
잘못된 예:
expect(component.state).toBe(true)
올바른 예:
await expect(page.locator('button')).toBeEnabled()
❌ 안정적인 셀렉터가 없음
사용할 것:
<button data-testid="login-button">Login</button>
그 후:
await page.click('[data-testid="login-button