Files
star-erp/.agents/skills/e2e-testing/SKILL.md
sky121113 e11193c2a7
All checks were successful
ERP-Deploy-Demo / deploy-demo (push) Successful in 1m36s
[FEAT] 導入 Playwright E2E 測試環境與登入功能測試腳本
2026-03-06 15:38:27 +08:00

7.6 KiB
Raw Blame History

name, description
name description
E2E 端到端測試規範 (E2E Testing with Playwright) 規範 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 核心設定

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

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 使用方式

import { login } from './helpers/auth';

test('應顯示庫存清單', async ({ page }) => {
  await login(page);
  await page.goto('/inventory/stock-query');
  // ...斷言
});

4. 測試撰寫規範

4.1 測試結構模板

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. Rolepage.getByRole('button', { name: '登入系統' })
  2. Textpage.getByText('系統概況')
  3. Labelpage.getByLabel('帳號')
  4. Placeholderpage.getByPlaceholder('請輸入...')
  5. Test IDpage.getByTestId('submit-btn')(需在元件加 data-testid
  6. CSSpage.locator('#username')(最後手段)

4.4 禁止事項

// ❌ 禁止:硬等待(不可預期的等待時間)
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 手動截圖(文件用途)

// 成功截圖存於 e2e/screenshots/
await page.screenshot({
  path: 'e2e/screenshots/inventory-list.png',
  fullPage: true,
});

5.2 視覺回歸測試(偵測 UI 變化)

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. 執行指令速查

# 執行所有 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.onlytest.skip