從端到端測試開始:用 Playwright 守護前端品質的實戰指南
如果你已經用 Vitest 替元件寫了單元測試,恭喜你,已經守住了「函數」與「元件」這一層。但老實說,使用者從來不在乎你的某個函數有沒有通過測試——他們只在乎打開瀏覽器後,能不能順利登入、填完表單、看到正確的結果。很多時候單元測試全綠,使用者卻在真實頁面裡卡關:按鈕點了沒反應、表單跳轉錯頁、手機版排版整個崩掉。這,就是端到端測試(End-to-End, E2E)要解決的戰場。
一、什麼是端到端測試?
端到端測試模擬真實使用者,從頭到尾跑完一條業務流程:開瀏覽器 → 輸入網址 → 登入 → 操作 → 斷言結果。它不關心內部實作,只在乎「使用者看到的行為對不對」。相對於單元測試(測一個函數)、整合測試(測模組協作),E2E 是離使用者最近、也最貼近真實的一層防護網。
二、為什麼選 Playwright?
過去談 E2E,大家直覺想到 Selenium,但它笨重、容易因為「元素還沒出現」而閃爍(flaky)。後來的 Cypress 體驗好很多,卻只支援 Chromium 系瀏覽器、且對多分頁與登入態切換較為不便。Playwright 由微軟推出,原生支援 Chromium、Firefox、WebKit(Safari 引擎)三大引擎,自帶自動等待(auto-wait),幾乎不用寫 sleep,穩定性明顯更好,這也是它近兩年快速竄紅的原因。
三、環境準備與安裝
步驟 1:在專案中安裝 Playwright(以 Node.js 前端專案為例):
npm init playwright@latest
# 或手動安裝
npm install -D @playwright/test
npx playwright install # 下載瀏覽器驅動
步驟 2:確認專案根目錄產生了 playwright.config.ts 與 tests/ 資料夾。
步驟 3:在 playwright.config.ts 中設定 baseURL 與要跑的瀏覽器:
import { defineConfig } from '@playwright/test';
export default defineConfig({
testDir: './tests',
use: {
baseURL: 'http://localhost:5173', // 你本地開發伺服器
headless: true,
},
projects: [
{ name: 'chromium', use: { browserName: 'chromium' } },
{ name: 'firefox', use: { browserName: 'firefox' } },
{ name: 'webkit', use: { browserName: 'webkit' } },
],
});
四、寫出第一個登入測試
步驟 1:在 tests/login.spec.ts 寫下模擬登入的流程。
import { test, expect } from '@playwright/test';
test('使用者可以成功登入並看到儀表板', async ({ page }) => {
await page.goto('/login');
// 填寫表單
await page.fill('input[name="username"]', 'demo');
await page.fill('input[name="password"]', 'secret');
await page.click('button[type="submit"]');
// 斷言:登入後跳轉到儀表板
await expect(page).toHaveURL(/\/dashboard/);
await expect(page.getByText('歡迎回來')).toBeVisible();
});
步驟 2:執行測試:
npx playwright test
重點:Playwright 會自動等待元素可點擊、可見,再執行動作,因此你幾乎不必手寫 waitFor 或 sleep,這是它比老工具穩定的關鍵。
五、進階技巧:選擇器、等待與夾具
步驟 1:優先使用以角色或文字為基礎的選擇器(getByRole、getByText、getByLabel),它們對 CSS 重構更魯棒,不會因為 class 改名而全軍覆沒。
await page.getByRole('button', { name: '送出' }).click();
await page.getByLabel('電子郵件').fill('a@b.com');
步驟 2:用 fixtures 抽離重複動作,例如把「登入」封裝成可復用的步驟,讓多個測試共用,減少維護成本。
步驟 3:用 expect 的軟斷言(soft assert)或 test.step 把流程分層,報錯時能一眼定位是哪一關卡住。
六、在 CI 中跑起來
重點:E2E 測試的最大價值,是在每次合併前自動擋下會破壞流程的程式碼。把 Playwright 接進 CI(如 GitHub Actions):
name: e2e
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npx playwright install --with-deps
- run: npm run build
- run: npx playwright test
搭配 --reporter=html 產出可視化報表,失敗時還能拿到自動截圖與錄影,排查問題事半功倍。
E2E 測試不是要取代單元測試,而是補上「使用者視角」這最後一塊拼圖。單元測試回答「程式對不對」,E2E 回答「產品能不能用」。兩者搭配,你的前端品質才真正站得住腳。
互動話題:你們團隊目前有在跑端到端測試嗎?最常被「閃爍測試(flaky test)」困擾的場景是什麼?歡迎在留言區分享你的踩坑經驗!