PlaywrightE2E 測試Cypress自動化測試前端工程師前端教學

Playwright E2E 測試教學:前端工程師的自動化測試指南

Cypress 之外的新選擇!Playwright E2E 測試教學含配置、測試撰寫、CI 整合。Microsoft 開發,多瀏覽器支援,測試效率更高。

· 5 分鐘閱讀

單元測試驗證函式邏輯、整合測試驗證模組協作——但真正模擬用戶行為的,是 E2E(End-to-End)測試。Playwright 由 Microsoft 開發,支援三大瀏覽器(Chromium、Firefox、WebKit)、API 直覺、測試執行快速,成為 2024-2026 年最受歡迎的 E2E 測試框架。


前言:為什麼需要 E2E 測試?

單元測試再多,也無法告訴你:

  • 用戶實際操作流程是否通順:從登入到結帳,整個 flow 是否真的走得完
  • 跨頁面、跨系統的互動:多步驟表單、OAuth 登入、第三方 API 串接
  • 與真實瀏覽器的相容性:某個 CSS 樣式在 Safari 上看起來是否正常

E2E 測試用真實的瀏覽器模擬用戶行為,是測試金字塔最頂層的驗證。


Playwright vs Cypress:核心差異

面向CypressPlaywright
支援瀏覽器主要 Chrome/ElectronChromium、Firefox、WebKit
跨瀏覽器支援強(三大瀏覽器一次測試)
測試平行執行需要付費版原生支援
API 設計直覺但封閉直覺且完整(網路 interception、檔案上傳等)
截圖 / 錄影內建內建
測試隔離自動清理手動或自動都行
生態成熟但封閉快速成長,工具鏈完整

Playwright 最大的技術優勢是 WebDriver 的替代方案:用 Chrome DevTools Protocol 直接控制瀏覽器,繞過傳統 WebDriver 的效能瓶頸,速度比 Cypress 快一個數量級。


Playwright 安裝與設定

安裝

npm init playwright@latest
# 或在現有專案安裝
npm install -D @playwright/test
npx playwright install --with-deps chromium

--with-deps 會一併安裝瀏覽器所需的系統依賴(Linux 需要)。

playwright.config.ts 基本設定

// playwright.config.ts
import { defineConfig, devices } from '@playwright/test';

export default defineConfig({
  testDir: './tests',           // 測試檔案目錄
  fullyParallel: true,          // 平行執行所有測試
  forbidOnly: !!process.env.CI, // CI 環境下不允許 only() 測試
  retries: process.env.CI ? 2 : 0,  // CI 失敗時重試
  workers: process.env.CI ? 1 : undefined,  // CI 平行度降低
  
  reporter: [
    ['list'],                  // 命令列輸出
    ['html'],                  // HTML 報告
  ],

  use: {
    baseURL: 'http://localhost:3000',
    trace: 'on-first-retry',  // 失敗時自動截圖與錄影
    screenshot: 'only-on-failure',
  },

  projects: [
    // 設定三個瀏覽器
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    },
    {
      name: 'firefox',
      use: { ...devices['Desktop Firefox'] },
    },
    {
      name: 'webkit',
      use: { ...devices['Desktop Safari'] },
    },
  ],
});

第一個 Playwright 測試

測試登入流程

// tests/login.spec.ts
import { test, expect } from '@playwright/test';

test.describe('登入功能', () => {
  test('應該能夠用正確帳號密碼登入', async ({ page }) => {
    // 前往登入頁
    await page.goto('/login');

    // 填入帳號密碼
    await page.fill('[name="email"]', 'xiaoming@example.com');
    await page.fill('[name="password"]', 'password123');

    // 點擊登入按鈕
    await page.click('button[type="submit"]');

    // 等待跳轉到儀表板
    await page.waitForURL('/dashboard');

    // 驗證登入成功
    await expect(page.getByText('歡迎回來')).toBeVisible();
  });

  test('應該在錯誤密碼時顯示錯誤訊息', async ({ page }) => {
    await page.goto('/login');

    await page.fill('[name="email"]', 'xiaoming@example.com');
    await page.fill('[name="password"]', 'wrongpassword');
    await page.click('button[type="submit"]');

    // 等待錯誤訊息出現
    await expect(page.getByRole('alert')).toHaveText('帳號或密碼錯誤');
  });
});

Playwright 實用技巧

1. 等待元素出現

Playwright 預設會等待元素出現才操作,不需要手動加 waitFor

// ✅ Playwright 會自動等這個元素出現,最多 30 秒(預設 timeout)
await page.click('#submit-button');

// ✅ 手動控制等待時間
await page.click('#modal', { timeout: 5000 });

// ✅ 等待 URL 變化
await page.waitForURL('/dashboard');

// ✅ 等待網路請求完成
await page.waitForResponse(
  response => response.url().includes('/api/auth') && response.status() === 200
);

2. 網路請求 interception(Mock API)

不需要實際的後端,就能測試前端邏輯:

test('應該在 API 失敗時顯示錯誤提示', async ({ page }) => {
  // Mock /api/users 回傳錯誤
  await page.route('/api/users', route => {
    route.fulfill({
      status: 500,
      contentType: 'application/json',
      body: JSON.stringify({ error: '伺服器錯誤' }),
    });
  });

  await page.goto('/users');
  await expect(page.getByText('伺服器錯誤')).toBeVisible();
});

3. 跨瀏覽器截圖比對

test('登入頁在各瀏覽器看起來正確', async ({ page }) => {
  await page.goto('/login');
  await page.fill('[name="email"]', 'test@example.com');
  await page.fill('[name="password"]', 'password');

  // 截圖會存在 test-results/ 目錄
  await page.screenshot({ path: `login-form-${page.context().browser()?.browser()?.type()}.png` });
});

4. Playground:互動式除錯

// 在測試中加入 debug 行,Playwright 會停在這裡等你用 Playwright inspector 查看
test('debug example', async ({ page }) => {
  await page.goto('/dashboard');
  // 執行到這一行後停住,開啟 Playwright Inspector 視窗
  await page.pause();
  // ...
});

Playwright + GitHub Actions

# .github/workflows/e2e.yml

name: E2E Tests

on: [push, pull_request]

jobs:
  e2e:
    timeout-minutes: 60
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'npm'

      - run: npm ci

      - name: Install Playwright Browsers
        run: npx playwright install --with-deps

      - name: Run E2E tests
        run: npx playwright test

      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 30

常見問題

Q:Playwright 和 Cypress 哪個更適合我的專案?

A:選擇 Cypress 的理由——你只需要測試 Chrome/Electron,而且喜歡 Cypress 獨特的「同步」語法。選擇 Playwright 的理由——你需要跨瀏覽器支援(特別是 Safari/WebKit)、需要測試 API interception、或需要更完整的調試工具。新專案建議直接選 Playwright,技術債更少。

Q:Playwright 可以用來做 Visual Regression Testing 嗎?

A:可以。Playwright 支援 page.screenshot() 截圖功能,加上 pixelmatchplaywright-visual-regression 外掛可以做像素比對。這個方向可以參考「Visual Regression Testing」的文章。

Q:Playwright 的測試速度怎麼樣?

A:比 Cypress 快很多,特別是平行執行時。單一瀏覽器執行大約是 Cypress 的 2-3 倍快,多瀏覽器平行執行還會更快。但要注意 E2E 測試本身的特性——啟動瀏覽器、開頁面、等網路請求——這些時間是無法省掉的。

Q:測試要寫多少才夠?

A:E2E 測試的原則是測試核心 user journey,而不是追求覆蓋率。建議測試最多的是:

  • 登入 / 註冊流程
  • 付款流程(如果有的話)
  • 關鍵的資料建立和刪除流程

其他周邊功能交給單元測試和整合測試就好。


總結:E2E 測試是測試金字塔的最後一塊

Playwright 的核心價值:用最少的設定,覆蓋最多的瀏覽器

這篇文章涵蓋:

  • Playwright 與 Cypress 的核心差異
  • Playwright 安裝與 playwright.config.ts 設定
  • 第一個登入流程測試
  • 實用技巧(等待、API Mock、截圖)
  • GitHub Actions 整合

下一步:在你的 React 或 Next.js 專案加入 Playwright,測試一個你最重要的 user journey。從「登入」開始,是最不容易失敗、最有價值的起點。


延伸閱讀