Playwright 베스트 프랙티스: AI 에이전트가 실수하는 10가지 규칙 (2026)
요약
AI 에이전트가 작성한 Playwright 테스트의 불안정성을 해결하기 위한 10가지 베스트 프랙티스를 소개합니다. 역할 기반 로케이터 사용, 웹 퍼스트 어서션 활용, 테스트 격리 등 안정적인 브라우저 테스트를 위한 핵심 규칙을 다룹니다.
핵심 포인트
- CSS/XPath 대신 getByRole 등 역할 기반 로케이터 사용
- 하드 웨이트(sleep)를 피하고 웹 퍼스트 어서션 활용
- 테스트 간 데이터 및 상태 격리 유지
- AI 에이전트가 생성하는 오래된 패턴과 취약한 선택자 주의
**Playwright 베스트 프랙티스 (Best practices)**는 브라우저 테스트를 안정적이고 읽기 쉽게 유지하는 규칙입니다. 역할 기반 로케이터 (role-based locators, 사용자가 보는 방식으로 찾기), 자동 대기 기능이 있는 웹 퍼스트 어서션 (web-first assertions), 그리고 격리된 테스트를 사용하세요. 데이터 시딩 (Seed data)은 UI가 아닌 API (직접 요청)를 통해 수행하세요. 하드 웨이트 (hard waits), 조건부 로직 (conditional logic), 그리고 HTML에 종속된 테스트를 피하세요. 트레이스 (traces)를 활성화하고 병렬로 실행하세요.
AI 에이전트는 1분 안에 50개의 Playwright 테스트를 작성할 수 있습니다. 그것은 매우 빨라 보입니다.
하지만 그 테스트들이 무작위로 실패하고, 아무도 그 이유를 모릅니다. 에이전트는 학습 데이터에서 오래된 패턴을 복사해 온 것입니다. 에이전트는 어젯밤에 실행이 실패했다는 사실을 알지 못합니다.
이 가이드는 테스트를 안정적으로 유지하는 10가지 베스트 프랙티스를 나열합니다. 각 규칙에 대해 올바른 작은 예시를 보여줍니다. 또한 AI 코드 에이전트가 무엇을 틀리는지도 보여줍니다. Copilot, Cursor, 그리고 Playwright codegen (테스트 레코더)과 같은 AI 도구들은 오래된 습관에 의존합니다. 누군가는 이를 바로잡아야 합니다.
1. 사용자가 보는 방식으로 요소를 찾으세요
로케이터 (locator, 요소에 대한 포인터)는 화면에서 사람이 보는 것과 일치해야 합니다. getByRole, getByLabel, 또는 getByText를 사용하세요. 이것들은 페이지를 읽는 것처럼 자연스럽습니다. 또한 HTML 리디자인 시에도 살아남습니다.
import { test, expect } from '@playwright/test';
test('user can sign in', async ({ page }) => {
...
AI 에이전트가 틀리는 부분: 이들은 page.locator('div.btn-primary > span')와 같이 CSS나 XPath (취약한 경로 선택자)를 사용합니다. 클래스 이름 하나만 바뀌어도 테스트는 깨집니다.
2. 당신을 기다려주는 웹 퍼스트 어서션을 사용하세요
웹 퍼스트 어서션 (web-first assertion, 자동 대기 체크)은 페이지가 준비될 때까지 재시도합니다. expect(locator).toBeVisible()은 스스로 기다립니다. 절대로 고정된 sleep을 추가하지 마세요.
import { test, expect } from '@playwright/test';
test('welcome message appears', async ({ page }) => {
...
AI 에이전트가 틀리는 부분: 이들은 await page.waitForTimeout(3000) (하드 포즈)을 추가합니다. 하드 웨이트는 플래키 테스트 (flaky tests, 무작위로 실패하는 테스트)의 가장 큰 원인입니다. 너무 짧으면 테스트가 실패하고, 너무 길면 테스트 스위트가 느려집니다.
3. 모든 테스트를 격리하세요
격리(Isolated)된다는 것은 각 테스트가 깨끗한 상태에서 시작됨을 의미합니다. 공유된 로그인 정보가 없어야 하며, 이전 테스트에서 남겨진 데이터도 없어야 합니다. Playwright는 각 테스트에 새로운 브라우저 컨텍스트 (browser context, 깨끗한 세션)를 제공합니다. 상태 설정은 테스트 간에 공유하지 말고 훅 (hook)에서 수행하세요.
import { test, expect } from '@playwright/test';
test.beforeEach(async ({ page }) => {
...
AI 에이전트가 실수하는 부분: 테스트를 체이닝 (chaining)하여, 테스트 2를 실행하기 위해 테스트 1이 먼저 실행되어야 하도록 만듭니다. 이렇게 하면 하나의 실패가 파일 전체를 망가뜨리게 됩니다.
4. UI가 아닌 API를 통해 상태를 시딩(Seed)하세요
페이지를 테스트하려면 먼저 데이터가 필요한 경우가 많습니다. 사용자, 주문, 초안 등이 필요할 수 있습니다. 이를 만들기 위해 10개의 화면을 일일이 클릭하지 마세요. request 픽스처 (fixture, 내장된 HTTP 클라이언트)를 사용하여 데이터를 백엔드에 직접 전송하세요. 이것이 더 빠르고 안정적입니다.
import { test, expect } from '@playwright/test';
test('opens an existing project', async ({ page, request }) => {
...
AI 에이전트가 실수하는 부분: 매번 UI를 통해 데이터를 생성합니다. 이로 인해 테스트가 길어지고 느려지며, 실제 검증과는 상관없는 이유로 설정 단계에서 실패가 발생합니다.
5. 기본적으로 테스트 ID에 의존하지 마세요
테스트 ID (테스트만을 위해 추가된 data-testid와 같은 태그)는 폴백 (fallback, 대체 수단)으로 작동해야 합니다. 하지만 먼저 getByRole과 getByLabel을 사용하세요. 이 방식들은 실제 사용자가 할 수 있는 것을 테스트합니다. 테스트 ID는 단지 특정 속성이 존재하는지만 증명할 뿐입니다.
import { test, expect } from '@playwright/test';
test('cart shows one item', async ({ page }) => {
...
AI 에이전트가 실수하는 부분: 모든 곳에 data-testid를 붙여넣습니다. 이렇게 하면 버튼에 라벨이 없고 스크린 리더 (screen reader, 보조 소프트웨어)가 버튼을 찾을 수 없는 상황에서도 테스트가 통과됩니다. 결국 테스트가 실제 버그를 놓치게 됩니다.
6. 첫 번째 재시도 시에만 트레이스(trace)를 켜세요
트레이스 (trace, 실행 전체 기록)는 모든 단계, DOM, 그리고 네트워크를 보여줍니다. 실패한 테스트의 첫 번째 재시도(retry) 시에만 기록하도록 설정하세요. 이렇게 하면 실패에 대한 증거를 확보하면서도, 정상적인 실행은 빠르게 유지할 수 있습니다.
// playwright.config.ts
import { defineConfig } from '@playwright/test';
...
AI 에이전트가 실수하는 부분: 트레이싱 (tracing)을 꺼두거나, 모든 실행에 대해 trace: 'on'으로 설정합니다. 꺼두면 테스트가 실패했을 때 증거가 남지 않습니다. 항상 켜두면 테스트 스위트 (suite) 속도가 느려지고 디스크 용량을 가득 채웁니다.
7. 테스트를 병렬로 실행하고 샤딩 (shard) 하세요
병렬 (Parallel)이란 많은 테스트를 동시에 실행하는 것을 의미합니다. Playwright는 기본적으로 이를 수행합니다. 독립적인 테스트들로 구성된 하나의 큰 파일의 경우, 병렬 모드를 설정하세요. 느린 테스트 스위트를 여러 머신에 걸쳐 나누려면, 샤딩 (sharding, 머신당 하나의 슬라이스 실행)을 사용하세요.
import { test, expect } from '@playwright/test';
test.describe.configure({ mode: 'parallel' });
...
CI (빌드 서버)에서 세 대의 머신으로 나누어 실행하기:
npx playwright test --shard=1/3
AI 에이전트가 실수하는 부분: 데이터베이스 행 (row)이나 단일 사용자를 공유하는 테스트를 작성합니다. 이를 병렬로 실행하면 테스트들이 서로 충돌하여 플래키 테스트 (flaky tests, 간헐적 실패 테스트)가 발생합니다.
8. 테스트 코드에서 if와 try를 제거하세요
테스트는 하나의 명확한 경로를 따라가야 합니다. 분기 (branching)가 없어야 합니다. 만약 테스트가 "버튼이 있는가? 있다면 클릭하라"라고 묻는다면, 이는 버그를 숨기는 것입니다. 버튼은 항상 그 자리에 있어야 합니다. 이를 단언 (Assert) 하세요.
import { test, expect } from '@playwright/test';
test('checkout button works', async ({ page }) => {
...
AI 에이전트가 실수하는 부분: 에러를 막기 위해 클릭 동작을 if (await locator.isVisible())로 감쌉니다. 이는 실제 실패 원인을 숨깁니다. 스스로의 검증을 건너뛰는 테스트는 여전히 통과 (green) 상태로 표시됩니다.
9. 구현 방식이 아닌 사용자가 보는 것을 테스트하세요
내부 구현이 아닌 동작을 테스트하세요. 눈에 보이는 결과를 확인하세요. CSS 클래스, 상태 변수 (state variable), 또는 함수 이름을 확인하지 마세요. 이러한 것들은 앱이 여전히 정상 작동하더라도 리팩터링 (refactor, 코드 재작성) 시 변경될 수 있습니다.
import { test, expect } from '@playwright/test';
test('shows a success message after submit', async ({ page }) => {
...
AI 에이전트가 실수하는 부분: class="is-active"나 정확한 HTML 구조를 단언 (assert) 합니다. 이로 인해 실제 변경 사항이 없더라도 디자인이 바뀔 때마다 테스트가 깨집니다.
10. 설정 파일에 프로젝트를 정의하세요
playwright.config.ts의 프로젝트 (이름이 지정된 테스트 설정)는 서로 다른 설정 하에서 동일한 테스트를 실행합니다. Chromium, Firefox, WebKit(세 가지 주요 브라우저 엔진)을 모두 커버하기 위해 프로젝트를 사용하세요. 하나의 설정으로 전체 커버리지를 달성할 수 있습니다.
// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
...
AI 에이전트가 실수하는 부분: 하나의 브라우저를 하드코딩하거나, projects 배열이 없는 설정을 복사합니다. 그러면 테스트 스위트가 Chrome만 테스트하게 되어, Safari 전용 버그가 사용자에게 그대로 배포됩니다.
표준은 여전히 인간의 영역입니다
AI는 초안을 빠르게 작성합니다. 이는 사실이며 유용합니다. 하지만 초안은 인터넷상의 오래된 코드 패턴을 복제합니다. 불필요한 대기 시간(hard waits)을 추가하고, 데이터를 생성하기 위해 UI를 일일이 클릭하며, 테스트 실행 결과가 계속 통과(green) 상태를 유지하도록 취약한 단계들을 if 블록으로 감싸버립니다.
아무것도 증명하지 못하는 '통과된(green)' 테스트 스위트는 테스트가 없는 것보다 더 나쁩니다. 이는 잘못된 신뢰를 심어줍니다.
따라서 워크플로우는 간단합니다. 에이전트가 초안을 작성하게 두십시오. 그다음 인간이 이 10가지 규칙에 따라 초안을 검토하고 에이전트가 틀린 부분을 수정합니다. 에이전트는 빠르게 움직이고, 인간은 테스트의 정직함을 유지합니다. 그것이 바로 AI QA 아키텍트 (AI QA Architect)의 역할입니다.
AI로 테스트를 구축하십시오. 그리고 그 테스트를 안정적으로 만드는 것은 직접 수행하십시오.
Anton Gulin은 LinkedIn에서 이 직함을 처음으로 주장한 AI QA 아키텍트 (AI QA Architect)입니다. 그는 AI 에이전트와 인간 엔지니어가 품질을 위해 협업하는 AI 기반 테스트 자동화 시스템을 구축합니다. 전 Apple SDET (Apple.com / Apple Card 출시 전 테스트 담당). anton.qa 또는 LinkedIn에서 그를 찾을 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기