Claude-skill-registry-data manage-react-component-tests
Create or update test files for React components. Use when user asks to "create component tests", "test MyComponent", "generate tests for component", "update component tests", or mentions needing tests for a React component. Generates vitest test files with render, mocked sub-components, and proper test structure focusing on logic and prop validation.
git clone https://github.com/majiayu000/claude-skill-registry-data
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry-data "$T" && mkdir -p ~/.claude/skills && cp -r "$T/data/manage-react-component-tests" ~/.claude/skills/majiayu000-claude-skill-registry-data-manage-react-component-tests && rm -rf "$T"
data/manage-react-component-tests/SKILL.mdManage React Component Tests Skill
This skill helps you create or update test files for React components. Tests follow a specific pattern with vitest,
render from React Testing Library, and mocked sub-components to test logic and prop passing in isolation.
When to Use This Skill
Use this skill when you need to:
- Create a new test file for a React component
- Update an existing test file when the component changes
- Generate test coverage for component logic and prop validation
The skill will generate/update:
- A test file with vitest and React Testing Library imports
- Mocked versions of all imported sub-components
- A
helper function usingrenderMyComponentrender - Individual test cases for different component behaviors and prop permutations
Usage
Invoke this skill when the user asks to:
- "Create tests for [MyComponent]"
- "Generate a test file for [MyComponent]"
- "I need tests for [MyComponent]"
- "Update tests for [MyComponent]"
- "The [MyComponent] changed, update its tests"
- "Test [MyComponent]"
Core Principles
Testing Philosophy
- Logic-Focused: Test component logic, not UI appearance
- Prop Validation: Verify sub-components receive correct props
- Isolation: Mock all sub-components to test the component in isolation
- Callback Testing: Simulate callbacks to test handlers
- Unit Testing: Each component has its own tests; dependencies should have separate tests
Prerequisites
Before creating/updating component tests:
- Verify the component exists - The component you're testing must already be defined
- Check for existing test file - Use Glob to search for existing
file.spec.tsx - Identify sub-components - Determine what components are imported and rendered
- Verify @testing-library/react - Ensure it's installed (for
)render
Create vs Update Decision
If test file exists: Update mode
- Read the existing test file
- Read the component definition
- Compare and identify what's missing or outdated
- Update the test to match current implementation
If test file does NOT exist: Create mode
- Read the component definition
- Identify all sub-components to mock
- Generate complete test file from scratch
Test File Location
CRITICAL: Test files MUST be in the
__tests__ folder, which is a SIBLING of the /src folder, NOT inside it.
Directory Structure
packages/ my-package/ src/ components/ MyComponent.tsx __tests__/ # Sibling to src/, NOT inside src/ MyComponent.spec.tsx # .tsx extension for React components
Naming Convention
For a component named
MyComponent:
- Test file:
(matches component name exactly, withMyComponent.spec.tsx
extension).tsx - Located in:
packages/my-package/__tests__/MyComponent.spec.tsx
Test File Structure
1. Imports
Import Rules:
- Import React (required for this project's JSX transform)
- Import vitest utilities from
'vitest' - Import
andrender
fromscreen'@testing-library/react' - Import the component being tested
- DO NOT import sub-components (they will be mocked)
Example:
import React from 'react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen } from '@testing-library/react'; import { MyComponent } from '../src/components/MyComponent';
2. Mocking Sub-Components
All imported sub-components must be mocked to test the component in isolation.
Pattern:
// Mock all sub-component modules vi.mock('../src/components/SubComponentA', () => ({ SubComponentA: vi.fn(() => <div data-testid="mock-sub-component-a">SubComponentA</div>) })); vi.mock('../src/components/SubComponentB', () => ({ SubComponentB: vi.fn(() => <div data-testid="mock-sub-component-b">SubComponentB</div>) }));
Rules:
- Place mocks at the top of the file, after imports
- Use
to create a mock function that returns a simplevi.fn()<div> - Add
for easy querying in testsdata-testid - Mock EVERY component imported by the component under test
3. Main Describe Block
describe('MyComponent', () => { // Helper function function renderMyComponent(props?: Partial<MyComponentProps>) { // ... } // Reset mocks before each test beforeEach(() => { vi.clearAllMocks(); }); // Test cases it('should render sub-components with correct props', () => { // Test... }); });
Structure Rules:
- Main describe uses the component name
- Contains one
helper function at the toprenderMyComponent - Includes
to clear mocksbeforeEach - All test cases use the
helperrenderMyComponent
4. renderMyComponent Helper Function
Purpose: Factory function that renders the component with default or custom props.
Pattern:
function renderMyComponent(props?: Partial<MyComponentProps>) { const defaultProps: MyComponentProps = { title: 'Test Title', onSubmit: vi.fn(), items: [], }; return render(<MyComponent {...defaultProps} {...props} />); }
Rules:
- Accept partial props (optional)
- Define sensible defaults for all required props
- Use
for callback propsvi.fn() - Spread defaults first, then custom props
- Return the result of
render()
5. Testing Sub-Component Props
Access the mock to verify props:
import { SubComponentA } from '../src/components/SubComponentA'; it('should pass correct props to SubComponentA', () => { renderMyComponent({ title: 'My Title', count: 5 }); expect(SubComponentA).toHaveBeenCalledWith( expect.objectContaining({ title: 'My Title', count: 5 }), expect.anything() // React context ); });
Rules:
- Import the mocked component at the top
- Use
expect(MockedComponent).toHaveBeenCalledWith() - Use
to match propsexpect.objectContaining() - Use
as second arg (React context)expect.anything()
6. Testing Callbacks
Simulate callback invocation to test handlers:
it('should call onSubmit when button is clicked', () => { const mockOnSubmit = vi.fn(); const { SubButton } = require('../src/components/SubButton'); renderMyComponent({ onSubmit: mockOnSubmit }); // Get the onClick prop passed to SubButton const onClickProp = SubButton.mock.calls[0][0].onClick; // Simulate the click onClickProp(); expect(mockOnSubmit).toHaveBeenCalled(); });
Rules:
- Pass
as callback propsvi.fn() - Extract callback from mock's call arguments
- Invoke the callback to test the handler
- Assert the handler was called correctly
7. Testing Conditional Rendering
Test different branches:
it('should render ErrorMessage when error prop is provided', () => { const { ErrorMessage } = require('../src/components/ErrorMessage'); renderMyComponent({ error: 'Something went wrong' }); expect(ErrorMessage).toHaveBeenCalledWith( expect.objectContaining({ message: 'Something went wrong' }), expect.anything() ); }); it('should not render ErrorMessage when no error', () => { const { ErrorMessage } = require('../src/components/ErrorMessage'); renderMyComponent({ error: null }); expect(ErrorMessage).not.toHaveBeenCalled(); });
8. Testing Lists and Iterations
Test components rendered in loops:
it('should render ListItem for each item', () => { const { ListItem } = require('../src/components/ListItem'); const items = [ { id: '1', name: 'Item 1' }, { id: '2', name: 'Item 2' }, { id: '3', name: 'Item 3' } ]; renderMyComponent({ items }); expect(ListItem).toHaveBeenCalledTimes(3); expect(ListItem).toHaveBeenNthCalledWith( 1, expect.objectContaining({ id: '1', name: 'Item 1' }), expect.anything() ); expect(ListItem).toHaveBeenNthCalledWith( 2, expect.objectContaining({ id: '2', name: 'Item 2' }), expect.anything() ); expect(ListItem).toHaveBeenNthCalledWith( 3, expect.objectContaining({ id: '3', name: 'Item 3' }), expect.anything() ); });
Workflow
Create Workflow
- Identify the component - Determine which component to test
- Locate the component file - Use Glob to find the component definition
- Read the component - Understand props, sub-components, logic branches
- Identify sub-components - List all imported components to mock
- Ensure
exists - Create folder if needed (sibling to__tests__
)/src - Verify @testing-library/react - Check package.json
- Create test file in
with:__tests__/MyComponent.spec.tsx- All required imports (including React)
- Mock declarations for all sub-components
- Main describe block
helper functionrenderMyComponent
to clear mocksbeforeEach- Test cases covering all scenarios
Update Workflow
- Read existing test and component - Compare current state
- Identify changes:
- New sub-components → Add mocks
- Changed props → Update test cases
- New logic branches → Add test cases
- Removed functionality → Remove tests
- Apply updates using Edit tool - Targeted changes only
- Verify coverage - Ensure all logic branches tested
Update Guidelines
- Preserve structure - Use Edit tool, not Write
- Maintain consistency - Follow existing patterns
- Keep descriptive names - Clear, behavior-focused
- Don't delete passing tests - Only update broken/obsolete tests
- Add missing coverage - Test new logic and props
Best Practices
- Test Logic, Not UI - Focus on props passed and callbacks invoked
- Mock All Sub-Components - Test the component in complete isolation
- Descriptive Test Names - Explain expected behavior clearly
- Clear Mocks Between Tests - Use
withbeforeEachvi.clearAllMocks() - Test All Branches - Cover conditional rendering, loops, error states
- Test Callbacks - Simulate sub-component callbacks to test handlers
- Use expect.objectContaining - Match specific props without over-specifying
Common Pitfalls to Avoid
- ❌ Don't Import Sub-Components Normally - They should be mocked, not imported
- ❌ Don't Forget React Import - Required for JSX in this project
- ❌ Don't Forget beforeEach - Mocks persist between tests
- ❌ Don't Test UI Appearance - Focus on logic and prop passing
- ❌ Don't Skip expect.anything() - It's needed as the second argument for React context
- ❌ Don't Forget to Mock Everything - ALL sub-components must be mocked
Example Reference
See
examples.md in the same directory for complete working examples of:
- Simple component with sub-components
- Component with conditional rendering
- Component with lists and iterations
- Component with callbacks and handlers
- Component with complex prop passing
- Component with multiple branches
Important Notes
File Organization
- Tests in
at package root (sibling to__tests__/
)/src - Use
extension.tsx - Match component name exactly
Dependencies
- Ensure
is installed@testing-library/react - Use
for all sub-componentsvi.mock() - Mock at the module level, not inside tests
Test Quality
- Many small tests > few large tests
- Test happy path and error cases
- Test all conditional branches
- Descriptive test names
- Simple, focused tests
Running Tests
After creating/updating:
- Run
to verify tests passpnpm test - Run
to check lintingpnpm lint - Run
to verify TypeScript compilespnpm build
Mocking Best Practices
- Always use
for mock componentsvi.fn() - Return simple
elements with<div>data-testid - Clear mocks in
beforeEach - Import mocked components when you need to assert on them
- Use
to verify propsexpect.objectContaining()