Files
awoooi/docs/runbooks/RUNBOOK-E2E-CI-SCHEDULE.md
Your Name 95110971f3
Some checks failed
CD Pipeline / tests (push) Successful in 1m27s
Code Review / ai-code-review (push) Successful in 29s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
fix(telegram): close remaining DM alert routes
2026-04-30 23:02:17 +08:00

337 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`
```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 類別
```typescript
// 在各 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: 部署並驗證
```bash
# 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` 深度沙盤推演,代碼確認級別
### 補丁 1playwright.config.ts 必須加入 ignoreHTTPSErrors
**問題**:內網 K3s 使用自簽憑證Self-signed certPlaywright 連接 `https://192.168.0.120:32335` 時會遭遇 `NET::ERR_CERT_AUTHORITY_INVALID`,導致**所有測試在第一步就失敗**。
**修復**`apps/web/playwright.config.ts`
```typescript
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,
},
},
});
```
---
### 補丁 2Visual Baseline 必須在 DockerLinux 環境)中產生
**問題**MacCoreText 渲染)與 GitHub Actions CILinux FreeType 渲染)的字體像素不同。若在 Mac 本機產生 baselineCI 比對時**100% 誤報失敗**。
> 🔴 **絕對禁止在本機 Mac 環境執行 `--update-snapshots`**
**正確的 Baseline 更新流程**
```bash
# 在 Mac 本機執行,但透過 DockerLinux 環境)產生截圖
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**
```json
{
"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"
}
}
```
---
### 補丁 3CI Threshold 需與本 RunBook Step 2 標籤保持一致
Visual 測試中 `threshold: 0.02`Step 2 示例代碼)與 `playwright.config.ts` 全局設定 `0.05` 會以**個別設定優先**。建議統一為:
```typescript
// 全局playwright.config.ts
threshold: 0.05 // 寬鬆(跨平台環境差異)
// 個別敏感組件(*.spec.ts
await expect(page).toHaveScreenshot('component.png', {
threshold: 0.02 // 嚴格(關鍵組件精確比對)
});
```