
Frontend Testing Best Practices
Steer React testing toward high-confidence E2E user flows instead of brittle component unit tests that break on refactors.
Overview
Frontend Testing Best Practices is an agent skill most often used in Ship (also Build frontend) that steers React teams away from isolated component unit tests toward E2E user-flow coverage.
Install
npx skills add https://github.com/sergiodxa/agent-skills --skill frontend-testing-best-practicesWhat is this skill?
- HIGH impact guidance: avoid testing React components in isolation
- Explains why component tests chase implementation details and heavy provider mocking
- Contrasts bad @testing-library unit examples with good E2E coverage of real user flows
- Frames component rendering correctness as React’s responsibility, not test suite bloat
- Tagged for testing, react, and components discovery
- Documented impact level: HIGH
- Covers bad vs good patterns with TypeScript Testing Library and E2E examples
Adoption & trust: 1.7k installs on skills.sh; 87 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your React component unit tests break on harmless refactors and mock half the app without proving the feature works for users.
Who is it for?
Solo builders on React or Next apps who are rewriting test pyramids or deleting noisy component specs.
Skip if: Teams that must enforce granular unit coverage for compliance, or non-React stacks where the anti-patterns do not apply.
When should I use this skill?
When choosing or refactoring React frontend test strategy toward E2E confidence.
What do I get? / Deliverables
You adopt a testing strategy that prioritizes E2E flows and drops low-value isolation tests, reducing maintenance while increasing release confidence.
- Test strategy aligned to E2E user flows
- Reduced component isolation test surface
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Primary shelf is Ship/testing because the skill governs how you validate UI behavior before release. Testing subphase is where frontend verification strategy is chosen—unit vs integration vs E2E.
Where it fits
Decide to delete OrderCard unit specs and cover checkout via one E2E path.
Set team convention on new screens: no isolated render tests, only flow-level coverage.
Flag PRs that add prop-level component tests without user-visible behavior assertions.
How it compares
Opinionated testing philosophy skill—not a Playwright/Cypress installer or a test generator.
Common Questions / FAQ
Who is frontend-testing-best-practices for?
Indie developers and small teams building React UIs who want practical guidance on what not to unit test.
When should I use frontend-testing-best-practices?
During Ship testing when choosing E2E vs component tests, and during Build frontend when scaffolding a new app’s test approach.
Is frontend-testing-best-practices safe to install?
It is documentation-only procedural knowledge with no runtime permissions; still review the Security Audits panel on this page for the package source.
SKILL.md
READMESKILL.md - Frontend Testing Best Practices
# Avoid Testing React Components in Isolation Don't write unit tests for React components. Test them through E2E tests or not at all. ## Why - Component tests often test implementation details - They break when you refactor without changing behavior - They require complex mocking (context, hooks, providers) - They don't provide confidence that the feature actually works - E2E tests cover components naturally as part of user flows ## Bad: Component Unit Tests ```typescript // BAD: Testing component rendering import { render, screen } from "@testing-library/react"; import { OrderCard } from "./order-card"; describe("OrderCard", () => { test("renders order amount", () => { render(<OrderCard amount={100} itemName="Example Item" />); expect(screen.getByText("$100")).toBeInTheDocument(); expect(screen.getByText("Red Cross")).toBeInTheDocument(); }); test("shows pending state", () => { render(<OrderCard amount={100} itemName="Example Item" status="pending" />); expect(screen.getByText("Pending")).toBeInTheDocument(); }); }); ``` Why this is bad: - Tests that props render correctly - this is React's job - Doesn't test that the component works in context - Will break if you rename props or restructure JSX - Mocking providers is tedious and error-prone ## Good: E2E Test That Covers the Component ```typescript // GOOD: E2E test that naturally tests OrderCard import { test, expect } from "@playwright/test"; test("order history shows pending orders", async ({ page }) => { // Create a pending order via API or test setup await createTestOrder({ status: "pending" }); await page.goto("/orders"); // The OrderCard component is tested implicitly await expect(page.getByText("$100")).toBeVisible(); await expect(page.getByText("Example Item")).toBeVisible(); await expect(page.getByText("Pending")).toBeVisible(); }); ``` ## When Component Tests Might Be Acceptable Only consider component tests for: 1. **Highly reusable UI library components** (Button, Input, Modal) - But even then, prefer visual regression tests or Storybook 2. **Complex isolated logic** (but extract it to a hook and test that) ```typescript // ACCEPTABLE: Testing a reusable Badge component variants // But only if it's a shared UI component used everywhere describe(Badge.name, () => { test('renders the "success" variant classes', () => { render(<Badge variant="success">Text</Badge>); expect(screen.getByText("Text")).toHaveClass("bg-success-100"); }); }); ``` ## Extract Logic to Testable Hooks If a component has complex logic, extract it: ```typescript // BAD: Complex logic in component, tested via component test function OrderForm() { let [amount, setAmount] = useState(0); let [fee, setFee] = useState(0); useEffect(() => { // Complex fee calculation let baseFee = amount * 0.029 + 0.3; let adjustedFee = amount > 1000 ? baseFee * 0.9 : baseFee; setFee(adjustedFee); }, [amount]); // ... } // GOOD: Extract logic to hook, test the hook function useOrderFee(amount: number) { return useMemo(() => { let baseFee = amount * 0.029 + 0.3; return amount > 1000 ? baseFee * 0.9 : baseFee; }, [amount]); } // Or even better: pure function function calculateOrderFee(amount: number): number { let baseFee = amount * 0.029 + 0.3; return amount > 1000 ? baseFee * 0.9 : baseFee; } // Test the pure function describe("calculateOrderFee", () => { test("calculates standard fee", () => { expect(calculateOrderFee(100)).toBe(3.2); }); test("applies discount for large orders", () => { expect(calculateOrderFee(2000)).toBe(52.47); }); }); ``` ## Rules 1. Don't write unit tests for React components 2. Test components through E2E tests as part of user flows 3. If component has complex logic, extract to a hook or pure function 4. UI library components can have minimal va