跳轉到

3.3 測試隔離與自動等待#

測試隔離:每個測試都是乾淨的#

Playwright 的核心設計:每個 test 都拿到一個全新的瀏覽器 context——等同全新的無痕視窗,Cookie、localStorage、session 全是空的。

test("測試 A", async ({ page }) => {   // 全新的 context
  // ...
});

test("測試 B", async ({ page }) => {   // 又一個全新的 context
  // 不會受到測試 A 的任何影響
});

這帶來的好處:

  1. 測試之間零依賴:順序打亂、平行執行,結果都一樣
  2. 失敗好定位:A 壞了不會連累 B
  3. 可平行執行:因為互不干擾,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");

黃金法則#

  1. 每個測試獨立:自己準備自己的資料,不依賴其他測試
  2. 不寫 sleep:靠自動等待與斷言重試
  3. 平行是預設:設計測試時就要假設它們會同時執行