[FEAT] 導入 Playwright E2E 測試環境與登入功能測試腳本
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 1m36s

This commit is contained in:
2026-03-06 15:38:27 +08:00
parent 02e5f5d4ea
commit e11193c2a7
8 changed files with 548 additions and 60 deletions

View File

@@ -19,6 +19,7 @@ Skills 位於 `.agents/skills/`,採漸進式揭露以節省 Token。
| 跨模組、Service Interface、`Contracts`、模組間通訊、`ServiceProvider` 綁定、禁止跨模組引用 | **跨模組調用與通訊規範** | `.agents/skills/cross-module-communication/SKILL.md` |
| 按鈕樣式、表格規範、圖標、分頁、Badge、Toast、表單、UI 統一、頁面佈局、`button-filled-*``button-outlined-*``lucide-react`、色彩系統 | **客戶端後台 UI 統一規範** | `.agents/skills/ui-consistency/SKILL.md` |
| Git 分支、commit、push、合併、部署、`feature/``hotfix/``develop``main` | **Git 分支管理與開發規範** | `.agents/skills/git-workflows/SKILL.md` |
| E2E、端到端測試、Playwright、`spec.ts`、功能驗證、自動化測試、回歸測試 | **E2E 端到端測試規範** | `.agents/skills/e2e-testing/SKILL.md` |
---
@@ -31,6 +32,7 @@ Skills 位於 `.agents/skills/`,採漸進式揭露以節省 Token。
1. **permission-management** — 設定權限
2. **ui-consistency** — 遵循 UI 規範
3. **activity-logging** — 若涉及 Model CRUD需加上操作紀錄
4. **e2e-testing** — 確認是否需要新增對應的 E2E 測試
### 🔴 新增或修改 Model 時
必須讀取:

View File

@@ -0,0 +1,266 @@
---
name: E2E 端到端測試規範 (E2E Testing with Playwright)
description: 規範 Playwright 端到端測試的撰寫慣例、目錄結構、共用工具與執行方式,確保所有 E2E 測試保持一致性與可維護性。
---
# E2E 端到端測試規範 (E2E Testing with Playwright)
本技能定義了 Star ERP 系統中端到端 (E2E) 測試的實作標準,使用 Playwright 模擬真實使用者操作瀏覽器,驗證 UI 顯示與功能流程的正確性。
---
## 1. 專案結構
### 1.1 目錄配置
```
star-erp/
├── playwright.config.ts # Playwright 設定檔
├── e2e/ # E2E 測試根目錄
│ ├── helpers/ # 共用工具函式
│ │ └── auth.ts # 登入 helper
│ ├── screenshots/ # 測試截圖存放
│ ├── auth.spec.ts # 認證相關測試(登入、登出)
│ ├── inventory.spec.ts # 庫存模組測試
│ ├── products.spec.ts # 商品模組測試
│ └── {module}.spec.ts # 依模組命名
├── playwright-report/ # HTML 測試報告(自動產生,已 gitignore
└── test-results/ # 失敗截圖與錄影(自動產生,已 gitignore
```
### 1.2 命名規範
| 項目 | 規範 | 範例 |
|---|---|---|
| 測試檔案 | 小寫,依模組命名 `.spec.ts` | `inventory.spec.ts` |
| 測試群組 | `test.describe('中文功能名稱')` | `test.describe('庫存查詢')` |
| 測試案例 | 中文描述「**應**」開頭 | `test('應顯示庫存清單')` |
| 截圖檔案 | `{module}-{scenario}.png` | `inventory-search-result.png` |
---
## 2. 設定檔 (playwright.config.ts)
### 2.1 核心設定
```typescript
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',
use: {
baseURL: 'http://localhost:8081', // Sail 開發伺服器
screenshot: 'only-on-failure', // 失敗時自動截圖
video: 'retain-on-failure', // 失敗時保留錄影
trace: 'on-first-retry', // 重試時收集 trace
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
],
});
```
### 2.2 重要注意事項
> [!IMPORTANT]
> `baseURL` 必須指向本機 Sail 開發伺服器(預設 `http://localhost:8081`)。
> 確保測試前已執行 `./vendor/bin/sail up -d``./vendor/bin/sail npm run dev`
---
## 3. 共用工具 (Helpers)
### 3.1 登入 Helper
位置:`e2e/helpers/auth.ts`
```typescript
import { Page } from '@playwright/test';
/**
* 共用登入函式
* 使用測試帳號登入 ERP 系統
*/
export async function login(page: Page, username = 'mama', password = 'mama9453') {
await page.goto('/');
await page.fill('#username', username);
await page.fill('#password', password);
await page.getByRole('button', { name: '登入系統' }).click();
// 等待儀表板載入完成
await page.waitForSelector('text=系統概況', { timeout: 10000 });
}
```
### 3.2 使用方式
```typescript
import { login } from './helpers/auth';
test('應顯示庫存清單', async ({ page }) => {
await login(page);
await page.goto('/inventory/stock-query');
// ...斷言
});
```
---
## 4. 測試撰寫規範
### 4.1 測試結構模板
```typescript
import { test, expect } from '@playwright/test';
import { login } from './helpers/auth';
test.describe('模組功能名稱', () => {
// 若整個 describe 都需要登入,使用 beforeEach
test.beforeEach(async ({ page }) => {
await login(page);
});
test('應正確顯示頁面標題與關鍵元素', async ({ page }) => {
await page.goto('/target-page');
// 驗證頁面標題
await expect(page.getByText('頁面標題')).toBeVisible();
// 驗證表格存在
await expect(page.locator('table')).toBeVisible();
});
test('應能執行 CRUD 操作', async ({ page }) => {
// ...
});
});
```
### 4.2 斷言 (Assertions) 慣例
| 場景 | 優先使用 | 避免使用 |
|---|---|---|
| 驗證頁面載入 | `page.getByText('關鍵文字')` | `page.waitForURL()` ※ |
| 驗證元素存在 | `expect(locator).toBeVisible()` | `.count() > 0` |
| 驗證表格資料 | `page.locator('table tbody tr')` | 硬編碼行數 |
| 等待操作完成 | `expect().toBeVisible({ timeout })` | `page.waitForTimeout()` |
> [!NOTE]
> ※ Star ERP 使用 Inertia.js頁面導航不一定改變 URL例如儀表板路由為 `/`)。
> 因此**優先使用頁面內容驗證**,而非依賴 URL 變化。
### 4.3 選擇器優先順序
依照 Playwright 官方建議,選擇器優先順序為:
1. **Role**`page.getByRole('button', { name: '登入系統' })`
2. **Text**`page.getByText('系統概況')`
3. **Label**`page.getByLabel('帳號')`
4. **Placeholder**`page.getByPlaceholder('請輸入...')`
5. **Test ID**`page.getByTestId('submit-btn')`(需在元件加 `data-testid`
6. **CSS**`page.locator('#username')`(最後手段)
### 4.4 禁止事項
```typescript
// ❌ 禁止:硬等待(不可預期的等待時間)
await page.waitForTimeout(5000);
// ✅ 正確:等待特定條件
await expect(page.getByText('操作成功')).toBeVisible({ timeout: 5000 });
// ❌ 禁止:在測試中寫死測試資料的 ID
await page.goto('/products/42/edit');
// ✅ 正確:從頁面互動導航
await page.locator('table tbody tr').first().getByRole('button', { name: '編輯' }).click();
```
---
## 5. 截圖與視覺回歸
### 5.1 手動截圖(文件用途)
```typescript
// 成功截圖存於 e2e/screenshots/
await page.screenshot({
path: 'e2e/screenshots/inventory-list.png',
fullPage: true,
});
```
### 5.2 視覺回歸測試(偵測 UI 變化)
```typescript
test('庫存頁面 UI 應保持一致', async ({ page }) => {
await login(page);
await page.goto('/inventory/stock-query');
// 比對截圖pixel 級差異會報錯
await expect(page).toHaveScreenshot('stock-query.png', {
maxDiffPixelRatio: 0.01, // 容許 1% 差異(動態資料)
});
});
```
> [!NOTE]
> 首次執行 `toHaveScreenshot()` 會自動建立基準截圖。
> 後續執行會與基準比對,更新基準用:`npx playwright test --update-snapshots`
---
## 6. 執行指令速查
```bash
# 執行所有 E2E 測試
npx playwright test
# 執行特定模組測試
npx playwright test e2e/login.spec.ts
# UI 互動模式(可視化瀏覽器操作)
npx playwright test --ui
# 帶頭模式(顯示瀏覽器畫面)
npx playwright test --headed
# 產生 HTML 報告並開啟
npx playwright test --reporter=html
npx playwright show-report
# 更新視覺回歸基準截圖
npx playwright test --update-snapshots
# 只執行特定測試案例(用 -g 篩選名稱)
npx playwright test -g "登入"
# Debug 模式(逐步執行)
npx playwright test --debug
```
---
## 7. 開發檢核清單 (Checklist)
### 新增頁面或功能時:
- [ ] 是否已為新頁面建立對應的 `.spec.ts` 測試檔?
- [ ] 測試是否覆蓋主要的 Happy Path正常操作流程
- [ ] 測試是否覆蓋關鍵的 Error Path錯誤處理
- [ ] 共用的登入步驟是否使用 `helpers/auth.ts`
- [ ] 斷言是否優先使用頁面內容而非 URL
- [ ] 選擇器是否遵循優先順序Role > Text > Label > CSS
- [ ] 測試是否可獨立執行(不依賴其他測試的狀態)?
### 提交程式碼前:
- [ ] 全部 E2E 測試是否通過?(`npx playwright test`
- [ ] 是否有遺留的 `test.only``test.skip`