3.2 Fixtures:beforeEach 與共用準備#
問題:每個測試都要重複準備#
十個測試都要先登入,難道要複製貼上十遍?
beforeEach:每個測試前自動執行#
import { test, expect } from "@playwright/test";
test.describe("購物車", () => {
test.beforeEach(async ({ page }) => {
// 每個測試前都先登入並進到購物車頁
await page.goto("https://my-site.com/login");
await page.getByLabel("電子郵件").fill("user@test.com");
await page.getByLabel("密碼").fill("password123");
await page.getByRole("button", { name: "登入" }).click();
await expect(page).toHaveURL(/dashboard/);
await page.getByRole("link", { name: "購物車" }).click();
});
test("加入商品後數量應該更新", async ({ page }) => {
await page.getByRole("button", { name: "加入購物車" }).click();
await expect(page.getByText("1 件商品")).toBeVisible();
});
test("清空購物車", async ({ page }) => {
await page.getByRole("button", { name: "清空" }).click();
await expect(page.getByText("購物車是空的")).toBeVisible();
});
});
其他相似工具:
test.beforeAll(async () => { }); // 整個檔案跑一次(開測試前)
test.afterEach(async () => { }); // 每個測試後(清理)
test.afterAll(async () => { }); // 整個檔案結束後(清理)
存取測試資料:fixtures 的參數#
test 的第一個參數物件提供內建 fixtures:
test("範例", async ({ page, browserName, viewport }) => {
// page:頁面物件(最常用)
// browserName:瀏覽器名稱(chromium/firefox/webkit)
// viewport:視窗大小
});
共用的登入 helper(跨檔案重複時)#
多個測試檔都要登入?抽出 helper 函式:
// tests/helpers/login.ts
import { expect, type Page } from "@playwright/test";
export async function login(page: Page) {
await page.goto("https://my-site.com/login");
await page.getByLabel("電子郵件").fill("user@test.com");
await page.getByLabel("密碼").fill("password123");
await page.getByRole("button", { name: "登入" }).click();
await expect(page).toHaveURL(/dashboard/);
}
// tests/cart.spec.ts
import { test, expect } from "@playwright/test";
import { login } from "./helpers/login";
test.beforeEach(async ({ page }) => {
await login(page);
});
分工原則#
| 情境 | 用什麼 |
|---|---|
| 同一個檔案內的共用準備 | beforeEach |
| 跨檔案共用的操作 | helper 函式 |
| 每個測試都需要、且與頁面狀態相關 | 自訂 fixture(進階) |
原則:準備工作抽出去,測試本體只留「操作 + 斷言」。這樣每個測試一打開就是重點,好讀好維護。