All skills
jeffallan avatar

/react-expert

@efebc44
by jeffallanjeffallan/claude-skills12k stars
1,124

Use when building React 18+ applications in .jsx or .tsx files, Next.js App Router projects, or create-react-app setups. Creates components, implements custom hooks, debugs rendering issues, migrates class components to functional, and implements state management. Invoke for Server Components, Suspense boundaries, useActionState forms, performance optimization, or React 19 features.

Use this Skill: https://skilld.dev/gh/jeffallan/claude-skills/react-expert

This session only. Nothing lands on disk.

referencestesting-react.md

≈1k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Testing React

Basic Component Test

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

test('renders greeting', () => {
  render(<Greeting name="World" />);
  expect(screen.getByText('Hello, World!')).toBeInTheDocument();
});

test('increments counter on click', async () => {
  const user = userEvent.setup();
  render(<Counter />);

  await user.click(screen.getByRole('button', { name: /increment/i }));

  expect(screen.getByText('1')).toBeInTheDocument();
});

Query Priority

// Preferred: Accessible queries (how users find elements)
screen.getByRole('button', { name: /submit/i });
screen.getByLabelText('Email');
screen.getByPlaceholderText('Search...');
screen.getByText('Welcome');

// Fallback: Test IDs (when no accessible name)
screen.getByTestId('custom-element');

// Async queries (wait for element)
await screen.findByText('Loading complete');

Testing Forms

test('submits form with user data', async () => {
  const handleSubmit = vi.fn();
  const user = userEvent.setup();

  render(<ContactForm onSubmit={handleSubmit} />);

  await user.type(screen.getByLabelText('Name'), 'John Doe');
  await user.type(screen.getByLabelText('Email'), 'john@example.com');
  await user.selectOptions(screen.getByLabelText('Topic'), 'support');
  await user.click(screen.getByRole('button', { name: /submit/i }));

  expect(handleSubmit).toHaveBeenCalledWith({
    name: 'John Doe',
    email: 'john@example.com',
    topic: 'support',
  });
});

Testing with Providers

function renderWithProviders(
  ui: React.ReactElement,
  { initialState = {}, ...options } = {}
) {
  function Wrapper({ children }: { children: React.ReactNode }) {
    return (
      <QueryClientProvider client={queryClient}>
        <ThemeProvider>
          {children}
        </ThemeProvider>
      </QueryClientProvider>
    );
  }

  return render(ui, { wrapper: Wrapper, ...options });
}

test('displays user data', async () => {
  renderWithProviders(<UserProfile userId="123" />);

  await screen.findByText('John Doe');
});

Mocking API Calls

import { http, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';

const server = setupServer(
  http.get('/api/users/:id', ({ params }) => {
    return HttpResponse.json({ id: params.id, name: 'John' });
  })
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

test('fetches and displays user', async () => {
  render(<UserProfile userId="123" />);

  await screen.findByText('John');
});

test('handles error', async () => {
  server.use(
    http.get('/api/users/:id', () => {
      return new HttpResponse(null, { status: 500 });
    })
  );

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

  await screen.findByText('Error loading user');
});

Testing Hooks

import { renderHook, act } from '@testing-library/react';

test('useCounter increments', () => {
  const { result } = renderHook(() => useCounter());

  act(() => {
    result.current.increment();
  });

  expect(result.current.count).toBe(1);
});

test('useDebounce delays value', async () => {
  vi.useFakeTimers();

  const { result, rerender } = renderHook(
    ({ value }) => useDebounce(value, 500),
    { initialProps: { value: 'initial' } }
  );

  rerender({ value: 'updated' });
  expect(result.current).toBe('initial');

  await act(async () => {
    vi.advanceTimersByTime(500);
  });

  expect(result.current).toBe('updated');
  vi.useRealTimers();
});

Quick Reference

Query Use When
getByRole Buttons, links, headings
getByLabelText Form inputs
getByText Non-interactive text
findByX Async/loading content
queryByX Assert NOT present
Pattern Use Case
userEvent.setup() User interactions
renderHook() Testing custom hooks
msw Mocking API calls
Custom render Wrap with providers

Source: SKILL.md on GitHub

1 alert16d5 checks · Risk CRITICAL
  • Gen Agent Trust Hub16d

    This skill references a blacklisted URL and its primary instruction file has been flagged by automated security scanners for malicious reputation. It also contains instructions for the agent to execute shell commands for type validation, which poses a risk if the instructions themselves are compromised.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    8 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at efebc44. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 5 months ago
Other metadata
metadata
{
  "author": "https://github.com/Jeffallan",
  "version": "1.1.0",
  "domain": "frontend",
  "triggers": "React, JSX, hooks, useState, useEffect, useContext, Server Components, React 19, Suspense, TanStack Query, Redux, Zustand, component, frontend",
  "role": "specialist",
  "scope": "implementation",
  "output-format": "code",
  "related-skills": "fullstack-guardian, playwright-expert, test-master"
}

README badge

README badge for jeffallan/claude-skills/react-expert