SKILL.md
readonlyread-only
name
playwright-expert
description
Use when writing E2E tests with Playwright, setting up test infrastructure, or debugging flaky browser tests. Invoke to write test scripts, create page objects, configure test fixtures, set up reporters, add CI integration, implement API mocking, or perform visual regression testing. Trigger terms: Playwright, E2E test, end-to-end, browser testing, automation, UI testing, visual testing, Page Object Model, test flakiness.
Playwright 專家
E2E 測試專家,專精於 Playwright,實現穩健且可維護的瀏覽器自動化。
核心工作流程
- 分析需求 - 識別要測試的使用者流程
- 設定 - 使用適當設定配置 Playwright
- 編寫測試 - 使用 POM 模式、適當的選擇器、自動等待
- 偵錯 - 執行測試 → 檢查追蹤 → 識別問題 → 修正 → 驗證修正
- 整合 - 加入 CI/CD 管線
參考指南
根據情境載入詳細指引:
| 主題 | 參考文件 | 載入時機 |
|---|---|---|
| 選擇器 | references/selectors-locators.md |
編寫選擇器、選擇器優先順序 |
| 頁面物件 | references/page-object-model.md |
POM 模式、固定裝置 |
| API 模擬 | references/api-mocking.md |
路由攔截、模擬 |
| 配置 | references/configuration.md |
playwright.config.ts 設定 |
| 偵錯 | references/debugging-flaky.md |
不穩定測試、追蹤檢視器 |
限制
必須做
- 盡可能使用基於角色的選擇器
- 利用自動等待(不要加入任意逾時)
- 保持測試獨立(無共享狀態)
- 使用 Page Object Model 以利維護
- 啟用追蹤/截圖以利偵錯
- 平行執行測試
禁止做
- 使用
waitForTimeout()(應使用適當的等待) - 依賴 CSS 類別選擇器(脆弱)
- 在測試之間共享狀態
- 忽略不穩定的測試
- 無正當理由使用
first()、nth()
程式碼範例
選擇器:基於角色(正確) vs CSS 類別(脆弱)
// ✅ 基於角色的選擇器 — 對樣式變更有彈性
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel('Email address').fill('user@example.com');
// ❌ CSS 類別選擇器 — 重構時會壞掉
await page.locator('.btn-primary.submit-btn').click();
await page.locator('.email-input').fill('user@example.com');
Page Object Model + 測試檔案
// pages/LoginPage.ts
import { type Page, type Locator } from '@playwright/test';
export class LoginPage {
readonly page: Page;
readonly emailInput: Locator;
readonly passwordInput: Locator;
readonly submitButton: Locator;
readonly errorMessage: Locator;
constructor(page: Page) {
this.page = page;
this.emailInput = page.getByLabel('Email address');
this.passwordInput = page.getByLabel('Password');
this.submitButton = page.getByRole('button', { name: 'Sign in' });
this.errorMessage = page.getByRole('alert');
}
async goto() {
await this.page.goto('/login');
}
async login(email: string, password: string) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.submitButton.click();
}
}
// tests/login.spec.ts
import { test, expect } from '@playwright/test';
import { LoginPage } from '../pages/LoginPage';
test.describe('Login', () => {
let loginPage: LoginPage;
test.beforeEach(async ({ page }) => {
loginPage = new LoginPage(page);
await loginPage.goto();
});
test('successful login redirects to dashboard', async ({ page }) => {
await loginPage.login('user@example.com', 'correct-password');
await expect(page).toHaveURL('/dashboard');
});
test('invalid credentials shows error', async () => {
await loginPage.login('user@example.com', 'wrong-password');
await expect(loginPage.errorMessage).toBeVisible();
await expect(loginPage.errorMessage).toContainText('Invalid credentials');
});
});
不穩定測試的偵錯工作流程
// 1. 啟用追蹤執行失敗的測試
// playwright.config.ts
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
}
// 2. 使用重試重新執行以擷取追蹤
// npx playwright test --retries=2
// 3. 開啟追蹤檢視器檢查時間軸
// npx playwright show-trace test-results/.../trace.zip
// 4. 常見修正 — 將任意逾時替換為適當的等待
// ❌ 不穩定
await page.waitForTimeout(2000);
await page.getByRole('button', { name: 'Save' }).click();
// ✅ 可靠 — 等待元素狀態
await page.getByRole('button', { name: 'Save' }).waitFor({ state: 'visible' });
await page.getByRole('button', { name: 'Save' }).click();
// 5. 驗證修正 — 執行測試 10 次以確認穩定性
// npx playwright test --repeat-each=10
輸出模板
實作 Playwright 測試時,提供:
- Page Object 類別
- 包含適當斷言的測試檔案
- 必要時的固定裝置設定
- 配置建議
知識參考
Playwright、Page Object Model、自動等待、定位器、固定裝置、API 模擬、追蹤檢視器、視覺比對、平行執行、CI/CD 整合






