12.3 Anti-pattern Catalog
1. Hard wait
await page.waitForTimeout(3000);
빠른 환경에서는 3초를 낭비하고 느린 환경에서는 여전히 실패합니다. 필요한 제품 상태를 assertion합니다.
2. 긴 CSS/XPath
page.locator('div:nth-child(4) > div.card > button.primary');
DOM layout과 styling에 coupling됩니다. Role, label, test id 같은 계약을 사용합니다.
3. .first()로 strictness 숨기기
여러 match 중 첫 번째가 우연히 맞는 상태입니다. Scope와 accessible name을 명확히 합니다.
4. force: true 기본 사용
Overlay, animation, disabled state 같은 실제 사용자 문제를 건너뜁니다. Root cause를 고치고 의도적 특수 case에만 씁니다.
5. Retry면 해결됐다고 판단
Retry pass는 flaky 분류입니다. 최초 failure trace와 발생률을 추적합니다.
6. Test 사이 state 공유
let createdOrderId: string;
Parallelism과 failure recovery를 깨뜨립니다. 각 test가 setup하거나 explicit serial workflow로 제한합니다.
7. beforeAll에 거대한 UI setup
한 번 실패하면 group 전체가 무너지고 worker restart에서 다시 실행될 수 있습니다. API seed, fixture, project dependency를 검토합니다.
8. Page Object가 assertion을 모두 숨김
어떤 결과를 기대하는지 test body에서 사라집니다. Reusable invariant는 object에 둘 수 있지만 scenario-specific expected result는 test가 표현합니다.
9. 모든 API를 mock
Frontend와 backend contract drift를 놓칩니다. Real integration test를 소수 유지합니다.
10. 모든 것을 E2E로 검증
느리고 원인 localization이 어렵습니다. Unit/component/API layer로 분배합니다.
11. Snapshot 무조건 update
제품 회귀를 baseline으로 승인해 버립니다. Diff와 requirement를 먼저 리뷰합니다.
12. Trace, HAR, storage state commit
Token과 개인정보가 포함될 수 있습니다. Ignore, sanitize, retention, access control을 적용합니다.
13. networkidle을 readiness로 사용
Polling, streaming, analytics 때문에 영원히 idle하지 않거나 너무 일찍 idle할 수 있습니다. 제품 marker를 기다립니다.
14. Browser마다 같은 failure를 세 번 보여주기
Browser-independent logic은 Chromium smoke에 두고 compatibility 위험이 있는 scenario만 full matrix로 실행합니다.
15. Test title이 implementation detail
“button click test” 대신 “사용자가 주문을 취소한다”처럼 business outcome을 표현합니다.
Review 질문
- 이 workaround가 제품 bug를 숨기는가?
- Failure message만으로 의도를 알 수 있는가?
- Test가 더 빠른 layer로 내려갈 수 있는가?
- Artifact가 root cause를 설명하는가?
- 이 test를 누가 소유하고 언제 삭제하는가?
참고: Best Practices