10 KiB
10 KiB
RunBook: E2E Playwright CI 定期排程設定
類型: 操作型 RunBook
優先級: 🔴 P0
建立: 2026-03-29 12:38 (台北)
建立者: Antigravity
工時預估: 30 分鐘
前置條件: Playwright 測試可在本機pnpm test:e2e成功執行
背景與現況
🔍 精確現況診斷
已有的 12 個 E2E 測試檔案(apps/web/tests/e2e/):
| 測試檔案 | 測試範圍 |
|---|---|
dashboard-acceptance.spec.ts |
首頁 Dashboard 驗收 |
multisig-security.spec.ts |
多重簽核安全性 |
approval-card-verify.spec.ts |
簽核卡片驗證 |
phase11-conversational.spec.ts |
對話式 Phase 11 功能 |
phase19-production-verification.spec.ts |
Phase 19 生產驗證 |
action-log.spec.ts |
行動日誌 |
cpo102-visual.spec.ts |
視覺截圖測試 |
visual-armor-upgrade.spec.ts |
視覺升級驗證 |
debug-error.spec.ts |
錯誤頁面 |
rbac-screenshot.spec.ts |
RBAC 截圖驗證 |
phase4-final-demo.spec.ts |
Phase 4 Demo |
phase4-timeline.spec.ts |
Phase 4 時間軸 |
缺口:playwright.config.ts 已有配置,但 .github/workflows/ 中無定期執行排程。
Step 1: 建立 E2E 定期排程 Workflow
建立 .github/workflows/e2e-weekly.yaml:
name: 🎭 E2E Playwright 週期驗收
on:
# 每週一凌晨 02:30 執行(台北時間,即 UTC 18:30 週日)
schedule:
- cron: '30 18 * * 0'
# 允許手動觸發
workflow_dispatch:
inputs:
environment:
description: '測試環境 URL'
required: false
default: 'https://192.168.0.120:32335'
test_suite:
description: '測試套件 (all / smoke / visual)'
required: false
default: 'all'
jobs:
e2e-test:
name: 🎭 E2E Playwright (${{ matrix.browser }})
runs-on: [self-hosted, harbor] # 使用 .110 的 GitHub Runner
strategy:
fail-fast: false # 一個瀏覽器失敗不影響其他
matrix:
browser: [chromium, firefox]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Install Playwright Browsers
run: pnpm --filter web exec playwright install --with-deps ${{ matrix.browser }}
- name: 🎭 Run E2E Tests
run: |
cd apps/web
pnpm exec playwright test \
--project=${{ matrix.browser }} \
--reporter=html \
${SUITE_FILTER}
env:
SUITE_FILTER: ${{ github.event.inputs.test_suite == 'smoke' && '--grep @smoke' || '' }}
BASE_URL: ${{ github.event.inputs.environment || 'http://192.168.0.120:32335' }}
CI: true
- name: 📁 Upload Test Report
uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report-${{ matrix.browser }}-${{ github.run_id }}
path: apps/web/playwright-report/
retention-days: 14
- name: 📸 Upload Screenshots on Failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: e2e-screenshots-${{ matrix.browser }}-${{ github.run_id }}
path: apps/web/test-results/
retention-days: 7
- name: 🚨 Notify Telegram on Failure
if: failure()
run: |
curl -s -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
-d chat_id="${TG_CHAT_ID}" \
-d parse_mode="HTML" \
-d text="🎭 <b>E2E 週期測試失敗</b>
瀏覽器:${{ matrix.browser }}
觸發:${{ github.event_name }}
時間:$(TZ='Asia/Taipei' date '+%Y-%m-%d %H:%M:%S')
報告:${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
🔍 請立即調查 UI 回歸問題"
env:
TG_BOT_TOKEN: ${{ secrets.OPENCLAW_TG_BOT_TOKEN }}
TG_CHAT_ID: ${{ env.TELEGRAM_ALERT_CHAT_ID }}
# 視覺截圖比對工作(獨立 job,只在排程時執行)
visual-regression:
name: 📸 視覺回歸比對
runs-on: [self-hosted, harbor]
if: github.event_name == 'schedule' # 只在定期排程時執行
needs: e2e-test
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install pnpm & deps
run: |
pnpm install --frozen-lockfile
pnpm --filter web exec playwright install --with-deps chromium
- name: 📸 Generate Visual Snapshots
run: |
cd apps/web
pnpm exec playwright test \
--project=chromium \
--grep @visual \
--reporter=html \
--update-snapshots=missing # 新截圖自動建立 baseline
env:
BASE_URL: 'http://192.168.0.120:32335'
CI: true
- name: 📁 Upload Visual Snapshots
uses: actions/upload-artifact@v4
with:
name: visual-snapshots-${{ github.run_id }}
path: apps/web/tests/e2e/__snapshots__/
retention-days: 30
- name: 🚨 Notify Telegram on Visual Regression
if: failure()
run: |
curl -s -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
-d chat_id="${TG_CHAT_ID}" \
-d parse_mode="HTML" \
-d text="📸 <b>視覺回歸測試失敗</b>
AWOOOI 前端出現視覺變化!
時間:$(TZ='Asia/Taipei' date '+%Y-%m-%d %H:%M:%S')
請統帥審查截圖比對報告:
${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
env:
TG_BOT_TOKEN: ${{ secrets.OPENCLAW_TG_BOT_TOKEN }}
TG_CHAT_ID: ${{ env.TELEGRAM_ALERT_CHAT_ID }}
Step 2: 標記現有測試為 Smoke / Visual 類別
// 在各 spec 檔案第一行測試加上標籤:
// dashboard-acceptance.spec.ts(核心功能,標記為 @smoke)
test.describe('Dashboard Acceptance @smoke', () => { ... });
// cpo102-visual.spec.ts(視覺截圖,標記為 @visual)
test.describe('Visual Regression @visual', () => {
test('CPO-102 首頁視覺', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('dashboard-baseline.png', {
fullPage: true,
threshold: 0.02 // 允許 2% 像素差異
});
});
});
建議標記方式:
| 標籤 | 包含測試 | 執行頻率 |
|---|---|---|
@smoke |
dashboard, approval, action-log | 每次 CD 後 + 每週 |
@visual |
cpo102-visual, visual-armor | 只在每週排程 |
| (無標籤) | 所有其他測試 | 只在每週排程 |
Step 3: 部署並驗證
# 1. 提交 Workflow 檔案
git add .github/workflows/e2e-weekly.yaml
git commit -m "feat(ci): add weekly E2E Playwright schedule with Telegram failure notification"
git push origin main
# 2. 手動觸發測試(確認 Workflow 運作正常)
gh workflow run e2e-weekly.yaml \
-f environment="http://192.168.0.120:32335" \
-f test_suite="smoke"
# 3. 監控 Workflow 執行
gh run watch
# 4. 確認 Telegram Bot 收到失敗通知(刻意讓一個測試失敗)
驗收標準
| 項目 | 通過條件 |
|---|---|
| Workflow 存在 | .github/workflows/e2e-weekly.yaml 成功 push |
| 手動觸發正常 | gh workflow run 可執行且完成 |
| Smoke 測試通過 | @smoke 標籤測試全部 PASS |
| 失敗通知正常 | Telegram Bot 收到失敗訊息 |
| 報告上傳 | GitHub Actions Artifacts 中有 playwright-report-* |
⚠️ 架構安全補丁(2026-03-29 更新,部署前必讀)
來源:
ARCHITECTURAL_RISK_WAR_GAME.md深度沙盤推演,代碼確認級別
補丁 1:playwright.config.ts 必須加入 ignoreHTTPSErrors
問題:內網 K3s 使用自簽憑證(Self-signed cert),Playwright 連接 https://192.168.0.120:32335 時會遭遇 NET::ERR_CERT_AUTHORITY_INVALID,導致所有測試在第一步就失敗。
修復(apps/web/playwright.config.ts):
export default defineConfig({
use: {
baseURL: process.env.BASE_URL || 'http://192.168.0.120:32335',
ignoreHTTPSErrors: true, // 🆕 必須加入,否則自簽憑證全面阻擋
viewport: { width: 1280, height: 720 },
deviceScaleFactor: 1, // 🆕 防止 Retina 螢幕 DPI 差異影響截圖比對
},
expect: {
toHaveScreenshot: {
threshold: 0.05, // 🆕 允許 5% 差異(吸收跨平台字體渲染微差)
maxDiffPixelRatio: 0.05,
},
},
});
補丁 2:Visual Baseline 必須在 Docker(Linux 環境)中產生
問題:Mac(CoreText 渲染)與 GitHub Actions CI(Linux FreeType 渲染)的字體像素不同。若在 Mac 本機產生 baseline,CI 比對時100% 誤報失敗。
🔴 絕對禁止在本機 Mac 環境執行
--update-snapshots!
正確的 Baseline 更新流程:
# 在 Mac 本機執行,但透過 Docker(Linux 環境)產生截圖
cd apps/web
docker run --rm \
-v $(pwd):/work -w /work \
-p 3000:3000 \
mcr.microsoft.com/playwright:v1.44.0-jammy \
pnpm exec playwright test \
--update-snapshots \
--project=chromium \
--grep @visual
# Docker 產生的 .png 自動存入 tests/e2e/__snapshots__/
# 提 PR,標注 📸 VISUAL_UPDATE
# 統帥視覺審核截圖後方可合併
加入 package.json scripts:
{
"scripts": {
"test:visual": "playwright test --project=chromium --grep @visual",
"test:visual:update": "docker run --rm -v $(pwd):/work -w /work mcr.microsoft.com/playwright:v1.44.0-jammy pnpm exec playwright test --update-snapshots --project=chromium --grep @visual"
}
}
補丁 3:CI Threshold 需與本 RunBook Step 2 標籤保持一致
Visual 測試中 threshold: 0.02(Step 2 示例代碼)與 playwright.config.ts 全局設定 0.05 會以個別設定優先。建議統一為:
// 全局(playwright.config.ts)
threshold: 0.05 // 寬鬆(跨平台環境差異)
// 個別敏感組件(*.spec.ts)
await expect(page).toHaveScreenshot('component.png', {
threshold: 0.02 // 嚴格(關鍵組件精確比對)
});