Playwright의 확장 기능과 커스터마이징

Playwright에서 page.on()으로 클릭, 입력 등 브라우저 이벤트를 감지해 테스트 코드를 생성할 수 있으며, TypeScript로 안정성을 높일 수 있습니다. 플러그인으로 로그인 자동화 등 기능을 재사용하거나, Supertest와 통합해 API와 UI 데이터를 검증할 수 있습니다. 결과는 JSON, CSV, Markdown, HTML로 저장해 보고서를 생성할 수 있습니다.

Playwright의 확장 기능과 커스터마이징

커스텀 코드 생성기 작성

Playwright에서 커스텀 코드 생성기를 작성하려면 Playwright의 이벤트 핸들러와 스크립트 캡처 기능을 활용하여 브라우저에서 발생하는 이벤트를 기반으로 코드를 생성할 수 있습니다. 아래는 기본적인 커스텀 코드 생성기의 설계 및 구현 방안을 소개합니다.

1. 목표

  • 브라우저에서 사용자가 실행한 동작(클릭, 입력 등)을 기반으로 Playwright 테스트 코드를 자동으로 생성.
  • 사용자 정의 포맷으로 코드를 출력하거나 특정 작업을 자동화.

2. 구현 방법

2.1 Playwright 이벤트 기반 코드 생성

Playwright는 page.on() 메서드를 통해 다양한 이벤트(클릭, 네트워크 요청, 입력 등)를 캡처할 수 있습니다. 이를 활용하여 사용자의 행동을 추적하고, 이를 테스트 코드로 변환하는 로직을 작성합니다.

2.2 주요 이벤트 추적

다음은 자주 사용되는 이벤트와 그 처리 방식입니다.

  • click: 사용자가 특정 버튼이나 링크를 클릭했을 때.
  • type: 사용자가 입력 필드에 텍스트를 입력했을 때.
  • navigate: 사용자가 페이지를 이동했을 때.
  • network: API 호출, 리소스 로드 등을 추적.

3. 코드 예시

아래는 간단한 Playwright 커스텀 코드 생성기의 구현 예시입니다.

const fs = require('fs');
const { chromium } = require('playwright');

// Playwright 테스트 코드 생성기
(async () => {
  // 브라우저 및 페이지 생성
  const browser = await chromium.launch({ headless: false });
  const context = await browser.newContext();
  const page = await context.newPage();

  // 생성된 코드를 저장할 배열
  let recordedSteps = [];

  // 이벤트 리스너 설정
  page.on('click', async (event) => {
    const selector = await event.target.selector();
    recordedSteps.push(`await page.click('${selector}');`);
  });

  page.on('input', async (event) => {
    const value = event.target.value;
    const selector = await event.target.selector();
    recordedSteps.push(`await page.fill('${selector}', '${value}');`);
  });

  page.on('navigation', (request) => {
    recordedSteps.push(`await page.goto('${request.url()}');`);
  });

  // 사용자가 실행한 동작을 기반으로 코드 작성
  page.on('close', () => {
    const outputCode = `
      const { test } = require('@playwright/test');
      
      test('Generated Test', async ({ page }) => {
        ${recordedSteps.join('\n')}
      });
    `;

    // 생성된 코드를 파일로 저장
    fs.writeFileSync('generated-test.js', outputCode, 'utf-8');
    console.log('Generated test code saved to generated-test.js');
  });

  // URL로 이동
  await page.goto('https://example.com');

  // 테스트 환경을 위해 브라우저 유지
  await new Promise(resolve => setTimeout(resolve, 300000));
  await browser.close();
})();

4. 설명

  1. 이벤트 캡처
    • page.on('click'): 사용자가 클릭한 요소를 캡처하여 Playwright의 page.click() 코드로 변환.
    • page.on('input'): 입력한 텍스트를 추적하여 Playwright의 page.fill() 코드로 변환.
    • page.on('navigation'): 페이지 이동을 추적하여 page.goto() 코드로 변환.
  2. 코드 저장
    • 사용자가 실행한 동작을 기록한 배열(recordedSteps)에 동작을 추가.
    • 페이지가 닫히는 시점에 전체 동작을 테스트 코드로 변환하여 파일로 저장.
  3. 파일 저장
    • 생성된 코드를 generated-test.js 파일에 저장하여 나중에 실행 가능.

5. 확장 가능성

  • 다양한 이벤트 추가
    • page.on('dialog'): 경고창, 확인창 등의 동작 기록.
    • page.on('response'): 네트워크 응답 추적.
  • UI 강화
    • GUI 기반으로 이벤트를 실시간으로 시각화.
  • 코드 포맷 옵션 추가
    • 예: TypeScript, 특정 프레임워크(예: Jest) 코드 스타일.

위 코드는 기본적인 커스텀 코드 생성기의 시작점으로, 필요한 기능에 따라 확장할 수 있습니다.


아래는 Playwright 커스텀 코드 생성기를 TypeScript로 작성한 예시 코드입니다. TypeScript의 타입 시스템을 활용하여 더 안전한 코드를 작성할 수 있도록 구성했습니다.

import { chromium, Page } from 'playwright';
import * as fs from 'fs';

// Playwright 테스트 코드 생성기
(async () => {
  // 브라우저 및 페이지 생성
  const browser = await chromium.launch({ headless: false });
  const context = await browser.newContext();
  const page = await context.newPage();

  // 생성된 코드를 저장할 배열
  const recordedSteps: string[] = [];

  // 유틸리티 함수: CSS 셀렉터 가져오기
  const getSelector = async (page: Page, elementHandle: any): Promise<string> => {
    const selector = await page.evaluate((el) => {
      const path: string[] = [];
      while (el && el.nodeType === Node.ELEMENT_NODE) {
        let selector = el.nodeName.toLowerCase();
        if (el.id) {
          selector += `#${el.id}`;
        } else if (el.className) {
          selector += `.${el.className.split(' ').join('.')}`;
        }
        path.unshift(selector);
        el = el.parentElement;
      }
      return path.join(' > ');
    }, elementHandle);
    return selector;
  };

  // 이벤트 리스너 설정
  page.on('click', async (event) => {
    const elementHandle = event.target();
    if (elementHandle) {
      const selector = await getSelector(page, elementHandle);
      recordedSteps.push(`await page.click('${selector}');`);
    }
  });

  page.on('input', async (event) => {
    const elementHandle = event.target();
    if (elementHandle) {
      const selector = await getSelector(page, elementHandle);
      const value = await page.evaluate((el) => (el as HTMLInputElement).value, elementHandle);
      recordedSteps.push(`await page.fill('${selector}', '${value}');`);
    }
  });

  page.on('framenavigated', (frame) => {
    if (frame.url() !== 'about:blank') {
      recordedSteps.push(`await page.goto('${frame.url()}');`);
    }
  });

  // 페이지 닫힐 때 생성된 코드를 저장
  page.on('close', () => {
    const outputCode = `
      import { test, expect } from '@playwright/test';

      test('Generated Test', async ({ page }) => {
        ${recordedSteps.join('\n        ')}
      });
    `;

    // 파일로 저장
    fs.writeFileSync('generated-test.ts', outputCode, 'utf-8');
    console.log('Generated test code saved to generated-test.ts');
  });

  // URL로 이동
  await page.goto('https://example.com');

  // 테스트 환경을 위해 브라우저 유지
  console.log('Recording actions... Perform your actions in the browser.');
  await new Promise((resolve) => setTimeout(resolve, 300000)); // 5분 대기
  await browser.close();
})();

주요 변경점 및 설명

  1. TypeScript 사용
    • import 구문으로 TypeScript 모듈 가져오기.
    • Pagechromium 등 Playwright에서 제공하는 타입 명시.
    • 이벤트 핸들러나 함수에 적절한 타입 추가(Page, string, any 등).
  2. 유틸리티 함수
    • getSelector: 선택자를 계산하여 CSS 셀렉터를 정확히 가져오는 함수. DOM 트리를 거슬러 올라가며 고유 셀렉터를 생성.
  3. 코드 저장
    • 기록된 테스트 코드가 TypeScript 형식으로 출력되며, @playwright/test 기반의 테스트 구조를 포함.
  4. 기본 이벤트 처리
    • Click 이벤트: page.click() 코드로 변환.
    • Input 이벤트: 입력 필드의 값을 추적하여 page.fill() 코드로 변환.
    • Navigation 이벤트: page.goto() 코드로 변환.
  5. 타임아웃 설정
    • 브라우저를 5분 동안 유지(setTimeout)하며 사용자가 필요한 동작을 수행할 수 있도록 구성.
  6. 파일 저장 경로
    • 생성된 코드는 generated-test.ts라는 이름으로 저장됩니다.

확장 포인트

  • 다양한 이벤트 추가
    • 네트워크 요청(page.on('request'), page.on('response')) 추적.
    • 팝업 및 다이얼로그(page.on('dialog')) 처리.
  • GUI 시각화 추가
    • 이벤트를 실시간으로 화면에 보여주는 UI 추가.
  • 코드 포맷 옵션
    • ESLint나 Prettier를 활용해 출력되는 코드를 포맷팅.

위 코드는 Playwright와 TypeScript를 사용하는 프로젝트에 바로 통합할 수 있습니다.


플러그인 활용하기

Playwright에서 플러그인을 활용하면 코드 재사용성을 높이고 기능을 확장할 수 있습니다. 특히, Playwright Test Fixtures, Custom Plugins, 그리고 Third-party Plugin을 활용하면 테스트 자동화가 더욱 효율적이 됩니다.

1. Playwright 플러그인을 활용하는 이유

  • 공통 기능(로그인, API 요청, 성능 측정 등)의 재사용성 증가
  • 코드 유지보수 및 가독성 향상
  • 테스트 실행 시 로깅(logging), 트레이싱(tracing), 리포팅(reporting) 등의 기능 추가 가능
  • 커스텀 Playwright 플러그인을 만들어 특정 기능을 확장 가능

2. 기본적인 Playwright 플러그인 활용 방법

Playwright는 기본적으로 test fixtures 기능을 제공하며, 이를 활용하여 플러그인을 구현할 수 있습니다.

(1) Playwright Test Fixtures를 이용한 플러그인

Playwright에서 제공하는 test.extend()를 활용하면 테스트 환경을 확장할 수 있습니다.

📌 예제: 사용자 로그인 플러그인

아래는 자동 로그인을 수행하는 Playwright 플러그인을 만드는 예제입니다.

import { test as base } from '@playwright/test';

// 사용자 로그인 플러그인 정의
export const test = base.extend<{ login: () => Promise<void> }>({
  login: async ({ page }, use) => {
    await page.goto('https://example.com/login');
    await page.fill('#username', 'testuser');
    await page.fill('#password', 'password123');
    await page.click('button[type="submit"]');
    await page.waitForNavigation();
    await use();
  },
});

테스트에서 활용

위에서 정의한 플러그인을 활용하여 로그인한 후 다른 작업을 수행할 수 있습니다.

import { test, expect } from './my-plugin';

test('로그인이 필요한 페이지 테스트', async ({ page, login }) => {
  await login(); // 로그인 플러그인 실행
  await page.goto('https://example.com/dashboard');
  const welcomeMessage = await page.locator('.welcome').textContent();
  expect(welcomeMessage).toContain('Welcome, testuser');
});

장점

  • 매 테스트마다 로그인 과정을 반복할 필요 없이 login()을 호출하여 간단하게 로그인 가능
  • test.extend()여러 개의 플러그인을 조합하여 활용 가능

3. 커스텀 Playwright 플러그인 만들기

Playwright는 확장성을 고려하여 사용자 정의 플러그인을 지원합니다. 이를 활용하면 Playwright의 기능을 확장할 수 있습니다.

(1) 페이지 내 요소를 추적하는 플러그인

아래 플러그인은 사용자가 상호작용한 요소를 기록하여 코드로 변환하는 기능을 제공합니다.

import { Page } from 'playwright';

export class ActionRecorder {
  private steps: string[] = [];

  constructor(private page: Page) {}

  async startRecording() {
    this.page.on('click', async (event) => {
      const selector = await event.target().evaluate((el) => el.outerHTML);
      this.steps.push(`await page.click('${selector}');`);
    });

    this.page.on('input', async (event) => {
      const selector = await event.target().evaluate((el) => el.outerHTML);
      const value = await event.target().evaluate((el) => (el as HTMLInputElement).value);
      this.steps.push(`await page.fill('${selector}', '${value}');`);
    });

    console.log('Recording started...');
  }

  stopRecording() {
    console.log('Recorded steps:');
    console.log(this.steps.join('\n'));
  }
}

(2) 사용법

import { chromium } from 'playwright';
import { ActionRecorder } from './action-recorder';

(async () => {
  const browser = await chromium.launch({ headless: false });
  const context = await browser.newContext();
  const page = await context.newPage();

  const recorder = new ActionRecorder(page);
  await recorder.startRecording();

  await page.goto('https://example.com');
  await page.waitForTimeout(5000); // 사용자 입력 대기

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

기능

  • 사용자의 클릭 및 입력 기록
  • stopRecording()을 호출하면 기록된 테스트 코드 자동 출력
  • Playwright의 기본 기능을 확장하여 반복적인 테스트 코드 작성 자동화

4. 서드파티(Third-Party) Playwright 플러그인 활용

Playwright는 공식적으로 여러 플러그인을 지원하며, 아래와 같은 기능을 추가할 수 있습니다.

(1) Playwright 공식 플러그인

  • @playwright/test: 기본 테스트 프레임워크
  • playwright-aws-lambda: AWS Lambda 환경에서 Playwright 실행
  • @playwright/experimental-ct-react: React 컴포넌트 테스트 지원

(2) 서드파티 플러그인

  • playwright-video: Playwright 테스트 실행을 동영상으로 저장
  • playwright-trace-viewer: Playwright 트레이스를 GUI로 확인

📌 예제: Playwright 동영상 녹화 플러그인 활용

Playwright 테스트를 실행하는 동안 동영상을 녹화할 수 있습니다.

import { test as base } from '@playwright/test';

export const test = base.extend({
  context: async ({ browser }, use) => {
    const context = await browser.newContext({
      recordVideo: { dir: 'videos/' },
    });
    await use(context);
    await context.close();
  },
});

test('녹화 테스트', async ({ page }) => {
  await page.goto('https://example.com');
  await page.waitForTimeout(5000); // 5초 대기 (녹화 확인용)
});

장점

  • 테스트 실행 과정을 동영상으로 저장하여 디버깅에 활용 가능
  • videos/ 폴더에 테스트 실행 동영상이 자동 저장됨
  • Playwright Test Fixtures를 사용하여 로그인, API 호출 등의 반복적인 기능을 플러그인화할 수 있음.
  • 커스텀 플러그인을 제작하여 사용자 이벤트 추적, 자동 코드 생성 등의 기능을 확장 가능.
  • 서드파티 플러그인을 활용하여 동영상 녹화, 트레이스 뷰어, 클라우드 환경 실행 등의 기능 추가 가능.

📌 Playwright 플러그인은 테스트 자동화를 더욱 강력하게 만들어주며, 확장성이 뛰어납니다. 필요에 따라 맞춤형 플러그인을 제작하거나 기존 플러그인을 활용하면 효율적인 테스트 환경을 구축할 수 있습니다.


Playwright와 외부 라이브러리 통합

Playwright와 외부 라이브러리를 통합하면 테스트 자동화의 기능을 확장하고, 데이터 처리, API 호출, 데이터베이스 연동, 보고서 생성 등 다양한 기능을 추가할 수 있습니다.

1. Playwright와 외부 라이브러리 통합이 필요한 경우

테스트 데이터 관리: Faker.js, Chance.js를 사용하여 무작위 데이터 생성
API 테스트: Axios, Supertest를 사용하여 API 요청 및 응답 검증
데이터베이스 연동: MySQL, PostgreSQL, MongoDB 등의 DB에서 데이터를 가져와 테스트
보고서 생성: Allure, HTML Report를 사용하여 테스트 리포트 생성
파일 처리: fs (파일 시스템), ExcelJS를 사용하여 데이터 입출력

2. Playwright + API 요청 (Axios, Supertest)

Playwright 테스트 중 API를 호출하여 데이터를 확인하거나, UI 테스트 전에 데이터를 미리 설정할 수 있습니다.

(1) Axios와 Playwright 연동

📌 Axios를 활용하여 API 요청을 보내고, 응답을 검증하는 예제

import { test, expect } from '@playwright/test';
import axios from 'axios';

test('API 응답을 검증한 후 UI 테스트', async ({ page }) => {
  const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
  expect(response.status).toBe(200);
  expect(response.data).toHaveProperty('title');

  await page.goto('https://example.com');
  await expect(page.locator('h1')).toHaveText(response.data.title);
});

API 데이터와 UI 데이터가 일치하는지 확인 가능
Playwright 실행 중 API 요청을 직접 호출하여 API 응답을 UI와 비교 가능

(2) Supertest와 Playwright 연동

📌 Supertest를 활용하여 API 테스트를 Playwright에 통합하는 예제

import { test, expect } from '@playwright/test';
import request from 'supertest';

test('Supertest를 활용한 API 검증', async ({ page }) => {
  const api = request('https://jsonplaceholder.typicode.com');
  const response = await api.get('/posts/1');

  expect(response.status).toBe(200);
  expect(response.body.title).toBeDefined();
});

Supertest는 API 테스트에 특화된 라이브러리로, REST API를 쉽게 호출하고 검증 가능

3. Playwright + 무작위 데이터 생성 (Faker.js)

UI 입력 필드 테스트 시 동적 데이터를 사용해야 할 때가 많습니다. Faker.js를 활용하면 가짜 이름, 이메일, 주소 등을 생성하여 테스트할 수 있습니다.

(1) Faker.js로 가짜 데이터 생성

📌 Faker.js를 사용하여 무작위 사용자 데이터를 생성하여 폼을 자동 입력하는 예제

import { test, expect } from '@playwright/test';
import { faker } from '@faker-js/faker';

test('무작위 사용자 데이터 입력', async ({ page }) => {
  const name = faker.name.fullName();
  const email = faker.internet.email();
  const password = faker.internet.password();

  await page.goto('https://example.com/signup');
  await page.fill('#name', name);
  await page.fill('#email', email);
  await page.fill('#password', password);
  await page.click('button[type="submit"]');

  expect(await page.locator('.welcome-message').textContent()).toContain(name);
});

매번 새로운 테스트 데이터를 생성하여 폼 입력 테스트 수행 가능
실제 사용자의 데이터를 입력하는 것처럼 테스트 가능

4. Playwright + 데이터베이스 연동 (MySQL, PostgreSQL, MongoDB)

테스트 실행 전후로 데이터베이스에서 데이터를 삽입하거나 검증해야 하는 경우 Playwright와 DB 라이브러리를 통합할 수 있습니다.

(1) MySQL 연동

📌 MySQL에서 데이터를 조회한 후, Playwright UI 테스트에서 검증하는 예제

import { test, expect } from '@playwright/test';
import mysql from 'mysql2/promise';

test('MySQL 데이터를 기반으로 UI 테스트', async ({ page }) => {
  const connection = await mysql.createConnection({
    host: 'localhost',
    user: 'root',
    password: 'password',
    database: 'testdb',
  });

  const [rows] = await connection.execute('SELECT name FROM users WHERE id = ?', [1]);
  const userName = rows[0]?.name;

  await page.goto('https://example.com/user-profile');
  expect(await page.locator('.user-name').textContent()).toContain(userName);

  await connection.end();
});

DB에서 가져온 데이터를 Playwright 테스트에 활용 가능
UI에 표시된 데이터가 실제 DB와 일치하는지 검증 가능

5. Playwright + 테스트 보고서 생성 (Allure, HTML Report)

Playwright에서 실행된 테스트 결과를 시각적으로 확인할 수 있도록 보고서를 생성할 수 있습니다.

(1) Playwright 기본 HTML Report

Playwright는 기본적으로 --reporter=html 옵션을 제공하여 HTML 형태의 리포트를 생성할 수 있습니다.

npx playwright test --reporter=html

playwright-report/index.html에서 상세 리포트 확인 가능

(2) Allure Report 연동

📌 Allure를 Playwright에 추가하여 더욱 상세한 보고서를 생성

npm install --save-dev allure-playwright

📌 Playwright 설정 파일(playwright.config.ts) 수정

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

export default defineConfig({
  reporter: [
    ['list'],
    ['allure-playwright'],
  ],
});

📌 테스트 실행 후 Allure 리포트 생성

npx playwright test
npx allure generate allure-results --clean
npx allure open

테스트 실행 기록, 오류 로그, 스크린샷 등을 시각적으로 확인 가능

6. Playwright + 파일 처리 (fs, ExcelJS)

UI 테스트 중에 파일을 읽거나 다운로드한 파일을 검증해야 할 때 파일 시스템(fs)ExcelJS를 사용할 수 있습니다.

(1) 파일 다운로드 후 검증

📌 Playwright에서 파일을 다운로드한 후 해당 파일이 존재하는지 확인

import { test, expect } from '@playwright/test';
import * as fs from 'fs';

test('파일 다운로드 후 존재 여부 확인', async ({ page }) => {
  await page.goto('https://example.com/download');
  
  const [download] = await Promise.all([
    page.waitForEvent('download'),
    page.click('a#download-link'),
  ]);

  const filePath = await download.path();
  expect(fs.existsSync(filePath!)).toBe(true);
});

Playwright에서 파일 다운로드 후 실제로 존재하는지 검증 가능

(2) ExcelJS를 활용한 데이터 검증

📌 Excel 데이터를 읽고 UI에 표시된 값과 비교

import { test, expect } from '@playwright/test';
import * as ExcelJS from 'exceljs';

test('Excel 데이터를 읽고 UI 검증', async ({ page }) => {
  const workbook = new ExcelJS.Workbook();
  await workbook.xlsx.readFile('test-data.xlsx');
  const worksheet = workbook.getWorksheet(1);
  const cellValue = worksheet.getCell('A1').value as string;

  await page.goto('https://example.com');
  expect(await page.locator('.data-field').textContent()).toBe(cellValue);
});

Excel 데이터와 UI 데이터를 비교하여 정확성 검증 가능

  • Playwright와 외부 라이브러리를 결합하여 API, 데이터베이스, 보고서, 파일 처리 등 다양한 기능을 추가할 수 있습니다.
  • 테스트 데이터 자동 생성(Faker.js), API 연동(Axios, Supertest), DB 조회(MySQL, PostgreSQL), 보고서 생성(Allure) 등의 기능을 쉽게 통합 가능.
  • 이러한 기술들을 조합하면 더욱 강력한 E2E 테스트 환경을 구축할 수 있습니다. 🎯🚀

Supertest와 Playwright 연동 상세 설명

1. Supertest란?

SupertestNode.js 기반의 HTTP 요청 테스트 라이브러리로, REST API의 응답을 검증하는 데 사용됩니다.
Playwright와 함께 사용하면 UI 테스트 실행 중 API 요청을 수행하고 API 데이터와 UI 데이터를 비교할 수 있습니다.

주요 기능

  • HTTP 요청 (GET, POST, PUT, DELETE) 테스트
  • REST API 응답 데이터 검증 (status, header, body 등)
  • API의 상태 코드 및 응답 값을 UI 요소와 비교 가능
  • Playwright와 결합하여 API 백엔드와 프론트엔드가 동기화되었는지 검증 가능

2. Supertest 설치

Playwright 프로젝트에서 Supertest를 사용하려면 먼저 설치해야 합니다.

npm install --save-dev supertest @playwright/test

이제 SupertestPlaywright를 함께 사용할 수 있습니다.

3. Supertest와 Playwright를 함께 사용한 예제

📌 시나리오

  1. API를 호출하여 특정 사용자 데이터를 가져온다.
  2. Playwright를 사용해 UI에 표시된 데이터가 API 응답과 동일한지 확인한다.

📌 API 예제 (https://jsonplaceholder.typicode.com/posts/1)

{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit..."
}

📌 Supertest + Playwright 코드 예제

import { test, expect } from '@playwright/test';
import request from 'supertest';

const API_URL = 'https://jsonplaceholder.typicode.com';

test('API 데이터와 UI 데이터 비교', async ({ page }) => {
  // 1️⃣ API 요청을 수행하여 응답 데이터를 가져옴
  const response = await request(API_URL).get('/posts/1');
  expect(response.status).toBe(200); // 상태 코드 검증

  const apiData = response.body;
  expect(apiData).toHaveProperty('title'); // title 필드 확인

  // 2️⃣ 웹 페이지 이동
  await page.goto('https://example.com');

  // 3️⃣ API 데이터와 UI 데이터 비교
  const uiTitle = await page.locator('.post-title').textContent();
  expect(uiTitle).toContain(apiData.title); // UI의 제목이 API 응답과 일치하는지 확인
});

설명

  1. Supertest를 사용해 GET 요청을 보냄
    • request(API_URL).get('/posts/1')를 호출하여 API 데이터를 가져옴.
    • API 응답 상태 코드가 200인지 검증.
    • title 필드가 존재하는지 확인.
  2. Playwright를 사용해 UI에서 데이터 확인
    • 웹 페이지 (https://example.com)에 이동.
    • .post-title 요소의 텍스트를 가져옴.
    • UI의 title이 API 응답의 title과 일치하는지 검증.

4. API를 통한 UI 사전 데이터 설정

실제 UI 테스트에서는 특정 데이터를 미리 생성해야 할 수도 있습니다.
Supertest를 활용하면 API를 호출하여 테스트 데이터를 미리 생성한 후 UI 테스트를 진행할 수 있습니다.

📌 API 호출을 통해 UI 테스트 전 데이터를 준비하는 예제

import { test, expect } from '@playwright/test';
import request from 'supertest';

const API_URL = 'https://jsonplaceholder.typicode.com';

test('API를 통해 데이터를 생성한 후 UI에서 확인', async ({ page }) => {
  // 1️⃣ API 요청을 통해 새로운 데이터를 생성
  const createResponse = await request(API_URL)
    .post('/posts')
    .send({
      title: '테스트 제목',
      body: '테스트 본문',
      userId: 1,
    });

  expect(createResponse.status).toBe(201); // POST 요청 성공 검증
  const createdPost = createResponse.body;
  expect(createdPost).toHaveProperty('id');

  // 2️⃣ UI에서 생성된 데이터 확인
  await page.goto(`https://example.com/posts/${createdPost.id}`);
  const uiTitle = await page.locator('.post-title').textContent();
  expect(uiTitle).toContain('테스트 제목'); // UI의 제목이 API에서 생성한 데이터와 일치하는지 확인
});

설명

  1. Supertest를 사용해 POST /posts 요청을 보내서 새로운 데이터를 생성.
  2. 생성된 데이터의 id를 이용해 Playwright에서 해당 페이지로 이동.
  3. UI에서 표시된 제목이 API를 통해 생성한 데이터와 일치하는지 확인.

5. Playwright API Request와 Supertest 비교

Playwright 자체적으로 API 테스트 기능을 제공하는 request 객체가 있습니다.
하지만 Supertest는 더 많은 HTTP 요청 옵션을 제공하며, 기존 API 테스트 코드와의 호환성이 높습니다.

기능 Supertest (request()) Playwright API Request (context.request())
HTTP 요청 지원 GET, POST, PUT, DELETE, PATCH, HEAD 등 지원 fetch와 유사한 API
요청 체이닝 가능 .set(), .query(), .send() 등 메서드 체이닝 가능 ❌ 직접 요청을 수행해야 함
상태 코드 확인 .expect(200)로 상태 코드 검증 .ok()status() 사용 가능
JSON 자동 파싱 ✅ 응답을 자동으로 JSON 변환 .json() 메서드 사용
쿠키/세션 관리 .set('Cookie', 'session=12345') 가능 ✅ Playwright의 storageState 활용 가능
Playwright 통합 ✅ API 호출 후 UI 테스트 가능 ✅ Playwright 네이티브 기능 사용

📌 언제 Supertest를 사용해야 할까?

  • 기존 API 테스트 코드(Supertest 사용)가 많을 때 Playwright UI 테스트와 함께 사용
  • .set(), .query() 같은 메서드를 활용한 복잡한 API 요청이 필요한 경우
  • Playwright API request보다 더 많은 기능이 필요한 경우

📌 Playwright API Request를 사용해야 할 때

  • Playwright의 내장 API 요청 기능을 사용하여 API와 UI 테스트를 한 곳에서 관리할 때
  • API 테스트가 많지 않고 단순한 요청만 필요할 때

  • Supertest를 Playwright와 함께 사용하면 API 백엔드와 UI 데이터를 동기화하여 검증 가능
  • API에서 가져온 데이터를 UI에서 제대로 렌더링했는지 검증 가능
  • API를 이용한 사전 데이터 설정 (POST 요청 후 UI 확인) 가능
  • Playwright의 request 기능도 있지만, Supertest는 더 다양한 요청 옵션과 API 테스트 기능 제공
  • API와 UI가 함께 동작하는 E2E 테스트 시나리오에서 매우 유용함 🚀

📌 Supertest와 Playwright을 결합하면 강력한 API + UI 테스트를 구축할 수 있습니다!


사용자 지정 보고서 생성

Playwright에서 기본적으로 제공하는 HTML Report, Allure Report 외에도 사용자 지정 보고서(Custom Report) 를 생성할 수 있습니다.
테스트 데이터를 원하는 형식(JSON, CSV, Markdown 등)으로 저장하고, 이를 기반으로 맞춤형 보고서를 만들 수 있습니다.

1. 사용자 지정 보고서를 만드는 방법

Playwright는 Event Listener를 활용하여 테스트 실행 결과를 추적할 수 있습니다. 이를 기반으로 다음과 같은 방식으로 맞춤 보고서를 생성할 수 있습니다.

파일 형식에 따른 맞춤 보고서

  • JSON 파일 → 분석 도구에서 활용 가능
  • CSV 파일 → Excel에서 결과 정리
  • Markdown 파일 → 간단한 문서화 보고서 생성
  • HTML 파일 → 웹 기반 보고서 UI 제공

보고서 생성 방식

  • Playwright의 Reporter API를 사용하여 자동화된 맞춤 보고서 생성
  • fs 모듈을 사용하여 JSON, Markdown, CSV 파일로 저장
  • playwright.config.ts에 사용자 정의 리포터 설정

2. JSON 기반 사용자 지정 보고서 생성

Playwright의 이벤트 리스너를 활용하여 테스트 실행 중 데이터를 JSON 파일에 저장할 수 있습니다.

📌 1) JSON 파일로 테스트 결과 저장

import { test, expect } from '@playwright/test';
import * as fs from 'fs';

// JSON 결과 저장을 위한 배열
const testResults: any[] = [];

test.afterEach(async ({ title }, testInfo) => {
  testResults.push({
    title: title, // 테스트 제목
    status: testInfo.status, // 'passed' | 'failed' | 'skipped'
    duration: testInfo.duration, // 실행 시간(ms)
  });

  fs.writeFileSync('test-results.json', JSON.stringify(testResults, null, 2), 'utf-8');
});

test('Example test 1', async ({ page }) => {
  await page.goto('https://example.com');
  expect(await page.title()).toBe('Example Domain');
});

test('Example test 2', async ({ page }) => {
  await page.goto('https://example.com');
  expect(await page.title()).toBe('Wrong Title'); // 실패하는 테스트
});

기능 설명

  • test.afterEach()를 사용하여 각 테스트가 실행될 때마다 JSON 파일에 저장
  • testInfo 객체에서 테스트 상태, 실행 시간 등을 가져와 JSON으로 저장
  • fs.writeFileSync()를 사용하여 결과를 test-results.json 파일로 생성

3. CSV 형식 사용자 지정 보고서 생성

📌 CSV 파일을 생성하여 Excel 등에서 확인 가능

import { test } from '@playwright/test';
import * as fs from 'fs';

// CSV 저장을 위한 문자열 초기화
let csvReport = 'Test Name,Status,Duration (ms)\n';

test.afterEach(async ({ title }, testInfo) => {
  csvReport += `${title},${testInfo.status},${testInfo.duration}\n`;

  fs.writeFileSync('test-results.csv', csvReport, 'utf-8');
});

test('Test A', async ({ page }) => {
  await page.goto('https://example.com');
});

test('Test B', async ({ page }) => {
  await page.goto('https://example.com');
  throw new Error('Intentional Failure'); // 실패하는 테스트
});

기능 설명

  • CSV 파일을 생성하여 test-results.csv 파일에 저장
  • test.afterEach()fs.writeFileSync()를 사용해 CSV 형식으로 결과 저장
  • 결과 파일을 Excel에서 쉽게 열어볼 수 있음

4. Markdown 기반 보고서 생성

📌 Markdown 형식의 보고서를 생성하여 GitHub에서 쉽게 확인 가능

import { test } from '@playwright/test';
import * as fs from 'fs';

// Markdown 초기화
let markdownReport = `# Playwright Test Report\n\n| Test Name | Status | Duration (ms) |\n|---|---|---|\n`;

test.afterEach(async ({ title }, testInfo) => {
  markdownReport += `| ${title} | ${testInfo.status} | ${testInfo.duration} |\n`;

  fs.writeFileSync('test-results.md', markdownReport, 'utf-8');
});

test('Markdown Test 1', async ({ page }) => {
  await page.goto('https://example.com');
});

test('Markdown Test 2', async ({ page }) => {
  await page.goto('https://example.com');
  throw new Error('Test Failure'); // 실패하는 테스트
});

기능 설명

  • Markdown 형식의 보고서를 생성 (test-results.md)
  • GitHub의 Markdown Viewer에서 쉽게 확인 가능
  • 테이블 형식으로 정리하여 가독성 향상

5. HTML 기반 사용자 지정 보고서 생성

📌 HTML 파일로 저장하여 브라우저에서 테스트 결과를 시각적으로 확인 가능

import { test } from '@playwright/test';
import * as fs from 'fs';

let htmlReport = `
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Playwright Test Report</title>
  <style>
    table { width: 100%; border-collapse: collapse; }
    th, td { border: 1px solid black; padding: 8px; text-align: left; }
    th { background-color: #f4f4f4; }
  </style>
</head>
<body>
  <h1>Playwright Test Report</h1>
  <table>
    <tr>
      <th>Test Name</th>
      <th>Status</th>
      <th>Duration (ms)</th>
    </tr>
`;

test.afterEach(async ({ title }, testInfo) => {
  htmlReport += `
    <tr>
      <td>${title}</td>
      <td>${testInfo.status}</td>
      <td>${testInfo.duration}</td>
    </tr>
  `;

  fs.writeFileSync('test-results.html', htmlReport + '</table></body></html>', 'utf-8');
});

test('HTML Report Test 1', async ({ page }) => {
  await page.goto('https://example.com');
});

test('HTML Report Test 2', async ({ page }) => {
  await page.goto('https://example.com');
  throw new Error('Test Failure');
});

기능 설명

  • test-results.html 파일이 생성되며, 브라우저에서 열어볼 수 있음
  • table 태그를 사용하여 시각적인 보고서 제공
  • fs.writeFileSync()를 사용해 HTML 파일 업데이트

6. Playwright의 Reporter API를 활용한 커스텀 리포터

Playwright는 기본적으로 Reporter API를 제공하여 playwright.config.ts에서 사용자 지정 리포터를 설정할 수 있습니다.

📌 Custom Reporter 설정 (playwright.config.ts)

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

export default defineConfig({
  reporter: [
    ['json', { outputFile: 'custom-report.json' }],
    ['html', { outputFolder: 'playwright-report' }],
    ['./custom-reporter.ts'], // 사용자 지정 리포터 등록
  ],
});

📌 사용자 지정 리포터 (custom-reporter.ts)

import { Reporter } from '@playwright/test/reporter';
import * as fs from 'fs';

class CustomReporter implements Reporter {
  private results: any[] = [];

  onTestEnd(test, result) {
    this.results.push({
      title: test.title,
      status: result.status,
      duration: result.duration,
    });
  }

  onEnd() {
    fs.writeFileSync('custom-test-results.json', JSON.stringify(this.results, null, 2), 'utf-8');
  }
}

export default CustomReporter;

Playwright에서 공식적으로 지원하는 Reporter API를 활용하여 맞춤형 보고서를 생성 가능

  • JSON, CSV, Markdown, HTML 등 다양한 맞춤형 보고서 생성 가능
  • fs.writeFileSync()를 활용하여 실시간 테스트 결과 저장
  • Playwright의 Reporter API를 활용하면 더욱 강력한 맞춤형 보고서 제작 가능 🚀

📌 커스텀 보고서는 자동화된 QA 프로세스에서 중요한 역할을 하므로 필요에 맞게 구성하는 것이 중요합니다! 🚀