3.3 測試隔離與自動等待#
測試隔離:每個測試都是乾淨的#
Playwright 的核心設計:每個 test 都拿到一個全新的瀏覽器 context——等同全新的無痕視窗,Cookie、localStorage、session 全是空的。
test("測試 A", async ({ page }) => { // 全新的 context
// ...
});
test("測試 B", async ({ page }) => { // 又一個全新的 context
// 不會受到測試 A 的任何影響
});
這帶來的好處:
- 測試之間零依賴:順序打亂、平行執行,結果都一樣
- 失敗好定位:A 壞了不會連累 B
- 可平行執行:因為互不干擾,Playwright 預設就平行跑
隔離的代價:不要測試間共享狀態#
// ❌ 不好:測試 B 依賴測試 A 產生的資料
test("A:新增商品", async ({ page }) => { /* 建立商品 */ });
test("B:檢查商品存在", async ({ page }) => { /* 假設商品在 */ });
// ✅ 好:每個測試自己準備自己需要的資料
test("B:檢查商品存在", async ({ page }) => {
await 建立測試商品(); // 自己建,或用 API 準備(見 4.3)
await page.goto("/products");
await expect(page.getByText("測試商品")).toBeVisible();
});
自動等待:不用手寫 sleep#
Selenium 時代的噩夢是手寫 sleep(3) 等頁面載入。Playwright 的操作與斷言內建自動等待:
// 點擊前會自動等到:元素出現、可見、可點擊
await page.getByRole("button", { name: "送出" }).click();
// 斷言會自動重試直到超時
await expect(page.getByText("成功")).toBeVisible();
所以:
// ❌ 不要這樣寫
await page.waitForTimeout(3000); // 死等 3 秒,又慢又不穩
await expect(page.getByText("成功")).toBeVisible();
// ✅ 直接斷言就好,它會自己等
await expect(page.getByText("成功")).toBeVisible();
waitForTimeout只有一個合理用途:刻意觀察動畫效果。其他情況一律靠自動等待。
明確等待的特殊情況#
// 等待網址改變
await page.waitForURL(/dashboard/);
// 等待特定請求完成(見 4.3)
await page.waitForResponse("**/api/data");
黃金法則#
- 每個測試獨立:自己準備自己的資料,不依賴其他測試
- 不寫 sleep:靠自動等待與斷言重試
- 平行是預設:設計測試時就要假設它們會同時執行