6.2 常見錯誤情境與一句話解決方案
定位與操作
| 情境 | 解法 |
Timed out waiting for locator(找不到元素) | 定位器寫錯或元素真的不存在:用 Inspector 的 Pick locator 確認 |
| 元素在 iframe 裡找不到 | page.frameLocator("iframe").getByRole(...) 先進 iframe |
| class 名稱是亂碼(CSS modules 產生) | 改用 getByRole / getByText 語意定位 |
| 頁面有多個符合元素報錯(strict mode) | 加 .first()、.nth(n) 或 filter({ hasText: ... }) 縮小範圍 |
| 點不到被蓋住的元素 | 等動畫結束或捲動到可視範圍;必要時 click({ force: true })(最後手段) |
斷言與等待
| 情境 | 解法 |
| 斷言太早失敗(元素還沒出現) | 改用 expect(...).toBeVisible()(自動重試),不要手寫 waitForTimeout |
| 測試又慢又亂睡一堆 timeout | 刪掉所有 waitForTimeout,改用自動等待與斷言重試 |
expect 超時太短 | 設定檔調高 expect.timeout(如 5000) |
| 跳轉後斷言失敗 | 先 await page.waitForURL(...) 再斷言 |
隔離與資料
| 情境 | 解法 |
| 測試單獨跑會過、一起跑就壞 | 測試間有狀態依賴:每個測試自己準備資料 |
| 測試依賴特定登入狀態 | beforeEach + helper 登入,或 API 登入 + addInitScript |
| 資料庫累積一堆測試垃圾資料 | 測試資料加固定前綴(如 e2e-test-),方便清理 |
| flaky(時好時壞)很難抓 | 設定 retries + 用 Trace Viewer 看失敗原因,修掉根因 |
CI 與環境
| 情境 | 解法 |
| 本機過、CI 壞 | 環境不一致:鎖 node 版本、設 locale/timezoneId、CI 用 workers: 1 |
| CI 找不到瀏覽器 | npx playwright install --with-deps chromium |
| CI 失敗看不到畫面 | screenshot/video/trace 設 retain-on-failure + 上傳 artifact |
commit 忘了移除 .only | 設定檔加 forbidOnly: !!process.env.CI |
| 測試跑太久 | 只測關鍵路徑、只跑使用者用的瀏覽器、平行化 |
終極保險:失敗時先看證據(UI Mode 重現、Trace Viewer、報告截圖),不要憑感覺改測試。大部分 flaky 的根因是「沒有隔離」或「手寫 timeout」。