frontend-testing-best-practices
sergiodxa/agent-skills
前端測試的最佳實務。強調端到端(E2E)測試優於單元測試、盡量減少模擬(mocking),並著重測試行為而非實作細節。適用於撰寫測試或審查測試程式碼時。
...展開全部關於frontend-testing-best-practices
「frontend-testing-best-practices 」技能提供了一套全面的指引,協助開發者為前端應用程式編寫有效且易於維護的測試。該技能針對測試常出現的常見問題——例如測試易碎、難以維護,以及因過度關注實作細節而非使用者行為而產生虛假信心——提供了解決方案。 這項技能強調一種理念:優先進行端到端(E2E)測試而非單元測試、盡量減少模擬(mocking),並著重測試行為而非實作細節。
本技能包含 6 條核心規則,分為三大類別:測試策略(關鍵級別)、端到端測試(高優先級)以及單元測試(中優先級)。 關鍵能力包括:何時應撰寫端到端測試而非單元測試、如何將端到端測試結構化並放置於正確的目錄中、在 Playwright 測試中使用可存取選擇器的最佳實踐、避免進行 React 元件單元測試,以及保持模擬物件的簡潔性。這些規則透過實用的程式碼範例,比較優劣做法,使相關指引能立即付諸實踐。
這項技能非常適合從事網頁應用程式開發的前端開發者,特別是需要做出測試決策、編寫新測試或審查測試程式碼的開發者。 對於使用 Playwright 進行端到端測試,並採用 React 開發 UI 元件的團隊而言,這項技能尤為寶貴。當您需要決定撰寫何種測試、實作新的測試覆蓋率、重構現有測試,或對測試檔案進行程式碼審查時,皆可運用此技能。這些指引能協助團隊避免常見的測試反模式,並建構出能讓人對應用程式行為真正充滿信心的測試套件。
常見問題
何時該編寫單元測試,何時該編寫端到端測試?
在大多數情況下,應以端到端測試為預設選擇。僅針對無依賴性且執行孤立邏輯(如資料格式化或計算)的純函式撰寫單元測試。若您要測試任何涉及 React 元件、API 呼叫或使用者互動的內容,請改為撰寫端到端測試。
本技能假設使用哪種測試框架?
本技能使用 Playwright 進行端到端測試範例,並參考 MSW(Mock Service Worker)進行 API 模擬。React 元件範例建議採用 JavaScript/TypeScript 前端技術堆疊,但核心原則適用於任何前端框架。
在單一測試中,多少個模擬對象才算過多?
若單一測試中需要 3 個或更多模擬物件,這便表示應改寫端到端測試。簡單的模擬(例如針對 API 端點的單一 MSW 處理程序)尚可接受,但複雜的模擬設定則表示您應測試實際的整合系統。
端到端測試應放置在專案的哪個位置?
端到端測試應放置於專案根目錄下的 `e2e/tests/` 目錄中,而非 `frontend/` 目錄內。這樣能將其與單元測試區隔開來,並明確顯示這些測試是針對整個系統進行的。
在 Playwright 測試中應採用何種選擇器策略?
請遵循以下優先順序:優先使用基於角色的選擇器(getByRole),其次是基於標籤的選擇器(getByLabel),接著是文字內容,最後僅在沒有可用的選擇器時才使用測試 ID(getByTestId)。請避免使用 CSS 選擇器,因為它們不穩定且無法反映使用者與應用程式互動的方式。
Testing Best Practices
Guidelines for writing effective, maintainable tests that provide real confidence. Contains 6 rules focused on preferring E2E tests, minimizing mocking, and testing behavior over implementation.
Core Philosophy
- Prefer E2E tests over unit tests - Test the whole system, not isolated pieces
- Minimize mocking - If you need complex mocks, write an E2E test instead
- Test behavior, not implementation - Test what users see and do
- Avoid testing React components directly - Test them through E2E
When to Apply
Reference these guidelines when:
- Deciding what type of test to write
- Writing new E2E or unit tests
- Reviewing test code
- Refactoring tests
Rules Summary
Testing Strategy (CRITICAL)
prefer-e2e-tests - @rules/prefer-e2e-tests.md
Default to E2E tests. Only write unit tests for pure functions.
// E2E test (PREFERRED) - tests real user flowtest("user can place an order", async ({ page }) => { await createTestingAccount(page, { account_status: "active" }); await page.goto("/catalog"); await page.getByRole("heading", { name: "Example Item" }).click(); await page.getByRole("link", { name: "Buy" }).click(); // ... complete flow await expect(page.getByAltText("Thank you")).toBeVisible();});// Unit test - ONLY for pure functionstest("formatCurrency formats with two decimals", () => { expect(formatCurrency(1234.5)).toBe("$1,234.50");});
avoid-component-tests - @rules/avoid-component-tests.md
Don't unit test React components. Test them through E2E or not at all.
// BAD: Component unit testdescribe("OrderCard", () => { test("renders amount", () => { render(<OrderCard amount={100} />); expect(screen.getByText("$100")).toBeInTheDocument(); });});// GOOD: E2E test covers the component naturallytest("order history shows orders", async ({ page }) => { await page.goto("/orders"); await expect(page.getByText("$100")).toBeVisible();});
minimize-mocking - @rules/minimize-mocking.md
Keep mocks simple. If you need 3+ mocks, write an E2E test instead.
// BAD: Too many mocks = write E2E testvi.mock("~/lib/auth");vi.mock("~/lib/transactions");vi.mock("~/hooks/useAccount");// GOOD: Simple MSW mock for loader testmockServer.use( http.get("/api/user", () => HttpResponse.json({ name: "John" })),);
E2E Tests (HIGH)
e2e-test-structure - @rules/e2e-test-structure.md
E2E tests go in e2e/tests/, not frontend/.
// e2e/tests/order.spec.tsimport { test, expect } from "@playwright/test";import { addAccountBalance, createTestingAccount } from "./utils";test.describe("Orders", () => { test.beforeEach(async ({ page, context }) => { await createTestingAccount(page, { account_status: "active" }); let cookies = await context.cookies(); let account_id = cookies.find((c) => c.name === "account_id").value; await addAccountBalance({ account_id, amount: 10000, replaceBalance: true }); }); test("place order with default values", async ({ page }) => { await page.goto("/catalog"); // ... user flow });});
e2e-selectors - @rules/e2e-selectors.md
Use accessible selectors: role > label > text > testid.
// GOOD: Role-based (preferred)await page.getByRole("button", { name: "Submit" }).click();await page.getByRole("heading", { name: "Dashboard" });// GOOD: Label-basedawait page.getByLabel("Email").fill("[email protected]");// OK: Test ID when no accessible selector existsawait expect(page.getByTestId("balance")).toHaveText("$1,234");// BAD: CSS selectorsawait page.locator(".btn-primary").click();
Unit Tests (MEDIUM)
unit-test-structure - @rules/unit-test-structure.md
Unit tests for pure functions only. Co-locate with source files.
// app/utils/format.test.tsimport { describe, test, expect } from "vitest";import { formatCurrency } from "./format";describe("formatCurrency", () => { test("formats positive amounts", () => { expect(formatCurrency(1234.5)).toBe("$1,234.50"); }); test("handles zero", () => { expect(formatCurrency(0)).toBe("$0.00"); });});
Key Files
e2e/tests/- E2E tests (Playwright)e2e/tests/utils.ts- E2E test utilitiesvitest.config.ts- Unit test configurationvitest.setup.ts- Global test setup with MSWapp/utils/test-utils.ts- Unit test utilities
所有檔案
7 個檔案安裝 frontend-testing-best-practices
請下載並將技能檔案解壓縮至您的 .claude/skills/ 目錄中。
下載 ZIP複製儲存庫並將技能檔案複製到您的專案中。
git clone https://github.com/sergiodxa/agent-skills/blob/main/skills/frontend-testing-best-practices/SKILL.md # Copy SKILL.md to your .claude/skills/ directory
複製





首頁
