Claude-skill-registry-data manage-react-hook-tests
Create or update test files for React hooks. Use when user asks to "create hook tests", "test useMyHook", "generate tests for hook", "update hook tests", or mentions needing tests for a React hook. Generates vitest test files with renderHook, Fake context providers, and proper test structure.
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-hook-tests" ~/.claude/skills/majiayu000-claude-skill-registry-data-manage-react-hook-tests && rm -rf "$T"
data/manage-react-hook-tests/SKILL.mdManage React Hook Tests Skill
This skill helps you create or update test files for React hooks. Tests follow a specific pattern with vitest,
renderHook from React Testing Library, and Fake context providers for controlled testing.
When to Use This Skill
Use this skill when you need to:
- Create a new test file for a React hook
- Update an existing test file when the hook changes
- Generate test coverage for hook logic and return values
The skill will generate/update:
- A test file with vitest and React Testing Library imports
- A
helper function usingrenderMyHookrenderHook - Individual test cases for different hook behaviors and branches
- Proper setup with Fake context providers when needed
Usage
Invoke this skill when the user asks to:
- "Create tests for [useMyHook]"
- "Generate a test file for [useMyHook]"
- "I need tests for [useMyHook]"
- "Update tests for [useMyHook]"
- "The [useMyHook] changed, update its tests"
- "Test [useMyHook]"
Core Principles
Testing Philosophy
- Hook-Driven: Test the hook's behavior, return values, and side effects
- Context Isolation: Use Fake context providers to isolate the hook from external dependencies
- Controlled Testing: Use Fake builders to control all dependencies and return values
- Single Responsibility: Each
block should test one specific scenarioit - Avoid vi.mock for Internal: Use Fakes for internal dependencies; only use
for external librariesvi.mock
Prerequisites
Before creating/updating hook tests:
- Verify the hook exists - The hook you're testing must already be defined
- Check for existing test file - Use Glob to search for existing
file.spec.tsx - Identify hook dependencies - Determine what contexts or other hooks it uses
- Locate Fake providers - Find available Fake context providers (usually in the same package under
)/fakes - Check for @testing-library/react - Verify that
is installed (for@testing-library/react
)renderHook
Create vs Update Decision
If test file exists: Update mode
- Read the existing test file
- Read the hook 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 hook definition
- Identify all dependencies and context requirements
- 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/ hooks/ useMyHook.ts __tests__/ # Sibling to src/, NOT inside src/ useMyHook.spec.tsx # .tsx extension for React components
Naming Convention
For a hook named
useMyHook:
- Test file:
(matches hook name exactly, withuseMyHook.spec.tsx
extension).tsx - Located in:
packages/my-package/__tests__/useMyHook.spec.tsx
Test File Structure
1. Imports
Import Rules:
- Import React (required for this project's JSX transform)
- Import vitest utilities from
'vitest' - Import
(andrenderHook
if needed) fromact'@testing-library/react' - Import the hook being tested
- Import Fake context providers from
subpath/fakes - Import Fake builders for services/dependencies when needed
Example:
import React from 'react'; import { describe, it, expect, vi } from 'vitest'; import { renderHook, act } from '@testing-library/react'; import { useMyHook } from '../src/hooks/useMyHook'; import { FakeMyContextProvider } from '../fakes'; import { FakeServiceBuilder } from '@someScope/some-library/fakes'; import type { IService } from '@someScope/some-library';
2. Main Describe Block
describe('useMyHook', () => { // Helper function function renderMyHook(/* overrides */): { /* return type */ } { // ... } // Test cases it('should return initial state', () => { // Test... }); });
Structure Rules:
- Main describe uses the hook name (e.g.,
)'useMyHook' - Contains one
helper function at the toprenderMyHook - All test cases use the
helperrenderMyHook - Tests cover all branches and return values
3. renderMyHook Helper Function
Purpose: Factory function that renders the hook with all necessary context providers and dependencies, allowing for easy overrides in tests.
Pattern with Context:
function renderMyHook(overrides?: { service?: IService; }) { const service = overrides?.service ?? new FakeServiceBuilder().build(); const hookRenderResult = renderHook(() => useMyHook(), { wrapper: ({ children }) => ( <FakeMyContextProvider service={service}> {children} </FakeMyContextProvider> ), }); return { hookRenderResult, service, }; }
Pattern without Context:
function renderMyHook(params?: { initialValue?: string; }) { const hookRenderResult = renderHook(() => useMyHook(params?.initialValue ?? 'default')); return { hookRenderResult, }; }
Rules:
- Accept
parameter for context dependenciesoverrides - Accept
parameter for hook argumentsparams - Use nullish coalescing (
) for default Fake instances?? - Use
withrenderHook
option for context providerswrapper - Return object with
and all dependencieshookRenderResult
4. Finding Context Dependencies
How to Identify:
- Read the hook file and look for
calls or other context hooksuseContext - Search for the context provider in the codebase
- Check if a Fake version exists in
folder/fakes - If no Fake exists, create one or use
for external dependenciesvi.mock
Multiple Contexts: Nest providers in the wrapper:
wrapper: ({ children }) => ( <FakeContextA> <FakeContextB> {children} </FakeContextB> </FakeContextA> )
5. Writing Test Cases
Structure:
- Use descriptive test names explaining the expected behavior
- Follow Arrange-Act-Assert pattern
- Access hook result via
hookRenderResult.result.current - Use
for state updatesact() - Use
for async operationsawait act(async () => ...)
Example:
it('should return expected value', () => { const { hookRenderResult } = renderMyHook({ service: new FakeServiceBuilder() .withGetDataReturnValue({ id: '123' }) .build() }); expect(hookRenderResult.result.current.data).toEqual({ id: '123' }); });
6. Testing State Updates
Always wrap state changes in
act():
it('should update state when action is called', () => { const { hookRenderResult } = renderMyHook(); act(() => { hookRenderResult.result.current.updateValue('new value'); }); expect(hookRenderResult.result.current.value).toBe('new value'); });
7. Testing Async Operations
Use
await act(async () => ...):
it('should save successfully', async () => { const { hookRenderResult } = renderMyHook(); await act(async () => { await hookRenderResult.result.current.save(); }); expect(hookRenderResult.result.current.isSaving).toBe(false); });
8. Mocking Dependencies
Preferred (Fake Providers):
const { hookRenderResult } = renderMyHook({ service: new FakeServiceBuilder() .withFetchDataReturnValue(Promise.resolve({ success: true })) .build() });
When to use vi.mock:
- External React hooks from 3rd party libraries
- Browser APIs
- Modules without Fake implementations
Workflow
Create Workflow
- Identify the hook - Determine which hook to test
- Locate the hook file - Use Glob to find the hook definition
- Read the hook - Understand behavior, return values, context usage
- Identify dependencies - Look for context hooks and other dependencies
- Locate Fakes - Find Fake providers and builders
- Ensure
exists - Create folder if needed (sibling to__tests__
)/src - Verify @testing-library/react - Check package.json
- Create test file in
with:__tests__/useMyHook.spec.tsx- All required imports (including React)
- Main describe block
helper functionrenderMyHook- Test cases covering all scenarios
Update Workflow
- Read existing test and hook - Compare current state
- Identify changes:
- New return values → Add test cases
- Changed logic → Update test cases
- New dependencies → Update
and importsrenderMyHook - 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
Best Practices
- Test Behavior, Not Implementation - Focus on return values and side effects
- Descriptive Test Names - Explain expected behavior clearly
- Arrange-Act-Assert - Structure tests consistently
- Use act() for Updates - Always wrap state changes
- Test Edge Cases - Null, undefined, empty values, errors
- Appropriate Matchers - Use correct expect matchers for the assertion
Common Pitfalls to Avoid
- ❌ Don't Render Hook Directly - Always use
renderHook() - ❌ Don't Forget React Import - Required for JSX in this project
- ❌ Don't Forget act() - State updates need to be wrapped
- ❌ Don't Use vi.mock for Internal - Use Fake providers instead
- ❌ Don't Forget async/await - Async operations need proper handling
Example Reference
See
examples.md in the same directory for complete working examples of:
- Simple hooks returning context values
- Hooks with complex logic and multiple return values
- Hooks with parameters
- Hooks with state management
- Standalone hooks without context
- Hooks using multiple contexts
Important Notes
File Organization
- Tests in
at package root (sibling to__tests__/
)/src - Use
extension.tsx - Match hook name exactly
Dependencies
- Ensure
is installed@testing-library/react - Use Fake providers from
subpath/fakes - Create Fakes if they don't exist
Test Quality
- Many small tests > few large tests
- Test happy path and error cases
- Test edge cases and boundaries
- 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