Playwright - E2E

하이솝·어제

소프트웨어공학

목록 보기
26/27
post-thumbnail

Playwright

  • 마이크로소프트가 개발한 오픈소스 웹 자동화 라이브러리

  • 단일 코드 베이스
    하나의 코드로 모든 브라우저 제어

  • 엔진 지원
    크롬, 파이어폭스, 사파리 완벽 지원

  • 다국어 지원
    TypeScript JavaScript, Python, Java, .NET

Playwright vs Selenium

E2E Test

  • 사용자가 실제로 애플리케이션을 사용하는 처음부터 끝까지의
    흐름 전체를 확인하는 테스트

  • 개별 함수가 아닌 사용자 관점에서의 시나리오 검증

  • ex) 회원가입 → 로그인 → 상품 검색 → 장바구니 → 결제 완료

  • 전체 서비스가 실제 환경에서 문제없이 동작하는지 보장

설치 및 프로젝트 시작

사전 요구사항: Node.js 16 버전 이상 설치

버전 확인 명령어: node -v

설치 명령어: npm init playwright@latest

설치 과정에서 TypeScript/JavaScript 선택, 예제 테스트 자동 생성

프로젝트 구조 및 설정 파일

tests/: 테스트 코드 파일을 저장하는 폴더

playwright.config.ts: 전체 실행 환경 설정 파일

핵심 옵션

  • retries: 실패 시 재시도 횟수
  • headless: 브라우저 창을 띄울지 여부

projects: 크롬, 파이어폭스, 웹킷 등 브라우저 별 실행 설정

사례: 네이버 검색 테스트 코드

시나리오: 네이버 접속 → 검색창에 "Playwright" 입력

import { test, expect } from '@playwright/test';
test('  네이버 검색테스트', async ({ page }) => {
  // 1. 네이버 사이트로 이동
  await page.goto('https://www.naver.com');
  
  // 2. 검색창(#query) 에 'Playwright' 입력
  await page.fill('#query', 'Playwright');

시나리오: 엔터 키 입력 → 결과 페이지 제목 확인

  // 3. 엔터 키 눌러서 검색 실행
  await page.press('#query', 'Enter');
  // 4. 페이지 제목에 'Playwright'   가 있는지 확인
  await expect(page).toHaveTitle(/Playwright/);
});

셀렉터(Selector)와 HTML

셀렉터(selector): 웹 페이지 내 특정 요소를 가리키는 주소

<input id="query" class="search_input" name="q">
<button class="btn_search">검색</button>

// CSS 선택자
#query        // id  로 찾기
.btn_search   // class  로 찾기

Playwright 로케이터(Locator)

로케이터를 써야 하는 이유

  • 깨지기 쉬운 CSS 경로 대신 사용자 관점 셀렉터 이용

  • 유지보수 용이: 구조가 바뀌어도 버튼의 역할과 이름은 그대로이기 때문

  • 가독성 향상: 코드만 봐도 무엇을 테스트하는지 알 수 있음

  • 웹 접근성(Accessibility) 준수

플래키(Flaky) 테스트

  • 성공과 실패를 오가는 불안정한 테스트

  • 원인: 네트워크 지연, 타이밍 이슈, 비동기 렌더링, 데이터 의존성

  • 영향: 테스트 결과에 대한 신뢰도 하락

  • 개발자가 테스트를 신뢰하지 않아 결국 자동화 포기

플래키 해결: 1. 자동 대기(Auto-Waiting)

  • 액션을 수행하기 전, 요소가 준비될 때 까지 자동으로 대기

체크 항목

  • 1) Visible: 요소가 화면에 보이는가?
  • 2) Stable: 애니메이션이 끝나 정지했는가?
  • 3) Enabled: 활성화되어 클릭 가능한가?
  • 4) Receives events: 이벤트가 처리될 준비가 됐는가?

플래키 해결: 2. 웹 퍼스트 어설션

  • 고정 대기(waitForTimeout)절대 금지
  • 웹 퍼스트 어설션은 조건이 만족될 때 까지 최대 5초간 확인
  • 조건이 맞으면 다음 단계로 넘어가므로 안정성과 속도 모두 확보

테스팅 피라미드 전략

  • 아래로 갈수록 많이, 위로 갈수록 개수를 적게
  • 유닛은 수천 개 단위로 빠르게, E2E는 핵심 흐름 위주로 소수 정예

테스팅 비교

유닛 테스트(Unit Test)

  • 함수, 메서드코드의 가장 작은 단위를 검증
  • 초고속(ms) 실행, 실패 시 문제 위치를 바로 특정
  • DB, 서버, 네트워크 등 외부 의존 없음
  • ex) sum(1, 2) 함수가 3을 반환하는가

통합 테스트(Integration Test)

  • 여러 모듈이 결합했을 때의 상호작용 검증
  • DB 연동, API 호출과 응답, 외부 서비스 연계
  • 유닛 테스트보다는 느리고, E2E 테스트보다는 빠름
  • ex) 회원가입 요청 시 실제로 DB에 사용자 정보가 저장되는지 확인

E2E 테스트

  • 실제 사용자 관점에서 전체 흐름을 시뮬레이션
  • 도구: Playwright, Selenium, Cypress 등
  • 실제 사용자 경험을 그대로 검증
  • 느리고 관리가 어려움, 핵심 기능 위주로 작성

사례: 네트워크 모킹

사용 의도와 목록 조회

1) 외부 서버에 의존하지 않는 독립적인 테스트 만들기

test('가짜 데이터를 사용한 목록 조회', async ({ page }) => {
  await page.route('**/api/todos', async route => {
    await route.fulfill({
      status: 200,
      body: JSON.stringify([{ id: 1, text: '모킹된 할일' }]),
    });
  });
  await page.goto('http://localhost:5173');
  await expect(page.getByText('모킹된 할일')).toBeVisible();
});

2) 인위적으로 만들기 어려운 엣지 케이스를 강제 재현

test('서버 에러 시 에러 메시지 표시', async ({ page }) => {
  await page.route('**/api/todos', async route => {
    await route.fulfill({ status: 500 }); // 500  에러 강제
  });
  await page.goto('http://localhost:5173');
  await expect(page.getByText('오류가 발생했습니다')).toBeVisible();
});

마무리

  • Playwright을 이용한 빠르고 안정적인 E2E 구현
  • 로케이터로 깨지지 않는 견고한 셀렉터 작성
  • 테스팅 피라미드 전략으로 테스트 효율 극대화
  • 네트워크 모킹으로 외부 환경으로부터 독립성 확보
  • 고정 대기 금지, 웹 퍼스트 어설션 사용 원칙 준수

0개의 댓글