맞왜틀

Playwright E2E 테스트 추가하기 본문

개발 일지/회사 기술 스택

Playwright E2E 테스트 추가하기

deo2kim 2025. 11. 9. 00:51
반응형
투두 앱에 Playwright E2E 테스트 추가하기

🎭 투두 앱에 Playwright E2E 테스트 추가하기

📌 작업 개요

레트로 스타일의 투두 앱에 Playwright를 활용한 E2E(End-to-End) 테스트를 추가했습니다. 접근성(Accessibility)과 테스트 가능성을 함께 개선했습니다.

🎯 주요 작업 내용

2. 접근성(Accessibility) 개선

스크린 리더 사용자와 E2E 테스트를 위해 aria-label 속성을 추가했습니다.

// TodoInput.tsx
<Input
  placeholder="오늘 할 일을 입력하세요..."
  aria-label="할 일 입력"
/>

<Button onClick={handleSubmit} aria-label="할 일 추가">
  ADD
</Button>
// TodoItem.tsx
<Checkbox
  onClick={() => onToggleTodo(todo.id)}
  aria-label={todo.completed ? '할 일 완료 취소' : '할 일 완료'}
>
  {todo.completed ? '✓' : ''}
</Checkbox>

<Button
  onClick={() => onRemoveTodo(todo.id)}
  aria-label={`${todo.title} 삭제`}
>
  DEL
</Button>
💡 핵심 포인트:
삭제 버튼의 aria-label에 투두 제목을 포함시켜 "아침 운동하기 삭제"처럼 어떤 항목을 삭제하는지 명확하게 표현했습니다. 이는 접근성뿐만 아니라 테스트에서 특정 항목을 정확히 선택할 수 있게 해줍니다.

3. Playwright E2E 테스트 작성

17개의 테스트 케이스를 작성했습니다.

테스트 카테고리

카테고리 테스트 수 주요 테스트
초기 화면 4개 제목, 빈 상태, 입력창, 통계 표시
투두 추가 5개 버튼 클릭, Enter 키, 입력창 초기화, 여러 개 추가, 빈 문자열 검증
투두 완료 3개 완료 처리, 완료 취소, 일부만 완료
투두 삭제 3개 삭제, 특정 항목만 삭제, 완료된 항목 삭제
통계 3개 추가/완료/삭제 시 통계 업데이트
통합 시나리오 1개 추가 → 완료 → 삭제 전체 플로우

테스트 코드 구조

test.describe('Todo App', () => {
  // 헬퍼 함수로 중복 제거
  const getTodoInput = (page: Page) =>
    page.getByRole('textbox', { name: '할 일 입력' });

  const addTodo = async (page: Page, todoText: string) => {
    const input = getTodoInput(page);
    await input.fill(todoText);
    await page.getByRole('button', { name: '할 일 추가' }).click();
  };

  test.beforeEach(async ({ page }) => {
    await page.goto('/todos');
  });

  // 테스트는 카테고리별로 그룹화
  test.describe('초기 화면', () => { ... });
  test.describe('투두 추가', () => { ... });
  test.describe('투두 완료', () => { ... });
  test.describe('투두 삭제', () => { ... });
  test.describe('통계', () => { ... });
  test.describe('통합 시나리오', () => { ... });
});

테스트 작성 시 학습한 Best Practices

✅ 헬퍼 함수 활용
중복되는 "투두 추가" 로직을 addTodo() 헬퍼 함수로 분리했습니다. 단, 헬퍼 함수에는 검증(assertion)을 넣지 않고 각 테스트에서 명시적으로 검증합니다.
✅ 접근성 기반 선택자 사용
getByRole(), getByLabel() 같은 접근성 기반 선택자를 우선 사용했습니다. CSS 선택자보다 더 의미론적이고 리팩토링에 강합니다.
✅ 명확한 aria-label
모든 버튼에 고유한 aria-label을 부여해서 테스트에서 정확한 요소를 선택할 수 있게 했습니다. 예: "아침 운동하기 삭제"

4. Playwright 타임아웃 최적화

빠른 피드백을 위해 타임아웃을 대폭 단축했습니다.

// playwright.config.ts
export default defineConfig({
  timeout: 10000,              // 전체 테스트: 10초 (기본 30초)
  use: {
    actionTimeout: 3000,       // 클릭, fill 등: 3초
    navigationTimeout: 5000,   // 페이지 이동: 5초
  },
  expect: {
    timeout: 3000,             // assertion: 3초
  },
});
⚡ 효과: 테스트 실패 시 30초 대기 → 3초 만에 빠르게 실패하여 개발 속도가 10배 향상되었습니다.

📦 커밋 내역

2293f49 config: Playwright 타임아웃 3초로 최적화
5e120b1 test: 투두 앱 Playwright e2e 테스트 추가
96fdeca feat: 투두 컴포넌트에 aria-label 접근성 속성 추가
b08ac20 refactor: 투두 앱 포켓몬 테마 제거 및 일반 텍스트로 변경

💡 배운 점

1. Playwright 선택자 전략

  • getByRole('button', { name: '할 일 추가' }) - 접근성 기반, 가장 권장
  • getByLabel('할 일 입력') - label 요소와 연결된 input 선택
  • getByPlaceholder('...') - placeholder로 선택 (보조적으로 사용)
  • getByText('아침 운동하기') - 텍스트로 선택 (간단할 때 유용)

2. 테스트 구조화

  • 헬퍼 함수: Setup 용도로만 사용 (assertion 없이)
  • 테스트: 명시적인 검증 포함 필수
  • 그룹화: test.describe()로 카테고리별 정리

3. 접근성과 테스트의 시너지

  • 접근성을 위해 추가한 aria-label이 테스트 작성을 훨씬 쉽게 만듦
  • 고유한 레이블은 스크린 리더와 자동화 테스트 모두에게 유용
  • 좋은 접근성 = 좋은 테스트 가능성

🚀 다음 단계

CI/CD 통합
GitHub Actions에 Playwright 테스트를 추가하여 PR 생성 시 자동으로 테스트가 실행되도록 설정할 예정입니다.
// .github/workflows/ci.yml (예정)
jobs:
  e2e-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npx nx e2e web-e2e

📊 테스트 실행 방법

# 전체 테스트 실행
npx nx e2e web-e2e

# UI 모드로 실행 (디버깅)
npx nx e2e web-e2e --ui

# 특정 브라우저만 실행
npx nx e2e web-e2e --project=chromium

🎉 결론

처음 Playwright를 도입하면서 E2E 테스트 작성 방법과 접근성의 중요성을 함께 배울 수 있었습니다. 특히 aria-label을 제대로 활용하면 접근성과 테스트 가능성을 동시에 향상시킬 수 있다는 점이 가장 큰 수확이었습니다.

타임아웃을 3초로 줄여서 테스트 실패 시 빠르게 피드백을 받을 수 있게 된 것도 개발 경험을 크게 개선시켰습니다. 앞으로는 CI/CD에 통합해서 더욱 안정적인 개발 프로세스를 구축할 예정입니다.


반응형