Playwright vs Cypress — 2025년 E2E 테스트 도구 비교

게시일: 2025년 11월 18일 · 14분 읽기

나는 Cypress를 3년 넘게 사용했다. 그리고 작년에 Playwright로 전환했다. 멀티브라우저 지원이 결정적이었는데, 이번 글에서는 두 도구의 차이점을 상세히 분석하겠다.

아키텍처의 근본적인 차이

Cypress와 Playwright의 가장 중요한 차이는 아키텍처다. 이것이 성능, 안정성, 기능성에 모두 영향을 미친다.

Cypress: In-browser 방식

Cypress는 테스트 코드가 브라우저 내부에서 실행된다. 즉, 애플리케이션과 같은 프로세스에서 동작한다는 뜻이다.


// Cypress는 브라우저 내부에서 이 코드를 실행
describe('Login Flow', () => {
  it('should login successfully', () => {
    cy.visit('https://app.example.com/login');
    cy.get('input[name=email]').type('user@example.com');
    cy.get('input[name=password]').type('password123');
    cy.get('button[type=submit]').click();
    cy.url().should('include', '/dashboard');
  });
});

장점은 애플리케이션의 내부 상태에 직접 접근할 수 있다는 것이다. Redux store, Vue state 등에 접근 가능하다.

Playwright: Out-of-process 방식

Playwright는 테스트 코드가 Node.js 프로세스에서 실행되고, 브라우저와는 웹소켓으로 통신한다.


// Playwright는 Node.js에서 이 코드를 실행하고 브라우저에 명령을 내림
import { test, expect } from '@playwright/test';

test('should login successfully', async ({ page }) => {
  await page.goto('https://app.example.com/login');
  await page.fill('input[name=email]', 'user@example.com');
  await page.fill('input[name=password]', 'password123');
  await page.click('button[type=submit]');
  await expect(page).toHaveURL(/.*dashboard/);
});

장점은 브라우저와 완전히 분리되어 있다는 것이다. 테스트가 안정적이고, 여러 탭을 동시에 제어할 수 있다.

브라우저 지원

이것이 내가 Playwright로 전환한 주된 이유다.

기능 Cypress Playwright
Chrome/Edge
Firefox
Safari/WebKit
Mobile Chrome
Mobile Safari

Cypress는 Safari를 지원하지 않는다. 이는 iOS 테스트를 할 수 없다는 의미다. 반면 Playwright는 Safari의 렌더링 엔진인 WebKit을 완벽히 지원한다.


// Playwright에서 여러 브라우저 테스트
import { test, expect } from '@playwright/test';

test.describe('Cross-browser tests', () => {
  test('Chrome', async ({ page }) => {
    // Chromium에서만 실행
  });

  test('Firefox', async ({ page }) => {
    // Firefox에서만 실행
  });

  test('Safari', async ({ page }) => {
    // WebKit에서만 실행
  });

  test('Mobile', async ({ page }) => {
    // 모바일 브라우저 에뮬레이션
    await page.setViewportSize({ width: 375, height: 812 });
  });
});

속도 벤치마크

간단한 로그인 플로우를 여러 번 실행하는 테스트로 비교해보자.


// 100회 반복 테스트
// Cypress: 약 180초 (테스트당 1.8초)
// Playwright: 약 90초 (테스트당 0.9초)

Playwright가 약 2배 빠르다. 이유는 out-of-process 아키텍처 덕분에 병렬 실행이 더 효율적이기 때문이다. Cypress는 동시에 하나의 브라우저만 제어할 수 있지만, Playwright는 여러 브라우저를 동시에 제어할 수 있다.


// Playwright 병렬 실행
import { test, expect } from '@playwright/test';

test.describe.configure({ mode: 'parallel' });

test('test 1', async ({ page }) => {
  // 동시 실행
});

test('test 2', async ({ page }) => {
  // 동시 실행
});

test('test 3', async ({ page }) => {
  // 동시 실행
});

디버깅 경험

Cypress - Time Travel Debugger

Cypress는 각 명령어 실행 시점의 화면을 스냅샷으로 저장한다. 테스트 결과에서 각 단계를 클릭하면 그 시점의 화면과 DOM을 볼 수 있다.


// Cypress는 이 각 명령어마다 스냅샷을 저장
cy.visit('https://app.example.com');
cy.get('input').type('data');  // 스냅샷 1
cy.get('button').click();       // 스냅샷 2
cy.get('.success-message');     // 스냅샷 3

Playwright - Trace Viewer

Playwright는 전체 테스트 실행을 기록했다가 나중에 재생할 수 있다. 마치 영화를 돌려보는 것처럼 테스트를 추적할 수 있다.


// playwright.config.ts
export default defineConfig({
  use: {
    trace: 'on-first-retry',
  },
});

// 실행
npx playwright test --trace on

// 보기
npx playwright show-trace trace.zip

또한 Playwright는 inspect 모드에서 요소를 클릭하면 자동으로 선택자를 생성해준다.


npx playwright codegen https://app.example.com

이 명령어를 실행하면 브라우저가 열리고, 내가 클릭하는 모든 행동이 자동으로 코드로 변환된다.

CI 통합

둘 다 GitHub Actions, GitLab CI 등과 잘 통합된다.


# GitHub Actions with Cypress
name: Cypress Tests
on: [push]
jobs:
  cypress-run:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: cypress-io/github-action@v4
        with:
          start: npm run dev

# GitHub Actions with Playwright
name: Playwright Tests
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
        with:
          node-version: 18
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npm run dev &
      - run: npx playwright test

컴포넌트 테스트

최근 두 도구 모두 컴포넌트 테스트를 지원하기 시작했다.


// Cypress Component Test
import { mount } from 'cypress/react';
import LoginForm from './LoginForm';

describe('LoginForm Component', () => {
  it('renders correctly', () => {
    mount();
    cy.get('input[name=email]').should('be.visible');
  });
});

// Playwright Component Test
import { test, expect } from '@playwright/experimental-ct-react';
import LoginForm from './LoginForm';

test('renders correctly', async ({ mount }) => {
  const component = await mount();
  await expect(component.locator('input[name=email]')).toBeVisible();
});

API 테스트

Playwright는 API 테스트 기능이 더 강력하다.


// Playwright API 테스트
import { test, expect } from '@playwright/test';

test('API test', async ({ request }) => {
  const response = await request.post('https://api.example.com/login', {
    data: {
      email: 'user@example.com',
      password: 'password'
    }
  });

  expect(response.status()).toBe(200);
  const json = await response.json();
  expect(json.token).toBeTruthy();
});

결론

Cypress를 3년 사용한 나의 평가는 이렇다:

2025년 기준, Safari를 테스트해야 한다면 Playwright 일택이다. 그렇지 않더라도 성능과 확장성을 고려하면 Playwright를 추천한다.

iL
ian.lab

실무 개발자입니다. 현장에서 겪은 문제와 해결 과정을 기록합니다. 오류 제보는 연락처로 보내주세요.