# Playwright E2E 測試配置 > **版本**: v1.0 > **建立日期**: 2026-03-20 > **負責人**: CPO > **CEO 指示 #5**: 啟用截圖與錄影加速除錯 --- ## 配置檔案 ```typescript // apps/web/playwright.config.ts import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './e2e', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: [ ['html', { outputFolder: 'playwright-report' }], ['json', { outputFile: 'playwright-report/results.json' }], ], use: { baseURL: process.env.BASE_URL || 'http://localhost:3000', trace: 'on-first-retry', // ⚠️ CEO 指示 #5: 截圖與錄影必須啟用 screenshot: 'on', // 每個測試都截圖 video: 'on-first-retry', // 失敗時錄影 // 本地化設定 locale: 'zh-TW', timezoneId: 'Asia/Taipei', }, projects: [ // Desktop Chrome (主要) { name: 'chromium', use: { ...devices['Desktop Chrome'], viewport: { width: 1920, height: 1080 }, }, }, // Desktop Firefox { name: 'firefox', use: { ...devices['Desktop Firefox'] }, }, // Desktop Safari { name: 'webkit', use: { ...devices['Desktop Safari'] }, }, // Mobile Chrome { name: 'Mobile Chrome', use: { ...devices['Pixel 5'] }, }, // Mobile Safari { name: 'Mobile Safari', use: { ...devices['iPhone 12'] }, }, ], // 本地開發伺服器 webServer: process.env.CI ? undefined : { command: 'pnpm dev', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, }, // 輸出目錄 outputDir: 'test-results/', // 截圖設定 expect: { toHaveScreenshot: { // 允許 1% 像素差異 maxDiffPixelRatio: 0.01, }, }, }); ``` --- ## 截圖與錄影配置 ### 截圖模式 | 模式 | 說明 | 建議場景 | |------|------|---------| | `'off'` | 不截圖 | - | | `'on'` | 每個測試都截圖 | **開發/CI (建議)** | | `'only-on-failure'` | 失敗時截圖 | 大規模測試 | ### 錄影模式 | 模式 | 說明 | 建議場景 | |------|------|---------| | `'off'` | 不錄影 | - | | `'on'` | 每個測試都錄影 | 深度除錯 | | `'retain-on-failure'` | 失敗時保留 | **CI (建議)** | | `'on-first-retry'` | 重試時錄影 | **CI (建議)** | --- ## 視覺回歸測試 ### 基準截圖 ```typescript // e2e/dashboard.spec.ts import { test, expect } from '@playwright/test'; test('dashboard renders correctly', async ({ page }) => { await page.goto('/dashboard'); await page.waitForLoadState('networkidle'); // 全頁截圖比對 await expect(page).toHaveScreenshot('dashboard-full.png', { fullPage: true, maxDiffPixelRatio: 0.01, }); // 特定元素截圖 const hostCard = page.locator('[data-testid="host-card"]').first(); await expect(hostCard).toHaveScreenshot('host-card.png'); }); ``` ### 基準圖存放 ``` apps/web/e2e/ ├── dashboard.spec.ts ├── dashboard.spec.ts-snapshots/ │ ├── dashboard-full-chromium.png │ ├── dashboard-full-firefox.png │ ├── dashboard-full-webkit.png │ └── host-card-chromium.png └── ... ``` --- ## CI 整合 ### GitHub Actions ```yaml # .github/workflows/e2e.yaml name: E2E Tests on: pull_request: branches: [main] jobs: e2e: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: pnpm install - name: Install Playwright browsers run: pnpm exec playwright install --with-deps - name: Run E2E tests run: pnpm exec playwright test env: BASE_URL: http://localhost:3000 # 上傳測試報告 - uses: actions/upload-artifact@v4 if: always() with: name: playwright-report path: apps/web/playwright-report/ retention-days: 30 # 上傳截圖與錄影 - uses: actions/upload-artifact@v4 if: failure() with: name: test-results path: apps/web/test-results/ retention-days: 7 ``` --- ## 測試報告 ### HTML 報告 ```bash # 本地查看報告 pnpm exec playwright show-report ``` ### 報告內容 - 所有測試結果 (通過/失敗/跳過) - 每個測試的截圖 - 失敗測試的錄影 - 錯誤堆疊追蹤 - 測試執行時間 --- ## 除錯工作流程 ### 失敗測試處理 1. 查看 CI Artifacts 下載測試報告 2. 開啟 HTML 報告查看失敗原因 3. 觀看錄影了解失敗時的畫面狀態 4. 比對截圖差異找出視覺問題 5. 本地重現並修復 ### 本地除錯 ```bash # 有頭模式執行 (可看到瀏覽器) pnpm exec playwright test --headed # 除錯模式 (可暫停/單步) pnpm exec playwright test --debug # 只執行失敗的測試 pnpm exec playwright test --last-failed ``` --- ## 變更記錄 | 日期 | 版本 | 變更 | 作者 | |------|------|------|------| | 2026-03-20 | v1.0 | 初版建立 | CPO | --- *此文件由 CPO 維護,E2E 測試必須遵守此配置。*