Playwright 고급 사용법

Playwright는 프록시 설정, 환경 변수 관리, 세션 분리, 트레이싱 및 성능 분석을 지원합니다. proxy 옵션으로 프록시를 설정하고, .env와 dotenv로 환경 변수를 관리합니다. browser.newContext()를 활용해 세션을 격리하며, 트레이싱으로 성능 병목점을 분석할 수 있습니다.

Playwright 고급 사용법

커스텀 환경 구성

Proxy 설정

Playwright에서 프록시(proxy)를 설정하려면 browserType.launch 또는 browserType.launchPersistentContext 메서드의 proxy 옵션을 사용하면 됩니다. 이 옵션을 통해 Playwright가 사용하는 브라우저가 특정 프록시를 통해 요청을 처리하도록 설정할 수 있습니다.

아래는 프록시 설정의 주요 방법과 예제입니다.

1. 기본 Proxy 설정

Playwright에서 특정 프록시 서버를 사용하려면 proxy 옵션을 다음과 같이 설정합니다.

예제 코드

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": "http://proxy.server.com:8080",  # 프록시 주소
        "username": "your_username",              # (선택) 프록시 사용자 이름
        "password": "your_password"               # (선택) 프록시 비밀번호
    })
    context = browser.new_context()
    page = context.new_page()
    page.goto("http://example.com")
    print(page.title())
    browser.close()

2. 프록시 설정 옵션

proxy 옵션에 사용할 수 있는 키는 다음과 같습니다.

  • server: (필수) 프록시 서버 주소 (예: http://proxy.server.com:8080).
  • username: (선택) 프록시 인증을 위한 사용자 이름.
  • password: (선택) 프록시 인증을 위한 비밀번호.
  • bypass: (선택) 프록시를 우회할 도메인의 리스트. 예: "*.example.com,localhost".

3. Persistent Context와 Proxy

특정 사용자 데이터 디렉터리를 사용하면서 프록시를 설정하려면 launchPersistentContext를 사용합니다.

예제 코드

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    user_data_dir = "/path/to/your/user/data/dir"
    browser = p.chromium.launch_persistent_context(
        user_data_dir,
        proxy={
            "server": "http://proxy.server.com:8080",
            "username": "your_username",
            "password": "your_password"
        }
    )
    page = browser.new_page()
    page.goto("http://example.com")
    print(page.title())
    browser.close()

4. 환경 변수로 프록시 설정

프록시를 코드에 하드코딩하지 않고 환경 변수를 통해 설정하는 방법도 가능합니다. 이를 위해 os 모듈을 사용할 수 있습니다.

예제 코드

import os
from playwright.sync_api import sync_playwright

# 환경 변수에서 프록시 정보를 가져옴
proxy_server = os.getenv("PROXY_SERVER")  # 예: "http://proxy.server.com:8080"
proxy_username = os.getenv("PROXY_USERNAME")
proxy_password = os.getenv("PROXY_PASSWORD")

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": proxy_server,
        "username": proxy_username,
        "password": proxy_password
    })
    context = browser.new_context()
    page = context.new_page()
    page.goto("http://example.com")
    print(page.title())
    browser.close()

5. Proxy 테스트

프록시 설정이 올바르게 적용되었는지 확인하려면 IP를 확인할 수 있는 서비스를 통해 테스트해보세요.

예제 코드

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        "server": "http://proxy.server.com:8080",
        "username": "your_username",
        "password": "your_password"
    })
    context = browser.new_context()
    page = context.new_page()
    page.goto("https://api.ipify.org?format=json")  # 현재 IP 확인
    print(page.content())  # 프록시 IP 확인
    browser.close()

이와 같은 방식으로 Playwright에서 프록시를 설정하고 활용할 수 있습니다. 필요한 인증 정보와 환경에 따라 설정을 조정하면 됩니다.


환경변수 활용

Playwright에서 환경변수를 활용하는 방법을 TypeScript 예제 코드로 설명드리겠습니다. 환경변수를 사용하면 민감한 데이터(예: API 키, 프록시 설정 등)를 코드에 하드코딩하지 않고 외부에서 안전하게 관리할 수 있습니다.

1. 환경변수 사용을 위한 준비

(1) .env 파일 생성

Playwright 프로젝트의 루트 디렉터리에 .env 파일을 생성하고 환경변수를 정의합니다.

# .env
API_KEY=abcdef12345
PROXY_SERVER=http://proxy.server.com:8080
PROXY_USERNAME=my_username
PROXY_PASSWORD=my_password
(2) dotenv 설치

dotenv 라이브러리를 사용하여 환경변수를 로드합니다.

npm install dotenv

2. Playwright에서 환경변수 활용

(1) 환경변수 로드

dotenv를 활용하여 환경변수를 로드합니다. require('dotenv').config()를 사용하거나 ES 모듈 방식의 import를 활용할 수 있습니다.

예제 코드
import { test, expect } from '@playwright/test';
import * as dotenv from 'dotenv';

// .env 파일 로드
dotenv.config();

test('Test with environment variables', async ({ page }) => {
  // 환경변수에서 API 키 가져오기
  const apiKey = process.env.API_KEY;
  
  console.log('Loaded API Key:', apiKey);

  await page.goto('https://example.com');
  await expect(page).toHaveTitle('Example Domain');
});
(2) 프록시 설정

Playwright에서 브라우저를 실행할 때 프록시를 환경변수로 설정합니다.

예제 코드
import { chromium, Browser } from 'playwright';
import * as dotenv from 'dotenv';

// .env 파일 로드
dotenv.config();

(async () => {
  // 환경변수에서 프록시 설정 로드
  const proxyServer = process.env.PROXY_SERVER;
  const proxyUsername = process.env.PROXY_USERNAME;
  const proxyPassword = process.env.PROXY_PASSWORD;

  // 브라우저 실행 시 프록시 설정 적용
  const browser: Browser = await chromium.launch({
    proxy: {
      server: proxyServer || '', // 프록시 서버 주소
      username: proxyUsername,  // 프록시 사용자 이름
      password: proxyPassword,  // 프록시 비밀번호
    },
  });

  const context = await browser.newContext();
  const page = await context.newPage();

  await page.goto('https://api.ipify.org?format=json'); // 현재 IP 확인
  const content = await page.textContent('body');
  console.log('IP Address via Proxy:', content);

  await browser.close();
})();
(3) 환경에 따라 다른 설정 적용

다양한 환경(개발, 테스트, 운영)에서 각각 다른 .env 파일을 로드하여 설정을 분리할 수 있습니다. 예를 들어, 환경별 .env 파일 이름을 development.env, production.env 등으로 나눌 수 있습니다.

.env.development

API_KEY=dev_api_key

.env.production

API_KEY=prod_api_key
실행 코드
import { test, expect } from '@playwright/test';
import * as dotenv from 'dotenv';

// NODE_ENV 환경변수에 따라 다른 .env 파일 로드
const envFile = process.env.NODE_ENV === 'production' ? '.env.production' : '.env.development';
dotenv.config({ path: envFile });

test('Load API Key from environment', async ({ page }) => {
  const apiKey = process.env.API_KEY;
  console.log(`Loaded API Key for ${process.env.NODE_ENV}:`, apiKey);

  await page.goto('https://example.com');
  await expect(page).toHaveTitle('Example Domain');
});

3. 환경변수 활용 장점

  1. 보안성 강화: 민감한 정보를 코드에서 분리하여 외부에서 관리.
  2. 유연성: 환경(개발/테스트/운영)에 따라 다른 설정을 쉽게 적용.
  3. 코드 관리 용이: 설정 변경 시 코드 수정 없이 .env 파일만 업데이트.

4. 주의사항

  1. 민감한 정보는 안전한 방법으로 관리(예: CI/CD 시스템의 환경변수 기능 사용).

.env 파일은 절대로 버전 관리 시스템(Git)에 포함되지 않아야 합니다. .gitignore에 추가하세요.

.env

위 방법으로 Playwright와 TypeScript에서 환경변수를 활용할 수 있습니다.


다중 사용자 시뮬레이션

동시 로그인 테스트

동시 로그인 테스트는 웹 애플리케이션이 여러 사용자 계정을 동일한 시간에 처리할 때의 동작을 확인하는 중요한 테스트 중 하나입니다. 이 테스트를 통해 인증 시스템의 안정성, 세션 처리 능력, 데이터 무결성 등을 점검할 수 있습니다.

Playwright를 활용하여 동시 로그인 테스트를 구현하는 방법은 아래와 같습니다.

1. 동시 로그인 테스트 설계

주요 테스트 목표
  1. 여러 사용자가 동시에 로그인할 수 있는지 확인.
  2. 각 사용자 세션이 격리되어 데이터가 혼합되지 않는지 확인.
  3. 성능 및 안정성을 점검.

2. Playwright를 활용한 동시 로그인 테스트 코드 (TypeScript)

(1) 테스트 준비
  • 테스트용 사용자 계정이 필요합니다. 예: user1, user2, user3.
  • 테스트 URL(로그인 페이지 URL)을 준비합니다.
(2) 코드 예제
import { test, expect, chromium, Browser, Page } from '@playwright/test';

// 테스트에 사용할 사용자 계정 목록
const users = [
  { username: 'user1', password: 'password1' },
  { username: 'user2', password: 'password2' },
  { username: 'user3', password: 'password3' },
];

// 동시 로그인을 위한 Playwright 테스트
test('Simultaneous login test', async () => {
  const browser = await chromium.launch();
  
  // 모든 사용자에 대해 페이지를 생성하고 로그인
  const pages: Page[] = [];
  for (const user of users) {
    const context = await browser.newContext(); // 각 사용자에 대해 세션 분리
    const page = await context.newPage();
    await page.goto('https://example.com/login'); // 로그인 페이지로 이동

    // 로그인 폼 입력
    await page.fill('input[name="username"]', user.username);
    await page.fill('input[name="password"]', user.password);
    await page.click('button[type="submit"]'); // 로그인 버튼 클릭

    // 로그인 성공 확인 (예: 대시보드로 리다이렉트)
    await expect(page).toHaveURL('https://example.com/dashboard');
    console.log(`${user.username} logged in successfully.`);

    pages.push(page);
  }

  // 추가 검증: 세션 격리 확인 (예: 대시보드의 사용자 이름 확인)
  for (let i = 0; i < users.length; i++) {
    const user = users[i];
    const page = pages[i];
    
    // 사용자 이름 확인
    const usernameElement = await page.textContent('.username'); // 사용자 이름 표시 위치
    expect(usernameElement).toBe(user.username);
    console.log(`Session verified for ${user.username}.`);
  }

  // 브라우저 종료
  await browser.close();
});
(3) 동작 설명
  1. 여러 사용자 세션 생성: browser.newContext()를 사용하여 각 사용자를 독립된 세션에서 실행합니다.
  2. 로그인 처리: 각 사용자가 로그인하고 성공적으로 대시보드로 이동했는지 확인합니다.
  3. 세션 격리 테스트: 로그인된 사용자 정보(예: 대시보드에 표시된 사용자 이름)가 올바르게 각 계정에 따라 표시되는지 확인합니다.
  4. 결과 검증: Playwright의 expect를 사용하여 세션 데이터와 페이지 동작을 확인합니다.

3. 동시 테스트 병렬 실행

Playwright는 기본적으로 테스트를 병렬로 실행할 수 있습니다. 각 사용자를 개별 테스트 케이스로 만들어 병렬 실행하면 더 빠르게 동시성 테스트를 수행할 수 있습니다.

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

const users = [
  { username: 'user1', password: 'password1' },
  { username: 'user2', password: 'password2' },
  { username: 'user3', password: 'password3' },
];

users.forEach(user => {
  test(`Login test for ${user.username}`, async ({ page }) => {
    await page.goto('https://example.com/login');
    await page.fill('input[name="username"]', user.username);
    await page.fill('input[name="password"]', user.password);
    await page.click('button[type="submit"]');
    await expect(page).toHaveURL('https://example.com/dashboard');
    console.log(`${user.username} logged in successfully.`);
  });
});

4. 테스트 실행 방법

위 코드를 작성한 후 Playwright 테스트 스크립트를 실행합니다.

npx playwright test

병렬 실행을 위해 test.parallel 옵션을 활성화하거나, Playwright 설정 파일에서 병렬 실행을 지정할 수 있습니다.

5. 추가 검증

  • 세션 충돌 테스트: 각 사용자의 세션에서 다른 사용자 계정 정보가 보이지 않는지 확인합니다.
  • 부하 테스트: 동시 사용자의 수를 늘려 애플리케이션의 성능을 점검합니다.

6. 주의사항

  1. 테스트 계정 준비: 테스트용으로만 사용되는 계정을 미리 생성합니다.
  2. 데이터 정리: 테스트 후 세션 로그아웃 또는 데이터 초기화를 수행하여 깨끗한 환경을 유지합니다.
  3. 테스트 환경 분리: 실제 운영 환경이 아닌, 테스트 환경에서 실행합니다.

위 코드는 기본적인 동시 로그인 테스트를 구현한 예제입니다. 특정 요구사항에 따라 커스터마이징하거나 테스트 범위를 확장할 수도 있습니다.


Context API 활용

Playwright에서 Context API는 브라우저의 세션과 설정을 관리하는 데 중요한 역할을 합니다. 브라우저 컨텍스트(Context)는 쿠키, 세션 저장소, 브라우저 캐시 등을 독립적으로 유지할 수 있어 테스트 간 격리와 독립 실행이 가능합니다. 이 기능은 로그인 테스트, 멀티세션 시뮬레이션, 사용자 권한 테스트 등에 유용합니다.

1. Context란?

Playwright의 Context는 브라우저 인스턴스 내에서 독립된 브라우저 환경을 의미합니다.

  • 각 Context는 별도의 세션을 유지하며 쿠키, 캐시, 스토리지 등이 다른 Context와 분리됩니다.
  • 하나의 브라우저 인스턴스 내에서 여러 Context 생성 가능: 더 빠르고 효율적인 리소스 사용.
장점
  1. 테스트 간 세션 독립성 확보.
  2. 하나의 브라우저에서 여러 사용자 시뮬레이션.
  3. 멀티 탭 테스트 구현.

2. Context API 주요 사용법

(1) 기본 Context 생성

브라우저에서 Context를 생성한 후 페이지를 열어 작업합니다.

예제 코드
import { chromium, BrowserContext } from 'playwright';

(async () => {
  const browser = await chromium.launch();
  
  // 브라우저 컨텍스트 생성
  const context: BrowserContext = await browser.newContext();

  // 페이지 생성 및 작업
  const page = await context.newPage();
  await page.goto('https://example.com');
  console.log(await page.title());

  // 브라우저 종료
  await browser.close();
})();
(2) Context 간 세션 격리

여러 Context를 생성하여 각기 다른 사용자 세션을 시뮬레이션합니다.

예제 코드
import { chromium } from 'playwright';

(async () => {
  const browser = await chromium.launch();

  // 사용자 1 세션 생성
  const user1Context = await browser.newContext();
  const user1Page = await user1Context.newPage();
  await user1Page.goto('https://example.com/login');
  await user1Page.fill('input[name="username"]', 'user1');
  await user1Page.fill('input[name="password"]', 'password1');
  await user1Page.click('button[type="submit"]');
  console.log('User 1 logged in.');

  // 사용자 2 세션 생성
  const user2Context = await browser.newContext();
  const user2Page = await user2Context.newPage();
  await user2Page.goto('https://example.com/login');
  await user2Page.fill('input[name="username"]', 'user2');
  await user2Page.fill('input[name="password"]', 'password2');
  await user2Page.click('button[type="submit"]');
  console.log('User 2 logged in.');

  await browser.close();
})();
(3) Context 설정 옵션

browser.newContext()에서 다양한 옵션을 설정할 수 있습니다.

주요 옵션
  • viewport: 화면 크기 설정 (기본값: 1280x720).
  • userAgent: 사용자 에이전트 문자열 설정.
  • proxy: 프록시 설정.
  • storageState: 세션 초기화 데이터 제공.
  • acceptDownloads: 파일 다운로드 허용 여부 설정.
  • permissions: 브라우저 권한 설정(GPS, 카메라 등).
예제 코드
import { chromium } from 'playwright';

(async () => {
  const browser = await chromium.launch();

  // Context 설정
  const context = await browser.newContext({
    viewport: { width: 1920, height: 1080 }, // 화면 크기
    userAgent: 'CustomUserAgent/1.0',       // 사용자 에이전트
    acceptDownloads: true,                  // 파일 다운로드 허용
  });

  const page = await context.newPage();
  await page.goto('https://example.com');
  console.log(await page.title());

  await browser.close();
})();
(4) 저장된 세션(State) 활용

로그인 세션을 저장하고 재사용할 수 있습니다. 이 기능은 반복 테스트에서 매우 유용합니다.

1) 세션 저장
import { chromium } from 'playwright';

(async () => {
  const browser = await chromium.launch();
  const context = await browser.newContext();

  const page = await context.newPage();
  await page.goto('https://example.com/login');
  
  // 로그인 절차 수행
  await page.fill('input[name="username"]', 'user1');
  await page.fill('input[name="password"]', 'password1');
  await page.click('button[type="submit"]');
  
  // 세션 상태 저장
  await context.storageState({ path: 'state.json' });

  console.log('Session state saved.');
  await browser.close();
})();
2) 저장된 세션 불러오기
import { chromium } from 'playwright';

(async () => {
  const browser = await chromium.launch();
  
  // 저장된 세션 로드
  const context = await browser.newContext({ storageState: 'state.json' });

  const page = await context.newPage();
  await page.goto('https://example.com/dashboard'); // 로그인 상태 유지
  console.log(await page.title());

  await browser.close();
})();
(5) Context 내 멀티탭 구현

하나의 Context에서 여러 탭(Page)을 생성할 수 있습니다.

예제 코드
import { chromium } from 'playwright';

(async () => {
  const browser = await chromium.launch();
  const context = await browser.newContext();

  // 탭 1
  const page1 = await context.newPage();
  await page1.goto('https://example.com');
  console.log('Page 1 Title:', await page1.title());

  // 탭 2
  const page2 = await context.newPage();
  await page2.goto('https://example.com/about');
  console.log('Page 2 Title:', await page2.title());

  await browser.close();
})();

3. Context API 활용 사례

  1. 멀티 세션 시뮬레이션: 여러 사용자가 동시 작업하는 환경을 테스트.
  2. 로그인 상태 유지 테스트: storageState를 활용하여 로그인된 상태로 테스트.
  3. 권한 테스트: Context별로 브라우저 권한(예: 위치, 카메라)을 다르게 설정하여 테스트.
  4. 멀티탭 테스트: 동일 Context 내에서 여러 탭을 열어 동작 확인.

4. 주의사항

리소스 관리: 테스트 후 Context를 명시적으로 닫아 리소스를 해제하세요.

await context.close();

Context 재사용: 테스트를 격리하기 위해 필요한 경우 Context를 재사용하지 않도록 설계합니다.

Playwright의 Context API는 독립적인 세션, 상태 관리, 멀티탭 테스트 등 다양한 기능을 제공하여 복잡한 테스트 시나리오를 구현할 수 있게 합니다. 필요에 따라 Context를 적절히 설정하여 효율적인 테스트를 수행해 보세요.


트레이싱과 성능 분석

Trace Viewer 사용법

Playwright의 Trace Viewer는 테스트 실행 중에 발생한 모든 상호작용(클릭, 입력, 네트워크 요청 등)을 시각적으로 분석할 수 있도록 도와주는 강력한 도구입니다. 이를 통해 디버깅을 더 효율적으로 수행할 수 있습니다.

1. Trace Viewer란?

Trace Viewer는 Playwright가 테스트 실행 중 생성한 Trace 파일을 시각적으로 재생하고, 해당 테스트가 어떻게 동작했는지 단계별로 확인할 수 있는 툴입니다.

  • 각 단계에서의 DOM 상태, 네트워크 요청, 스크린샷 등을 확인 가능.
  • 실패한 테스트의 원인을 쉽게 분석.

2. Trace 파일 생성 방법

(1) Trace 파일 활성화

Playwright는 테스트 실행 중 Trace 파일을 생성하도록 설정할 수 있습니다.

Playwright Test 설정 (playwright.config.ts)

trace 옵션을 활성화하여 Trace 파일을 생성합니다.

import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    trace: 'on', // 'on', 'off', 'retain-on-failure' 중 선택
  },
});
  • on: 모든 테스트에서 Trace 파일 생성.
  • off: Trace 파일 비활성화.
  • retain-on-failure: 실패한 테스트에만 Trace 파일 생성.
(2) 코드 내에서 Trace 활성화

테스트 코드에서 특정 Context 또는 페이지에 대해 Trace 파일을 활성화할 수도 있습니다.

예제 코드
import { test } from '@playwright/test';

test('Test with Trace enabled', async ({ page }) => {
  // Trace 시작
  await page.context().tracing.start({ snapshots: true, screenshots: true });

  // 테스트 동작
  await page.goto('https://example.com');
  await page.click('text=More information...');
  await page.fill('input[name="search"]', 'Playwright');
  
  // Trace 저장
  await page.context().tracing.stop({ path: 'trace.zip' });
});

3. Trace Viewer 실행 방법

Trace 파일을 생성한 후, 이를 확인하려면 Playwright가 제공하는 Trace Viewer를 실행합니다.

(1) Trace Viewer 설치

Playwright를 설치하면 기본적으로 Trace Viewer가 포함됩니다. 별도 설치는 필요하지 않습니다.

(2) Trace Viewer 실행

Trace 파일(trace.zip)을 열려면 다음 명령어를 사용합니다.

npx playwright show-trace trace.zip
  • trace.zip: 테스트 실행 중 생성된 Trace 파일.

Trace Viewer가 실행되면 브라우저 창이 열리고, 테스트의 세부 정보를 탐색할 수 있습니다.

4. Trace Viewer 주요 기능

Trace Viewer는 아래와 같은 정보를 제공합니다.

(1) 타임라인
  • 테스트 실행 중 발생한 모든 이벤트(클릭, 입력, 네트워크 요청 등)를 타임라인 형태로 보여줍니다.
  • 각 이벤트를 선택하면 세부 정보를 확인할 수 있습니다.
(2) 스냅샷
  • 각 이벤트 발생 시점의 DOM 상태를 시각적으로 확인할 수 있습니다.
  • 페이지가 어떻게 렌더링되었는지 확인 가능.
(3) 네트워크
  • 테스트 중 발생한 모든 네트워크 요청/응답을 확인할 수 있습니다.
  • 요청 헤더, 응답 헤더, 상태 코드 등을 분석 가능.
(4) 콘솔 로그
  • 브라우저의 console.log() 메시지를 확인할 수 있습니다.
  • 테스트 실행 중 출력된 에러나 경고를 디버깅할 때 유용.
(5) Call Metadata
  • 각 이벤트의 호출 스택을 확인하여 코드의 실행 흐름을 추적할 수 있습니다.

5. 실전 예제

Trace 활성화 및 뷰어 사용

테스트 실행: trace: 'on' 또는 trace: 'retain-on-failure' 설정 후, Playwright 테스트를 실행합니다.

npx playwright test

Trace 파일 확인: 테스트가 완료되면 test-results 폴더에 Trace 파일이 생성됩니다.

npx playwright show-trace test-results/<테스트-이름>/trace.zip

6. Trace Viewer 활용 사례

(1) 실패한 테스트 디버깅
  • 실패한 테스트에서 trace.zip 파일을 열어, 문제가 발생한 시점과 원인을 분석.
(2) 네트워크 요청 확인
  • API 요청 및 응답 데이터를 확인하여 네트워크 레벨에서 발생한 문제를 진단.
(3) DOM 상태 분석
  • 특정 시점의 DOM 상태를 확인하여 렌더링 오류나 요소 선택 문제를 해결.

7. 주의사항

  1. Trace 파일 크기
    • Trace 파일은 테스트 실행 내용이 많을수록 크기가 커질 수 있습니다. trace: 'retain-on-failure' 설정으로 필요할 때만 저장하도록 조정하세요.
  2. 환경에 따라 경로 확인
    • 생성된 Trace 파일의 경로가 테스트 결과 디렉터리에 저장되므로 실행 환경에 따라 경로를 확인하세요.

Trace Viewer는 Playwright의 가장 강력한 디버깅 도구 중 하나로, 테스트 실패 원인을 정확히 파악하고 해결할 수 있도록 도와줍니다.


성능 병목점 파악

Playwright를 활용하여 성능 병목점을 파악하려면 Playwright가 제공하는 다양한 기능(트레이싱, 네트워크 요청/응답 분석, 페이지 성능 메트릭 수집 등)을 활용할 수 있습니다. Playwright는 성능 테스트 도구 자체는 아니지만, 병목 현상을 식별하기 위한 중요한 데이터를 수집하고 분석할 수 있습니다.

1. 성능 병목점 파악 주요 기능

(1) 트레이싱 (Tracing)
  • Playwright의 트레이싱 기능을 통해 테스트 실행 중 성능 문제를 시각적으로 분석할 수 있습니다.
  • DOM 스냅샷, 네트워크 요청, 이벤트 타임라인 등을 제공.
(2) 네트워크 요청/응답 분석
  • 페이지가 로드되는 동안 발생하는 모든 네트워크 요청을 캡처하여 요청 시간, 응답 크기, 실패 여부 등을 확인할 수 있습니다.
(3) 브라우저 퍼포먼스 메트릭 수집
  • Playwright는 브라우저에서 제공하는 성능 메트릭(PerformanceTiming)을 활용하여 페이지 로드 시간, DOMContentLoaded, 첫 번째 페인트(FP/FCP) 시간 등을 분석합니다.

2. Playwright로 성능 병목점 파악하기 (구체적 코드 예제)

(1) 트레이싱 활성화 및 분석

Playwright의 Tracing 기능을 통해 테스트 실행 중 발생한 작업을 기록하고 성능 병목점을 분석할 수 있습니다.

코드 예제
import { test } from '@playwright/test';

test('Performance tracing example', async ({ page }) => {
  // 트레이싱 시작
  await page.context().tracing.start({ snapshots: true, screenshots: true });

  // 페이지 작업 수행
  await page.goto('https://example.com');
  await page.click('text=More information');
  await page.fill('input[name="search"]', 'Playwright');
  await page.keyboard.press('Enter');

  // 트레이싱 저장
  await page.context().tracing.stop({ path: 'trace.zip' });
  console.log('Trace file saved as trace.zip');
});
분석 방법
  1. 테스트 실행 후 trace.zip 파일이 생성됩니다.
  2. 아래 명령어로 Trace Viewer를 실행
npx playwright show-trace trace.zip
  1. Trace Viewer를 통해 요청 타임라인, DOM 스냅샷, 네트워크 활동을 분석하여 병목 현상을 파악합니다.
(2) 네트워크 요청/응답 분석

페이지 로드 시 발생하는 네트워크 요청의 응답 시간을 확인하고, 병목을 초래하는 요청을 식별할 수 있습니다.

코드 예제
import { test } from '@playwright/test';

test('Network request monitoring', async ({ page }) => {
  // 네트워크 요청 캡처
  page.on('request', request => {
    console.log(`Request: ${request.method()} ${request.url()}`);
  });

  // 네트워크 응답 캡처
  page.on('response', response => {
    console.log(`Response: ${response.status()} ${response.url()}`);
  });

  // 페이지 로드
  await page.goto('https://example.com');
});
출력 예
Request: GET https://example.com
Response: 200 https://example.com
Request: GET https://example.com/script.js
Response: 200 https://example.com/script.js
분석 방법
  • 요청/응답 시간 기록을 분석하여 느린 요청이 있는지 확인합니다.
  • HTTP 상태 코드(예: 4xx, 5xx)를 기반으로 실패한 요청을 식별합니다.
(3) 브라우저 성능 메트릭 분석

Playwright는 브라우저의 성능 API(PerformanceTiming)를 사용하여 페이지 로드 시간을 측정할 수 있습니다.

코드 예제
import { test } from '@playwright/test';

test('Page load performance metrics', async ({ page }) => {
  await page.goto('https://example.com');

  // 성능 메트릭 가져오기
  const metrics = await page.evaluate(() => JSON.stringify(window.performance.timing));
  const timing = JSON.parse(metrics);

  console.log(`Navigation Start: ${timing.navigationStart}`);
  console.log(`Response Start: ${timing.responseStart}`);
  console.log(`DOM Complete: ${timing.domComplete}`);
  console.log(`Load Event End: ${timing.loadEventEnd}`);

  const pageLoadTime = timing.loadEventEnd - timing.navigationStart;
  console.log(`Total Page Load Time: ${pageLoadTime} ms`);
});
분석 방법
  • responseStartdomComplete 간의 시간 차이를 분석하여 페이지 로드의 병목 현상을 식별합니다.
  • 특정 메트릭(예: loadEventEnd)이 비정상적으로 높은 경우, 해당 단계에서 병목이 발생했는지 확인합니다.
(4) CPU/메모리 사용량 모니터링

페이지의 CPU 및 메모리 사용량을 측정하여 성능 병목을 식별할 수 있습니다.

코드 예제
import { test } from '@playwright/test';

test('Monitor CPU and memory usage', async ({ page }) => {
  await page.goto('https://example.com');

  // 성능 통계 가져오기
  const performanceStats = await page.evaluate(() => {
    return {
      memoryUsage: performance.memory,
      cpuUsage: window.navigator.hardwareConcurrency, // 사용 가능한 CPU 코어 수
    };
  });

  console.log(`Memory Usage: ${JSON.stringify(performanceStats.memoryUsage)}`);
  console.log(`CPU Cores Available: ${performanceStats.cpuUsage}`);
});
분석 방법
  • 메모리 사용량(performance.memory)이 급격히 증가하는지 확인하여 리소스 낭비를 식별합니다.
  • CPU 부하가 높은 작업(예: 대규모 DOM 조작)을 식별합니다.
(5) 사용자 경험 지표 (Core Web Vitals)

Playwright를 사용해 LCP(최대 콘텐츠 표시), FID(첫 번째 입력 지연), CLS(누적 레이아웃 이동) 등의 사용자 경험 지표를 수집할 수 있습니다.

코드 예제
import { test } from '@playwright/test';

test('Core Web Vitals metrics', async ({ page }) => {
  await page.goto('https://example.com');

  // Web Vitals 스크립트 로드
  await page.addScriptTag({ url: 'https://unpkg.com/web-vitals/dist/web-vitals.umd.js' });

  // Web Vitals 데이터 수집
  const metrics = await page.evaluate(() => {
    const { getLCP, getFID, getCLS } = window.webVitals;
    return new Promise(resolve => {
      getLCP(metric => console.log(`LCP: ${metric.value}`));
      getFID(metric => console.log(`FID: ${metric.value}`));
      getCLS(metric => console.log(`CLS: ${metric.value}`));
      resolve('Metrics collected');
    });
  });

  console.log(metrics);
});

3. Playwright를 활용한 성능 병목점 분석 워크플로우

  1. 트레이싱 활성화: 테스트 실행 후 Trace Viewer를 사용해 병목 구간을 시각적으로 분석.
  2. 네트워크 요청 분석: 느린 요청 또는 실패한 요청 식별.
  3. 성능 메트릭 수집: 페이지 로드 시간, 메모리/CPU 사용량 분석.
  4. 지표 비교: 성능 최적화 전후의 데이터를 비교하여 개선 여부 확인.

4. 도구와 Playwright의 조합

Playwright는 성능 병목점 분석 시 다른 도구와 함께 사용하면 더욱 효과적입니다.

  • Lighthouse: 웹 성능과 SEO 점수를 종합적으로 분석.
  • k6 또는 JMeter: 부하 테스트로 병목 지점을 확인한 후 Playwright로 디버깅.
  • Grafana/Prometheus: 성능 데이터를 시각화하여 장기적인 성능 문제 파악.

Playwright는 디버깅과 테스트 자동화를 위해 설계된 도구이지만, 성능 병목점을 파악하는 데에도 강력한 기능을 제공합니다.