E2E 테스트 개요
20.5.1. 프레임워크 선택
E2E 테스트 프레임워크로 Playwright를 사용하는 것을 권장합니다.
| 항목 | Playwright | Cypress |
|---|---|---|
| 브라우저 지원 | Chromium, Firefox, WebKit | Chromium, Firefox, WebKit (실험적) |
| 실행 속도 | 빠름 (병렬 실행 기본 지원) | 보통 (병렬 실행 시 유료 플랜 필요) |
| 다중 탭/창 | 지원 | 미지원 |
| iframe 지원 | 네이티브 지원 | 제한적 |
| API 테스트 | 내장 지원 | 플러그인 필요 |
| 디버깅 도구 | Trace Viewer, Codegen | Cypress Runner |
| 언어 지원 | TypeScript, JavaScript, Python, Java, .NET | TypeScript, JavaScript |
- Playwright는 다중 브라우저 테스트, 병렬 실행, API 테스트를 기본 지원하므로 TQS 기준 권장 프레임워크입니다.
- Cypress를 이미 사용 중인 프로젝트는 전환을 강제하지 않으나, 신규 프로젝트는 Playwright를 채택합니다.
20.5.2. 핵심 시나리오
E2E 테스트는 사용자의 핵심 업무 흐름을 검증합니다. 아래 시나리오는 필수 테스트 대상입니다.
| 시나리오 | 검증 항목 |
|---|---|
| 로그인/로그아웃 | 정상 로그인, 잘못된 자격 증명 처리, 로그아웃 후 리다이렉트 |
| CRUD 플로우 | 항목 생성, 목록 조회, 상세 조회, 수정, 삭제 |
| 에러 처리 | 404 페이지, 서버 오류 시 사용자 피드백, 네트워크 오류 복구 |
| 권한 제어 | 미인증 사용자 접근 차단, 권한별 메뉴/기능 노출 |
| 폼 제출 | 유효성 검증, 중복 제출 방지, 성공/실패 피드백 |
typescript
// e2e/auth.spec.ts
import { test, expect } from '@playwright/test'
test.describe('인증 플로우', () => {
test('정상 로그인 후 대시보드로 이동해야 합니다', async ({ page }) => {
await page.goto('/login')
await page.fill('[data-testid="input-email"]', 'user@example.com')
await page.fill('[data-testid="input-password"]', 'password123')
await page.click('[data-testid="btn-login"]')
await expect(page).toHaveURL('/dashboard')
await expect(page.locator('[data-testid="user-greeting"]')).toBeVisible()
})
test('잘못된 비밀번호 시 에러 메시지를 표시해야 합니다', async ({ page }) => {
await page.goto('/login')
await page.fill('[data-testid="input-email"]', 'user@example.com')
await page.fill('[data-testid="input-password"]', 'wrong')
await page.click('[data-testid="btn-login"]')
await expect(page.locator('[data-testid="error-message"]')).toBeVisible()
})
})- 모든 핵심 시나리오에 대해 정상 경로와 예외 경로를 모두 테스트합니다.
- 테스트 시나리오는 사용자 스토리 또는 요구사항 문서와 매핑하여 관리합니다.
20.5.3. 테스트 작성 원칙
사용자 관점 테스트
E2E 테스트는 내부 구현이 아닌 사용자가 보고 상호작용하는 요소를 기준으로 작성합니다.
- CSS 클래스명이나 컴포넌트 내부 상태에 의존하지 않습니다.
data-testid속성을 사용하여 테스트 대상 요소를 선택합니다.data-testid네이밍 규칙:{요소유형}-{설명}(예:btn-submit,input-email,list-users)
플레이키 테스트 방지
불안정한(flaky) 테스트는 신뢰도를 저하시키므로 다음 원칙을 준수합니다.
- 고정된 대기 시간(
waitForTimeout) 대신 조건 기반 대기(waitForSelector,expect().toBeVisible())를 사용합니다. - 테스트 데이터는 각 테스트에서 독립적으로 생성하고 정리합니다.
- 외부 API 의존성은 가능한 한 목 서버로 대체합니다.
- 네트워크 요청 완료를
waitForResponse()로 명시적으로 대기합니다.
20.5.4. CI 연동
CI 환경에서 E2E 테스트를 자동 실행하기 위한 설정입니다.
typescript
// playwright.config.ts
import { defineConfig } from '@playwright/test'
export default defineConfig({
testDir: './e2e',
fullyParallel: true,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'on-first-retry',
},
webServer: {
command: 'yarn dev',
port: 3000,
reuseExistingServer: !process.env.CI,
},
})| 설정 항목 | CI 환경 값 | 설명 |
|---|---|---|
retries | 2 | 실패 시 최대 2회 재시도 |
workers | 1 | 안정성을 위해 직렬 실행 |
screenshot | only-on-failure | 실패 시 스크린샷 자동 저장 |
video | on-first-retry | 첫 번째 재시도 시 비디오 녹화 |
trace | on-first-retry | 첫 번째 재시도 시 Trace 파일 저장 |
- CI 환경에서는 headless 모드로 실행합니다 (Playwright 기본값).
- 실패 시 생성되는 스크린샷, 비디오, Trace 파일은 CI 아티팩트로 보관합니다.
webServer설정을 통해 테스트 전 개발 서버를 자동으로 시작합니다.- 재시도 횟수는 CI에서만 활성화하여 로컬 개발 시에는 즉시 실패를 확인합니다.