Next.js 15를 공부하면서 "이왕 하는 김에 테스트도 손에 익혀 보자" 싶어서
Playwright를 같이 붙이기 시작했다.
이번 글은 거창한 튜토리얼이라기보다는
"처음 깔고, 최소한의 설정을 하고, 내 페이지 하나를 실제로 눌러 본 기록"에 가깝다.
결론 먼저
- Next.js 15 프로젝트에 Playwright를 붙이는 것만 보면 어렵지 않았다
- pnpm create playwright로 설치하면 초기 설정 파일까지 한 번에 만들어 준다
- playwright.config.ts에서 dev 서버만 Next에 맞게 지정해 주면 바로 테스트를 돌릴 수 있다
- getByTestId를 쓰면 Tailwind 기반 UI에서도 꽤 편하게 요소를 찾을 수 있다
- pnpm exec playwright show-report로 HTML 리포트를 바로 확인할 수 있어서,
테스트 결과를 브라우저로 보는 경험이 생각보다 괜찮았다
0. 이번 글에서 하는 것
이 글에서 정리하는 내용은 대략 이렇다.
- Playwright 설치 방법 정리 (pnpm 기준)
- Next.js 15 dev 서버에 맞춘 최소 playwright.config.ts 설정
- 다이얼로그 열고 닫히는지 확인하는 첫 테스트 코드
- data-testid와 getByTestId로 요소를 잡는 패턴
- 테스트 리포트 보는 방법과, 앞으로 자주 쓸 것 같은 API 메모
공식 문서는 여기들을 참고했다.
- Next.js + Playwright 한글 문서
- Playwright 공식 문서
1. 설치 – pnpm 기준
처음에는 "설치부터 헷갈리면 귀찮아져서 안 하게 되겠지" 싶어서, 일단 명령어부터 정리했다.
# (옵션) 처음부터 Playwright 템플릿까지 같이 만들고 싶을 때
pnpm create playwright
# 내가 사용한 방식 – Next.js 프로젝트에 테스트 러너만 추가
pnpm install -D @playwright/test
# Playwright에서 사용하는 브라우저 엔진 설치
pnpm exec playwright install
# 기본 테스트 실행 (headless)
pnpm exec playwright test
# HTML 리포트 보기
pnpm exec playwright show-report
# UI 모드로 테스트 실행
pnpm exec playwright test --ui
내 경우에는 처음 도입이라 pnpm create playwright를 사용했고, 테스트 폴더와 예제 파일, 설정 파일이 한 번에 만들어졌다.
2. 최소 설정 – Next dev 서버 붙이기
설치 후에 큰 설정을 건드리지는 않았고,
처음 테스트를 돌리기 위해서는 dev 서버 설정만 Next에 맞게 잡아 주면 됐다.
playwright.config.ts에서 webServer 부분만 다음처럼 수정했다.
// playwright.config.ts 일부
webServer: {
command: "pnpm run dev",
url: "http://localhost:3000",
reuseExistingServer: !process.env.CI,
},
의도는 단순하다.
- 테스트 실행 시 dev 서버를 자동으로 띄운다
- 이미 떠 있는 경우에는 재사용한다
- CI에서는 항상 새로 띄운다
여기까지만 맞춰 놓으면 pnpm exec playwright test로
Next.js 앱을 실제 브라우저에서 두드려 볼 수 있다.
3. 첫 테스트 – 다이얼로그 열리고 닫히는지 보기
내가 먼저 테스트해 본 것은 탑 네비게이션에서 열리는 다이얼로그였다.
- 버튼을 클릭하면 다이얼로그가 올라온다
- 다른 버튼을 누르면 다시 내려간다
- Tailwind 클래스로 translate-y-full과 translate-y-0을 쓰고 있었다
그래서 테스트 목표는 이렇게 잡았다.
- 처음에는 다이얼로그가 내려가 있는지 확인
- 버튼을 클릭했을 때 올라오는지 확인
- 닫기 버튼을 클릭했을 때 다시 내려가는지 확인
import { test, expect } from "@playwright/test";
test("탑네비게이션에서 다이얼로그 열리고 닫히는지 확인", async ({ page }) => {
// 페이지 로드
await page.goto("http://localhost:3000");
// 필요한 요소들 미리 가져오기
const openButton = page.getByTestId("address-dialog-open-button");
const closeButton = page.getByTestId("address-dialog-close-button");
const dialog = page.getByTestId("address-dialog");
// 다이얼로그가 처음에는 닫혀 있는지 확인
await expect(dialog).toHaveClass(/translate-y-full/);
// 버튼 클릭해서 다이얼로그 열기
await openButton.click();
// 다이얼로그가 열렸는지 확인
await expect(dialog).toHaveClass(/translate-y-0/);
// 닫기 버튼 클릭
await closeButton.click();
// 다시 닫혔는지 확인
await expect(dialog).toHaveClass(/translate-y-full/);
});
테스트 코드만 보면 딱 "사람이 직접 눌러 보는 순서" 그대로다.
- 페이지로 이동한다
- 버튼과 다이얼로그 요소를 잡는다
- 처음 상태를 검증한다
- 열기 버튼을 누른다
- 열린 상태를 검증한다
- 닫기 버튼을 누른다
- 닫힌 상태를 다시 검증한다
4. getByTestId와 data-testid – Tailwind에서 특히 편했다
처음에는 "클래스로 잡을까, 텍스트로 잡을까" 고민하다가,
공식 문서에서 소개하는 getByTestId를 써 보기로 했다.
Tailwind 클래스를 그대로 셀렉터로 쓰면
- 클래스가 바뀔 때 테스트가 같이 깨지고
- 의도와 상관없이 스타일 변경에 너무 민감해진다
그래서 테스트 전용으로 data-testid를 박아두고
그걸 기준으로 요소를 잡는 쪽이 훨씬 편했다.
실제 컴포넌트는 이런 식으로 바꿨다.
<div
data-testid="address-dialog"
className={clsx(
"fixed bottom-0 left-0 right-0 top-0 z-20 mt-2 overflow-hidden rounded-md bg-gray-300/70 transition duration-300",
dialog ? "translate-y-0" : "translate-y-full",
)}
>
{/* ... */}
</div>
버튼들도 마찬가지로 data-testid를 달아 두고 사용했다.
<button data-testid="address-dialog-open-button">주소 변경</button>
<button data-testid="address-dialog-close-button">닫기</button>
이렇게 해 두면 테스트 코드에서는 언제나
page.getByTestId("address-dialog");
처럼 읽기 쉬운 형태로 요소를 가져올 수 있다.
5. 리포트 보는 흐름
테스트를 돌리고 나면, 콘솔에 이런 식으로 메시지가 뜬다.
pnpm exec playwright test
Running 3 tests using 3 workers
3 passed (30.9s)
To open last HTML report run:
pnpm exec playwright show-report
안내에 적힌 대로 명령어를 한 번 더 실행하면 된다.
pnpm exec playwright show-report
그러면 브라우저가 열리고
- 어떤 테스트가 있었는지
- 어느 단계에서 실패했는지
- 스크린샷과 타임라인은 어떻게 찍혔는지
같은 정보를 한 번에 볼 수 있다.
처음에는 그냥 콘솔에 "passed"만 뜨는 것으로도 만족했는데,
HTML 리포트를 보고 나니 차라리 여기까지 같이 보는 편이
"테스트를 돌렸다"는 느낌이 더 많이 들었다.
6. 자주 쓰게 될 것 같은 API 메모
아직은 많이 써 본 단계는 아니고,
우선 공식 문서와 샘플 코드에서 자주 보이는 것들만 정리해 놓았다.
Playwright 기본 API는 여기에서 볼 수 있다.
내가 특히 자주 보게 된 것들만 추리면 아래 정도다.
- page.goto() 페이지를 지정한 URL로 이동
- page.locator() 셀렉터로 요소 찾기
- page.getByTestId() data-testid 기반으로 요소 찾기
- locator.click() 요소 클릭
- expect(locator).toBeVisible() 화면에 보이는지 확인
- expect(page).toHaveURL() 현재 URL 검증
- expect(locator).toContainText() 특정 텍스트 포함 여부 확인
- expect(locator).toHaveClass() 클래스에 특정 패턴이 포함되어 있는지 확인
앞으로 테스트를 더 늘리면서
- 어떤 것은 getByRole로 잡는 것이 좋은지
- 어떤 것은 getByText나 getByPlaceholder가 더 나은지
같은 선택 기준도 조금씩 쌓아 갈 예정.
7. 작게 남겨두는 회고
Next.js 15에 Playwright를 붙여 본 첫 느낌은 이렇다.
- 설치와 기본 설정은 생각보다 단순했다
- 한 번 돌아가는 테스트를 만들고 나니, UI를 직접 눌러 보는 습관을
그대로 코드로 옮기는 느낌이라 나쁘지 않았다 - 다만 아직은 "테스트를 구조적으로 어떻게 나눌지"까지는 감이 덜 와서,
일단은 자주 쓰는 화면부터 하나씩 눌러 보는 수준이다
'FrontEnd > Testing' 카테고리의 다른 글
| Next.js 15 + Playwright 2편 – API 테스트 맛보기 (0) | 2024.11.25 |
|---|
