yja
[Webi] Playwright 본문
Fast and reliable end-to-end testing for modern web apps | Playwright
Cross-browser end-to-end testing for modern web apps
playwright.dev
Playwright 란?
마이크로소프트에서 만든 오픈소스 E2E(End-to-End) 테스트 프레임워크이다.
Playwright는 자동화된 UI 테스트, 크로스 브라우저 테스트, 스크린샷 / 비디오 캡쳐 기능을 지원하며, 모든 브라우저에서 지원한다는 장점이 있다.
Playwright 설치하기
pnpm create playwright
몇 가지 물음에 답을 하면 설치가 완료된다!

이때 Github Actions (CI/CD(지속적 통합/지속적 배포) 도구) 설정 파일을 자동으로 생성해줄까? 라는 질문이 나오는데, 대부분의 경우 하는 것이 좋다.
CI (Continuous Integration) 화면에서 자동 테스트 실행을 바로 설정해주어서 나중에 번거롭게 설정할 필요가 없어진다.
Yes 라고 답하면 Github Actions 자동 테스트 스크립트인 `.github/workflows/playwright.yml`을 자동으로 생성해준다.
이제 pr을 올릴 때와 push 할 때 Github Actions가 playwright 테스트를 자동 실행하게 된다.
playwright.yml
name: Playwright Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: lts/*
- name: Install dependencies
run: npm install -g pnpm && pnpm install
- name: Install Playwright Browsers
run: pnpm exec playwright install --with-deps
- name: Run Playwright tests
run: pnpm exec playwright test
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-report
path: playwright-report/
retention-days: 30
그리고 다음 명령어들을 사용할 수 있다고 뜬다.
pnpm exec playwright test
# Runs the end-to-end tests.
pnpm exec playwright test --ui
# Starts the interactive UI mode.
pnpm exec playwright test --project=chromium
# Runs the tests only on Desktop Chrome.
pnpm exec playwright test example
# Runs the tests in a specific file.
pnpm exec playwright test --debug
# Runs the tests in debug mode.
pnpm exec playwright codegen
# Auto generate tests with Codegen.
We suggest that you begin by typing:
# pnpm exec playwright test
package.json에 테스트 스크립트 추가
터미널에서 실행하기 편하게 이걸 적어놓으면 좋다. 터미널에서 `pnpm run test:e2e`로 실행할 수 있다.
"scripts": {
...
"test:e2e": "playwright test",
...
}
유닛 테스트 vs. E2E 테스트
유닛 테스트 (`vitest`, `@testing-library/react` 등 .. ) 과 E2E 테스트 (`playwright`) 의 다른 점은 무엇일까 ?
유닛 테스트는 컴포넌트 단위로 컴포넌트의 상태, 클래스 등의 동작을 테스트하고 가짜 DOM (jsdom) 에서 실행한다.
따라서 컴포넌트 테스트라고도 부른다.
밑의 예시는 Message 컴포넌트가 props에 따라 올바른 클래스를 갖고 있는지를 확인한다.
render(<Message type="me">내 메시지</Message>);
반면에 E2E 테스트는 페이지 이동이나 로그인, 검색과 같은 앱 전체 흐름을 테스트한다. 그리고 유닛 테스트와 는 다르게 실제 브라우저에서 실행한다.
밑에 예시는 유저가 실제로 '안녕하세요'라는 메시지를 입력하고, 버튼을 누르면 화면에 정상적으로 반영이 되는지 확인한다.
test('유저가 메시지를 입력하고 전송하면 채팅창에 표시됨', async ({ page }) => {
await page.goto('http://localhost:3000/chat');
await page.fill('#message-input', '안녕하세요');
await page.click('#send-button');
await expect(page.getByText('안녕하세요')).toBeVisible();
});
그래서 보통 프로젝트에서 작은 로직은 `vitest` + `@testing-library` 로 컴포넌트를 검사하고,
실제 사용자의 흐름은 `playwright`로 검사하여 두 가지를 같이 쓴다.
프로젝트 적용하기
platwright 설치를 완료하면, `tests/` 폴더와 `tests-examples/` 폴더가 생성되는데,
`tests/` 에는 내가 이 프로젝트에 적용하고 싶은 테스트를 직접 작성하는 곳이고,
`tests-examples/` 은 예제용 샘플 테스트 코드라서 나중에 삭제해도 된다.
기본적인 함수 알아보기
- `page.goto()` : 페이지 이동
- `.click()` : 요소 클릭
- `getByRole`, `getByText`, `getByTestId` : 요소 찾기
- `expect(...).toBeVisible()`, `toHaveTitle()` : 페이지 요소 확인하기
아직은 로직이 많지 않아서 일부 로직만 먼저 테스트 해보려고 한다.
첫번째로, 사이드 패널이 열리는지 테스트를 해보고 싶다.
여기서 잠깐 생각해봐야할 게 있다!
아까 playwright에서는 페이지 이동을 검사할 수 있다고 했다.
그런데 크롬 익스텐션을 보려면 빌드가 완성된 dist 폴더 하나로 나온다. 한 페이지 단위로 보려면 어떻게 해야하는지 먼저 이것부터 알아보자.
원래 웹 프로젝트에서는 `https://localhost:3000/..` 로컬 호스트 url이 있다.
그런데 크롬 익스텐션에서는 Vite에서 빌드된 결과물을 보고 있기 때문에, `pnpm run dev`와 같은 Vite dev 서버에서 보면 안된다.
왜냐하면 Vite dev 서버는 보통 `src` 기반의 개발 환경만을 제공하기 때문에, 빌드된 `dist/` 내부 파일은 자동으로 서빙되지 않는다.
그러면 어떻게 이 페이지만을 로컬로 직접 확인할 수 있을까?
Vite dev 서버가 아닌, 정적 서버로 dist 를 서빙하면 된다.
아래 명령어로 dist 폴더를 정적 웹 서버로 띄울 수 있다.
npx serve dist
`serve` 라는 패키지를 설치하라고 나오니 설치한다.
이제 로컬 호스트 url 로 직접 해당 페이지에 접근할 수 있게 되었다.


1. 사이드 패널이 잘 렌더링 되는지 확인하기
원래는 채팅 입력하기 버튼을 누르면 사이드 패널이 열리는지를 확인하고 싶었다.
그런데 playwright에는 크롬 내부 기능인 사이드 패널이 열리는지 검사를 할 수 없다고 해서, 사이드 패널 페이지가 잘 렌더링되는지를 검사하기로 했다.
사이드 패널 페이지로 가서, 사이드 패널의 헤더에 Webi 제목이 보이면 사이드 패널이 잘 렌더링되었다고 볼 수 있다.
`"Webi"` 만 검사하면 잘 탐지하지 못할 수도 있어서 `"/Webi/"` 로 앞 뒤에 무언가 포함되도 상관없게 했다.
import { test, expect } from "@playwright/test";
test("sidePanel.html이 렌더링되는지", async ({ page }) => {
await page.goto("http://localhost:3000/sidePanel.html");
const title = await page.getByRole("heading", { name: /Webi/ });
await expect(title).toBeVisible();
});
2. 채팅 메시지 전송하면 렌더링되는지 확인하기

placeholder에 있는 "Type your message..." 부분을 찾아서 여기에 텍스트를 입력하고 전송을 누르면 메시지가 화면에 잘 보이는지 테스트한다.
import { test, expect } from "@playwright/test";
test("채팅 메시지 전송 시 화면에 렌더링되는지 확인", async ({ page }) => {
await page.goto("http://localhost:3000/sidePanel.html");
// 1. 채팅 메시지를 입력
const input = page.getByPlaceholder("Type your message...");
const message = "this is a test message!";
await input.fill(message);
// 2. 전송 버튼 클릭
await input.press("Enter");
await expect(page.getByText(message)).toBeVisible();
});
테스트 하기
pnpm exec playwright test # 기본값으로 제공되는 테스트 실행
# 또는
pnpm run test:e2e # 자주 쓰는 옵션을 package.json에 미리 정의해놓고 실행
1. 테스트 실패 시
아까 실행했던 serve 서버를 중단해놓고 있었더니, `http://localhost:3000/sidePanel.html`으로 갈 수 없다고 나왔다.
터미널에서 각각의 브라우저에서 테스트가 성공/실패했는지가 뜨고,

`localhost:9323` 으로 실패한 이유가 화면에 나온다.

sidePanel.html 로 페이지 이동을 할 수 없다고 한다.

Attachments 탭에서 어떤 파일도 볼 수 있다.
`error-context.md`는 보통 Playwright 또는 CI 환경(GitHub Actions 등)에서 테스트 실패 시 자동 생성되는 Markdown 파일이다. 이 파일은 테스트의 실패 원인을 요약해서 사람이 읽기 쉬운 형식으로 정리해준다.
테스트 실패 시점의 UI 구조를 이렇게 요약해서 제공해서 화면이 예상한 대로 렌더링됐는지를 판단할 수 있다.


그리고 이 파일은 프로젝트의 `test-result` 폴더에도 나온다.

2. 테스트 성공 시
성공 시에는 실패 시에 떳던 화면이 뜨지 않고, 터미널 상에서만 성공했다고 알려준다.
아래 세가지 명령어는 모두 같다.
다만 `npx playright test` 는 npm 기반, `pnpm ~ `은 pnpm 기반이어서 pnpm으로 쓰는 것이 속도도 빠르고 더 좋다.

3. UI 모드로 실행하기
pnpm exec playwright test --ui
터미널 콘솔이 아닌 브라우저 기반의 테스트 실행 UI를 띄워준다.
이 UI에서 테스트 목록을 클릭해서 선택적으로 실행할 수 있고, 테스트 실패 원인과 스냅샷, 로그를 시각적으로 확인할 수 있다.


궁금증 !!
좀전에 로컬에서는 serve 서버가 켜져있지 않아서 테스트가 실패했다.
그래서 궁금증이 생겼다.
push할때마다 테스트가 실행되게 했는데,, 그럼 push를 올리기 전마다 번거롭게 미리 서버를 켜놓아야하는걸까?
-> CI 워크플로우 설정(`.github/workflows/*.yml`)에서 테스트 시작 전에 자동으로 서버를 띄우고, Playwright가 그 서버에 접속해서 테스트를 실행하게 하면 된다.
이렇게 하면 GitHub Actions가 자동으로 서버를 켜고 테스트를 수행하므로, 매번 수동으로 서버를 켜놓을 필요가 없다.
playwright.config.ts 에 다음을 추가한다.
테스트가 돌아가기 전에 서버가 먼저 실행되도록 한다. 이렇게 하면 push 시에도, 일반 로컬 테스트 시에도 자동으로 서버가 먼저 켜진다.
/* Run your local dev server before starting the tests */
webServer: {
command: "pnpm build && npx serve dist",
url: "http://localhost:3000",
reuseExistingServer: !process.env.CI,
},
'[Web-Front] React > [한이음] Chrome Extension' 카테고리의 다른 글
| [Webi] 크롬 익스텐션에서 카카오 로그인 구현하기 (0) | 2025.09.29 |
|---|---|
| Claude Code 써보기 (5) | 2025.08.15 |
| [Webi] Claude MCP와 크롬 익스텐션 (2) | 2025.07.27 |
| 서버 센트 이벤트 (SSE)로 채팅 만들기 (3) | 2025.06.16 |
| [Webi] 크롬 사이드 패널 구현하기 (2) | 2025.06.12 |