frontend-testing-best-practices — Claude Code skill
A set of 6 testing guidelines that prioritizes Playwright E2E workflows over isolated React component tests and heavy mocking.
npx skills add sergiodxa/agent-skills --skill frontend-testing-best-practices -a claude-codeWhat frontend-testing-best-practices does
This skill guides your coding agent toward testing user behavior instead of internal implementation details. It prioritizes end-to-end tests for full application flows and strictly discourages isolated React component unit tests. Pure functions like formatters remain the only acceptable target for unit tests in Vitest.
The skill sets specific conventions for file layout and element targeting. All E2E files belong in e2e/tests/, while unit tests sit right next to their source files. When interacting with elements, the agent must pick accessible selectors such as getByRole or getByLabel, avoiding brittle CSS classes.
Whenever a unit test demands three or more mocks, the rules require replacing it with an E2E test. That makes mock-heavy component testing unacceptable under this configuration.
What it helps with
- structure Playwright E2E tests for user journeys
- eliminate brittle CSS selectors in browser tests
- replace complex mock setups with end-to-end tests
- isolate pure utility functions for Vitest unit testing
Example prompts for the agent
- Write an E2E checkout test following the frontend-testing-best-practices rules
- Review this component test and convert it into an E2E spec if needed
- Refactor these tests to use accessible role selectors instead of CSS classes
How to install frontend-testing-best-practices
1Skills CLI (Vercel)
npx skills add sergiodxa/agent-skills --skill frontend-testing-best-practices -a claude-code2Manually: put the files in place
~/.claude/skills/frontend-testing-best-practices/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/frontend-testing-best-practices/
1Skills CLI (Vercel)
npx skills add sergiodxa/agent-skills --skill frontend-testing-best-practices -a codex2Manually: put the files in place
.agents/skills/frontend-testing-best-practices/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add sergiodxa/agent-skills --skill frontend-testing-best-practices -a cursor2Manually: put the files in place
.cursor/skills/frontend-testing-best-practices/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install sergiodxa/agent-skills frontend-testing-best-practices2Manually: put the files in place
.github/skills/frontend-testing-best-practices/SKILL.md1Skills CLI (Vercel)
npx skills add sergiodxa/agent-skills --skill frontend-testing-best-practices -a gemini-cli2Platform CLI
gemini skills install https://github.com/sergiodxa/agent-skills --path skills/frontend-testing-best-practicesManually: put the files in place
.devin/skills/frontend-testing-best-practices/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add sergiodxa/agent-skills --skill frontend-testing-best-practices -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about frontend-testing-best-practices
How do I install frontend-testing-best-practices in Claude Code?
Run npx skills add sergiodxa/agent-skills --skill frontend-testing-best-practices -a claude-code. The skill file will be placed in ~/.claude/skills/frontend-testing-best-practices/SKILL.md.
What is the core philosophy of frontend-testing-best-practices?
It prioritizes full-system E2E testing over unit tests, focuses on visible behavior rather than implementation, and avoids testing React components directly.
When does the skill allow mocking?
It keeps mocks minimal, such as simple HTTP handlers via MSW. If a test requires three or more mocks, the guidelines instruct you to write an E2E test instead.
Source text
SKILL.md · MIT
---
name: frontend-testing-best-practices
description: Testing best practices for the frontend. Emphasizes E2E tests over unit tests, minimal mocking, and testing behavior over implementation details. Use when writing tests or reviewing test code.
---
# 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
1. **Prefer E2E tests over unit tests** - Test the whole system, not isolated pieces
2. **Minimize mocking** - If you need complex mocks, write an E2E test instead
3. **Test behavior, not implementation** - Test what users see and do
4. **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.
```typescript
// E2E test (PREFERRED) - tests real user flow
test("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 functions
test("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.
```typescript
// BAD: Component unit test
describe("OrderCard", () => {
test("renders amount", () => {
render(<OrderCard amount={100} />);
expect(screen.getByText("$100")).toBeInTheDocument();
});
});
// GOOD: E2E test covers the component naturally
test("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.
```typescript
// BAD: Too many mocks = write E2E test
vi.mock("~/lib/auth");
vi.mock("~/lib/transactions");
vi.mock("~/hooks/useAccount");
// GOOD: Simple MSW mock for loader test
mockServer.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/`.
```typescript
// e2e/tests/order.spec.ts
import { 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.
```typescript
// GOOD: Role-based (preferred)
await page.getByRole("button", { name: "Submit" }).click();
await page.getByRole("heading", { name: "Dashboard" });
// GOOD: Label-based
await page.getByLabel("Email").fill("[email protected]");
// OK: Test ID when no accessible selector exists
await expect(page.getByTestId("balance")).toHaveText("$1,234");
// BAD: CSS selectors
await 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.
```typescript
// app/utils/format.test.ts
import { 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 utilities
- `vitest.config.ts` - Unit test configuration
- `vitest.setup.ts` - Global test setup with MSW
- `app/utils/test-utils.ts` - Unit test utilities
© sergiodxa · MIT · sergiodxa/agent-skills