All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 1m36s
267 lines
7.6 KiB
Markdown
267 lines
7.6 KiB
Markdown
---
|
||
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`?
|