frontend-react-testing-strategy

Standardized guidelines and patterns for Frontend React Testing Strategy.

16 stars

Best use case

frontend-react-testing-strategy is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Standardized guidelines and patterns for Frontend React Testing Strategy.

Teams using frontend-react-testing-strategy should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/frontend-react-testing-strategy/SKILL.md --create-dirs "https://raw.githubusercontent.com/diegosouzapw/awesome-omni-skill/main/skills/frontend/frontend-react-testing-strategy/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/frontend-react-testing-strategy/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How frontend-react-testing-strategy Compares

Feature / Agentfrontend-react-testing-strategyStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Standardized guidelines and patterns for Frontend React Testing Strategy.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

Related Guides

SKILL.md Source

# Frontend React Testing Strategy

## When to use this skill
- Writing tests for React components
- Setting up testing infrastructure
- Improving test coverage
- Debugging flaky tests
- Code reviews for test quality

## Workflow
- [ ] Choose what to test (behavior, not implementation)
- [ ] Write tests with React Testing Library
- [ ] Follow AAA pattern (Arrange, Act, Assert)
- [ ] Test user interactions, not internals
- [ ] Mock external dependencies

## Instructions

### Testing Philosophy

**Test behavior, not implementation:**
```typescript
// ❌ Bad - testing implementation details
expect(component.state.count).toBe(1);

// ✅ Good - testing user-visible behavior
expect(screen.getByText('Count: 1')).toBeInTheDocument();
```

### Basic Component Test

```typescript
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Button } from './Button';

describe('Button', () => {
  it('renders with correct text', () => {
    render(<Button>Click me</Button>);
    expect(screen.getByRole('button', { name: /click me/i })).toBeInTheDocument();
  });

  it('calls onClick when clicked', async () => {
    const handleClick = jest.fn();
    const user = userEvent.setup();
    
    render(<Button onClick={handleClick}>Click</Button>);
    
    await user.click(screen.getByRole('button'));
    expect(handleClick).toHaveBeenCalledTimes(1);
  });

  it('is disabled when disabled prop is true', () => {
    render(<Button disabled>Click</Button>);
    expect(screen.getByRole('button')).toBeDisabled();
  });
});
```

### Form Testing

```typescript
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { LoginForm } from './LoginForm';

describe('LoginForm', () => {
  it('submits form with email and password', async () => {
    const onSubmit = jest.fn();
    const user = userEvent.setup();
    
    render(<LoginForm onSubmit={onSubmit} />);
    
    // Fill form
    await user.type(screen.getByLabelText(/email/i), 'user@example.com');
    await user.type(screen.getByLabelText(/password/i), 'password123');
    
    // Submit
    await user.click(screen.getByRole('button', { name: /log in/i }));
    
    // Assert
    expect(onSubmit).toHaveBeenCalledWith({
      email: 'user@example.com',
      password: 'password123'
    });
  });

  it('shows validation error for invalid email', async () => {
    const user = userEvent.setup();
    
    render(<LoginForm onSubmit={jest.fn()} />);
    
    await user.type(screen.getByLabelText(/email/i), 'invalid');
    await user.click(screen.getByRole('button', { name: /log in/i }));
    
    expect(await screen.findByText(/invalid email/i)).toBeInTheDocument();
  });
});
```

### Async Testing

```typescript
import { render, screen, waitFor } from '@testing-library/react';
import { UserProfile } from './UserProfile';

// Mock fetch
global.fetch = jest.fn();

describe('UserProfile', () => {
  beforeEach(() => {
    (fetch as jest.Mock).mockClear();
  });

  it('displays user data after loading', async () => {
    (fetch as jest.Mock).mockResolvedValueOnce({
      json: async () => ({ name: 'John Doe', email: 'john@example.com' })
    });

    render(<UserProfile userId="123" />);

    // Initially loading
    expect(screen.getByText(/loading/i)).toBeInTheDocument();

    // Wait for data
    await waitFor(() => {
      expect(screen.getByText('John Doe')).toBeInTheDocument();
    });

    expect(screen.getByText('john@example.com')).toBeInTheDocument();
  });

  it('displays error message on fetch failure', async () => {
    (fetch as jest.Mock).mockRejectedValueOnce(new Error('Failed'));

    render(<UserProfile userId="123" />);

    expect(await screen.findByText(/error/i)).toBeInTheDocument();
  });
});
```

### Hook Testing

```typescript
import { renderHook, waitFor } from '@testing-library/react';
import { useUser } from './useUser';

// Mock API
jest.mock('./api', () => ({
  fetchUser: jest.fn()
}));

import { fetchUser } from './api';

describe('useUser', () => {
  it('fetches user data', async () => {
    (fetchUser as jest.Mock).mockResolvedValue({
      id: '1',
      name: 'John'
    });

    const { result } = renderHook(() => useUser('1'));

    expect(result.current.isLoading).toBe(true);

    await waitFor(() => {
      expect(result.current.isLoading).toBe(false);
    });

    expect(result.current.data).toEqual({ id: '1', name: 'John' });
  });

  it('refetches data when called', async () => {
    (fetchUser as jest.Mock).mockResolvedValue({ id: '1', name: 'John' });

    const { result } = renderHook(() => useUser('1'));

    await waitFor(() => {
      expect(result.current.data).toBeTruthy();
    });

    (fetchUser as jest.Mock).mockResolvedValue({ id: '1', name: 'Jane' });

    result.current.refetch();

    await waitFor(() => {
      expect(result.current.data?.name).toBe('Jane');
    });
  });
});
```

### Mocking Context

```typescript
import { render, screen } from '@testing-library/react';
import { AuthContext } from './AuthContext';
import { ProtectedRoute } from './ProtectedRoute';

const renderWithAuth = (component: React.ReactElement, isAuthenticated = false) => {
  return render(
    <AuthContext.Provider value={{ isAuthenticated, user: null }}>
      {component}
    </AuthContext.Provider>
  );
};

describe('ProtectedRoute', () => {
  it('shows content when authenticated', () => {
    renderWithAuth(<ProtectedRoute>Secret</ProtectedRoute>, true);
    expect(screen.getByText('Secret')).toBeInTheDocument();
  });

  it('redirects when not authenticated', () => {
    renderWithAuth(<ProtectedRoute>Secret</ProtectedRoute>, false);
    expect(screen.getByText(/login/i)).toBeInTheDocument();
  });
});
```

### Query Priority

```typescript
// Priority order (use the highest you can):
// 1. getByRole
expect(screen.getByRole('button', { name: /submit/i }));

// 2. getByLabelText (forms)
expect(screen.getByLabelText(/email/i));

// 3. getByPlaceholderText
expect(screen.getByPlaceholderText(/enter email/i));

// 4. getByText
expect(screen.getByText(/welcome/i));

// 5. getByTestId (last resort)
expect(screen.getByTestId('custom-element'));
```

### Snapshot Testing (Use Sparingly)

```typescript
import { render } from '@testing-library/react';
import { Card } from './Card';

it('matches snapshot', () => {
  const { container } = render(
    <Card title="Test" description="Description" />
  );
  expect(container).toMatchSnapshot();
});
```

## Resources
- Use React Testing Library, not Enzyme
- Query by role/label, not test IDs
- Test user behavior, not component state
- Mock network requests
- Use `userEvent` over `fireEvent`

Related Skills

web-testing

16
from diegosouzapw/awesome-omni-skill

Playwright automation, Chrome DevTools debugging, and browser interaction testing. Use for E2E/unit tests, capturing screenshots, inspecting network/console logs, or validating user flows in web applications.

qa-testing-mobile

16
from diegosouzapw/awesome-omni-skill

Mobile app testing strategy and execution for iOS and Android (native + cross-platform): choose automation frameworks, define device matrix, control flakes, validate performance/reliability/accessibility, and set CI + release gates. Use when you need a mobile QA plan, device lab/CI setup, or guidance on XCUITest/Espresso/Appium/Detox/Maestro/Flutter testing.

anthropic-webapp-testing

16
from diegosouzapw/awesome-omni-skill

Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

anthropic-web-testing

16
from diegosouzapw/awesome-omni-skill

Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.

starknet-react-rules

16
from diegosouzapw/awesome-omni-skill

Specific rules for Starknet React projects, focusing on blockchain integration.

ring:dev-refactor-frontend

16
from diegosouzapw/awesome-omni-skill

Analyzes frontend codebase against Ring standards and generates refactoring tasks for ring:dev-cycle-frontend. Dispatches frontend-specific agents in ANALYSIS mode.

react

16
from diegosouzapw/awesome-omni-skill

React development patterns and best practices including hooks, state management, and performance optimization.

react-fluent-ui-patterns

16
from diegosouzapw/awesome-omni-skill

Skill for React TypeScript frontend development with Fluent UI Copilot components. Use when creating UI components, handling SSE streams, working with chat interfaces, or implementing theme support.

rcr-frontend

16
from diegosouzapw/awesome-omni-skill

Component development rules specific to Red Cliff Record. Use when working with React components, Tailwind CSS styling, Radix/Shadcn primitives, icons, buttons, forms, or frontend code in this project. Triggers on component files, styling questions, design tokens, Tailwind v4, Shadcn, Radix, TanStack Forms, Lucide icons, or UI primitive usage patterns (sizing, spacing, layout).

nextjs15-react19-vercelai-tailwind-cursorrules-prompt-file-cursorrules

16
from diegosouzapw/awesome-omni-skill

Apply for nextjs15-react19-vercelai-tailwind-cursorrules-prompt-file. --- description: Best practices for using Tailwind CSS in Next.js 15 and React 19 applications, including responsive design, custom configurations, and performance optimization. globs: app/**/*

moai-domain-frontend

16
from diegosouzapw/awesome-omni-skill

Frontend development specialist covering React 19, Next.js 16, Vue 3.5, and modern UI/UX patterns with component architecture. Use when building web UIs, implementing components, optimizing frontend performance, or integrating state management.

Frontend Verification & Testing

16
from diegosouzapw/awesome-omni-skill

Verify and test Angular 18 frontend changes using Chrome DevTools MCP. Automatically check console errors, network requests, and visual rendering after implementing tasks or when fixing UI bugs. Use when creating components, debugging visual issues, validating API integration, or ensuring UI requirements are met. File types: .ts, .html, .css, .scss