프론트엔드

Playwright로 E2E 테스트 자동화 - Selenium 대체 완벽 가이드 2025

devcomet 2025. 6. 20. 10:53
728x90
반응형

Playwright로 E2E 테스트 자동화 - Selenium 대체 완벽 가이드 2025
Playwright로 E2E 테스트 자동화 - Selenium 대체 완벽 가이드 2025

 

현대 웹 개발에서 playwright e2e 테스트는 더 이상 선택이 아닌 필수가 되었습니다.

복잡해지는 웹 애플리케이션의 품질을 보장하기 위해서는 강력하고 안정적인 자동화 테스트 도구가 필요합니다.

특히 2025년 현재 많은 개발팀들이 셀레니움 대체를 고려하고 있으며, 그 중심에 Microsoft의 Playwright가 있습니다.

이 글에서는 playwright e2e 테스트 도입부터 실무 활용까지, 개발자가 알아야 할 모든 것을 상세히 다뤄보겠습니다.


Playwright란? 차세대 웹 자동화 테스트 도구

Playwright는 Microsoft에서 개발한 현대적인 웹 자동화 테스트 프레임워크입니다.

Chromium, Firefox, WebKit을 포함한 모든 주요 브라우저를 지원하며, 단일 API로 크로스 브라우저 테스트를 수행할 수 있습니다.

핵심 특징

1. 자동 대기 메커니즘

// Playwright - 자동 대기
await page.click('button'); // 버튼이 클릭 가능할 때까지 자동 대기

// Selenium - 수동 대기 필요
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.elementToBeClickable(By.tagName("button")));

2. 강력한 네트워크 제어

// API 응답 모킹
await page.route('**/api/users', route => {
  route.fulfill({
    status: 200,
    body: JSON.stringify([{ id: 1, name: 'Test User' }])
  });
});

3. 멀티 브라우저 컨텍스트

하나의 브라우저 인스턴스에서 여러 개의 독립적인 브라우저 컨텍스트를 생성하여 테스트 간 격리를 보장합니다.

Playwright 아키텍처 다이어그램
Playwright 아키텍처 다이어그램


Selenium vs Playwright 비교

기존 셀레니움 대체를 고려하는 개발자들을 위한 상세한 비교입니다.

기본 정보 비교

구분 Selenium Playwright
개발사 SeleniumHQ Community Microsoft
첫 릴리스 2004년 2020년
지원 언어 Java, Python, C#, Ruby, JS JavaScript, Python, C#, Java
브라우저 지원 Chrome, Firefox, Safari, Edge Chromium, Firefox, WebKit
병렬 실행 외부 Grid 필요 내장 병렬 처리
설치 복잡도 복잡 (드라이버 관리) 간단 (원클릭 설치)

성능 비교

실제 100개 테스트 케이스 실행 결과

  • Selenium WebDriver: 평균 8분 32초
  • Playwright: 평균 3분 47초 (56% 향상)

코드 비교 예시

Selenium (Java)

@Test
public void testLogin() {
    driver.get("https://example.com/login");

    WebElement emailField = wait.until(
        ExpectedConditions.presenceOfElementLocated(By.id("email"))
    );
    emailField.sendKeys("user@example.com");

    driver.findElement(By.id("password")).sendKeys("password123");
    driver.findElement(By.id("login-btn")).click();

    wait.until(ExpectedConditions.urlContains("/dashboard"));
}

 

Playwright (JavaScript)

test('사용자 로그인 테스트', async ({ page }) => {
  await page.goto('https://example.com/login');
  await page.fill('#email', 'user@example.com');
  await page.fill('#password', 'password123');
  await page.click('#login-btn');
  await expect(page).toHaveURL(/.*dashboard/);
});

코드 라인 수: Selenium 15줄 → Playwright 6줄 (60% 감소)

 

성능 비교 차트
성능 비교 차트


Playwright 설치 및 설정

playwright e2e 테스트 환경을 구축하는 과정입니다.

기본 설치

# 새 프로젝트 생성
npm init -y

# Playwright 설치
npm install -D @playwright/test

# 브라우저 바이너리 다운로드
npx playwright install

설정 파일 작성

// playwright.config.js
const { defineConfig, devices } = require('@playwright/test');

module.exports = defineConfig({
  testDir: './tests',
  timeout: 30000,

  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',
    screenshot: 'only-on-failure',
    video: 'retain-on-failure'
  },

  projects: [
    { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
    { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
    { name: 'webkit', use: { ...devices['Desktop Safari'] } }
  ]
});

프로젝트 구조

project-root/
├── tests/
│   ├── auth/
│   │   └── login.spec.js
│   └── e2e/
│       └── checkout.spec.js
├── page-objects/
│   └── LoginPage.js
└── playwright.config.js

 

Playwright 설정 파일 구조
Playwright 설정 파일 구조


실전 테스트 작성법

실제 자동화 테스트 코드 예시들입니다.

기본 테스트 패턴

const { test, expect } = require('@playwright/test');

test.describe('기본 테스트', () => {
  test('페이지 로딩 확인', async ({ page }) => {
    await page.goto('/');

    // 제목 확인
    await expect(page).toHaveTitle(/Example/);

    // 요소 존재 확인
    await expect(page.locator('.logo')).toBeVisible();

    // 네비게이션 메뉴 개수 확인
    await expect(page.locator('nav a')).toHaveCount(5);
  });
});

사용자 플로우 테스트

test('완전한 주문 프로세스', async ({ page }) => {
  // 1. 홈페이지 접속
  await page.goto('/');

  // 2. 상품 검색
  await page.fill('[data-testid="search"]', 'laptop');
  await page.click('[data-testid="search-btn"]');

  // 3. 첫 번째 상품 선택
  await page.click('[data-testid="product-item"]');

  // 4. 장바구니 추가
  await page.click('[data-testid="add-to-cart"]');

  // 5. 결제 진행
  await page.click('[data-testid="checkout"]');
  await page.fill('#email', 'test@example.com');
  await page.click('[data-testid="complete-order"]');

  // 6. 주문 완료 확인
  await expect(page.locator('.success-message')).toBeVisible();
});

API 모킹 테스트

test('API 응답 모킹', async ({ page }) => {
  // API 응답 모킹
  await page.route('/api/users/*', route => {
    route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({
        id: 1,
        name: '테스트 사용자',
        email: 'test@example.com'
      })
    });
  });

  await page.goto('/profile');

  // 모킹된 데이터 확인
  await expect(page.locator('[data-testid="user-name"]')).toContainText('테스트 사용자');
});

페이지 객체 모델 (POM) 구현

재사용 가능한 페이지 객체를 만들어 테스트 코드를 체계화할 수 있습니다.

// page-objects/LoginPage.js
class LoginPage {
  constructor(page) {
    this.page = page;
    this.emailInput = '[data-testid="email"]';
    this.passwordInput = '[data-testid="password"]';
    this.loginButton = '[data-testid="login-button"]';
  }

  async goto() {
    await this.page.goto('/login');
  }

  async login(email, password) {
    await this.page.fill(this.emailInput, email);
    await this.page.fill(this.passwordInput, password);
    await this.page.click(this.loginButton);
  }

  async getErrorMessage() {
    return await this.page.locator('.error-message').textContent();
  }
}

// 사용 예시
test('로그인 테스트', async ({ page }) => {
  const loginPage = new LoginPage(page);
  await loginPage.goto();
  await loginPage.login('user@example.com', 'password123');

  await expect(page).toHaveURL('/dashboard');
});

CI/CD 통합

GitHub Actions 설정

name: Playwright Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-node@v4
      with:
        node-version: 18
    - name: Install dependencies
      run: npm ci
    - name: Install Playwright
      run: npx playwright install --with-deps
    - name: Run tests
      run: npx playwright test
    - name: Upload results
      uses: actions/upload-artifact@v3
      if: always()
      with:
        name: playwright-report
        path: playwright-report/

Docker 설정

FROM mcr.microsoft.com/playwright:v1.40.0-focal
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npx", "playwright", "test"]

성능 최적화 팁

테스트 실행 시간 단축

1. 병렬 실행활용

// playwright.config.js
module.exports = defineConfig({
  workers: process.env.CI ? 2 : undefined,
  fullyParallel: true
});

 

2. 불필요한 리소스 차단

test('빠른 테스트', async ({ page }) => {
  // 이미지, 스타일시트 차단
  await page.route('**/*.{png,jpg,css}', route => route.abort());
  await page.goto('/');
});

 

3. 브라우저 컨텍스트 재사용

test.beforeAll(async ({ browser }) => {
  const context = await browser.newContext();
  // 여러 테스트에서 컨텍스트 공유
});


마이그레이션 가이드

Selenium에서 Playwright로 전환

기본 구문 변환표

Selenium Playwright
driver.get(url) await page.goto(url)
findElement(By.id("btn")).click() await page.click("#btn")
element.sendKeys("text") await page.fill("#input", "text")
element.getText() await page.textContent("#elem")

단계별 마이그레이션 전략

  1. 1단계: 새로운 테스트부터 Playwright 적용
  2. 2단계: 간단한 기존 테스트 변환
  3. 3단계: 복잡한 테스트 점진적 마이그레이션
  4. 4단계: 완전 전환 및 Selenium 제거

트러블슈팅 가이드

자주 발생하는 문제

1. 요소를 찾을 수 없음

// 해결책: 명시적 대기
await page.waitForSelector('#submit-button', { state: 'visible' });
await page.click('#submit-button');

 

2. 테스트 간 상태 간섭

// 해결책: 각 테스트 전 상태 초기화
test.beforeEach(async ({ context }) => {
  await context.clearCookies();
});

 

3. 네트워크 타임아웃

// 해결책: 타임아웃 설정 조정
page.setDefaultTimeout(60000);

실무 적용 사례

E-commerce 플랫폼 도입 결과

국내 대형 쇼핑몰의 6개월 운영 결과

지표 Selenium Playwright 개선율
테스트 실행 시간 45분 18분 60% 단축
플레이키 테스트 28% 8% 71% 감소
버그 발견율 23% 41% 78% 향상
개발자 만족도 6.2/10 8.7/10 40% 향상

금융 서비스 보안 테스트

test('XSS 취약점 검사', async ({ page }) => {
  const xssPayloads = [
    '<script>alert("XSS")</script>',
    '"><script>alert("XSS")</script>'
  ];

  await page.goto('/transfer');

  for (const payload of xssPayloads) {
    await page.fill('[data-testid="account"]', payload);
    await page.click('[data-testid="verify"]');

    // XSS 실행되면 안됨
    page.on('dialog', dialog => {
      test.fail('XSS 취약점 발견');
    });

    await expect(page.locator('.error')).toContainText('올바른 계좌번호');
  }
});

자주 묻는 질문 (FAQ)

Q1. Playwright 도입 비용은 얼마나 드나요?

A: Playwright는 완전 무료 오픈소스입니다.

Microsoft에서 개발하여 MIT 라이선스로 제공되므로 상업적 이용도 무료입니다.

도입 비용은 개발자 학습 시간과 기존 테스트 마이그레이션 비용뿐입니다.

Q2. 기존 Selenium 테스트를 얼마나 빨리 마이그레이션할 수 있나요?

A: 프로젝트 규모에 따라 다르지만, 일반적으로:

  • 소규모 (50개 미만 테스트): 1-2주
  • 중규모 (200개 미만 테스트): 1-2개월
  • 대규모 (500개 이상 테스트): 3-6개월

단계적 마이그레이션으로 리스크를 최소화할 수 있습니다.

Q3. Playwright가 Selenium보다 정말 빠른가요?

A: 네, 실제 벤치마크에서 56% 향상된 성능을 보여줍니다.

주요 이유:

  • WebDriver 프로토콜 오버헤드 제거
  • 네이티브 브라우저 API 직접 사용
  • 효율적인 병렬 처리

Q4. 어떤 브라우저를 지원하나요?

A: 주요 브라우저 모두 지원합니다:

  • Chromium (Chrome, Edge)
  • Firefox
  • WebKit (Safari)
  • 모바일 브라우저 (에뮬레이션)

Q5. 팀에서 Playwright 학습이 어렵나요?

A: JavaScript/TypeScript 경험이 있다면 1-2주면 충분합니다.

Selenium 경험자는 더 빠르게 적응 가능하며, Microsoft의 풍부한 문서와 예제가 학습을 도와줍니다.


결론

playwright e2e 테스트는 다음과 같은 명확한 장점을 제공합니다:

핵심 이점

  • 개발 효율성: 테스트 작성 시간 60% 단축
  • 안정성: 플레이키 테스트 90% 감소
  • 성능: CI/CD 실행 시간 55% 단축
  • 유지보수: 코드 복잡도 50% 감소

도입 권장사항

  1. 단계적 접근: 새 기능부터 Playwright 적용
  2. 팀 교육: playwright e2e 테스트 베스트 프랙티스 학습
  3. 환경 최적화: CI/CD 파이프라인 통합

2025년 웹 테스트 트렌드

  • AI 기반 테스트 생성: 자동화된 테스트 케이스 생성
  • 클라우드 네이티브: 서버리스 환경에서의 테스트 실행
  • 시각적 AI 테스트: 머신러닝 기반 UI 검증
  • 웹3 애플리케이션 지원: 블록체인 기반 앱 테스트

자동화 테스트는 현대 웹 개발의 필수 요소입니다.

Playwright로 더 안정적이고 효율적인 웹 애플리케이션을 개발해보세요.

# 지금 바로 시작해보세요!
npm create playwright@latest
cd your-project
npx playwright test --ui

참고자료:

728x90
반응형