Skip to main content Skills Marketplace Découvrez et explorez les compétences IA créées par la communauté.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Copier le promptAfficher les détails du prompt Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
npx skills add https://github.com/pluginagentmarketplace/custom-plugin-react --skill react-testing-libraryLa commande reste sur une seule ligne. Faites défiler horizontalement pour la vérifier avant de la copier.
Vous préférez une copie locale ? Téléchargez les fichiers actuellement disponibles dans SkillsMP.
Télécharger Zip Téléchargement... Plus depuis ce dépôt Build production-grade, accessible, and tested component libraries with Storybook, Chromatic, and design tokens
Build production-grade React apps with Next.js 14 App Router, Server Components, and Edge Runtime
Master React Hooks including useState, useEffect, useContext, useReducer, and custom hooks with production-grade patterns
Métiers associés SOC
Basé sur la classification professionnelle SOC
Explorateur de fichiers
4 fichiers name react-testing-library description Write production-grade React tests with Testing Library, MSW, and comprehensive coverage patterns sasmp_version 2.0.0 bonded_agent 07-testing-deployment bond_type PRIMARY_BOND input_validation {"required_packages":[{"@testing-library/react":">=14.0.0"},{"@testing-library/user-event":">=14.0.0"},{"msw":">=2.0.0"}]} output_format {"code_examples":"jsx","coverage_target":80} error_handling {"patterns":["retry_flaky","async_waitfor","mock_error_states"]} observability {"logging":"jest_console","metrics":["test_duration","coverage"]}
React Testing Library Skill
Overview
Master React Testing Library for writing maintainable tests that focus on user behavior rather than implementation details.
Learning Objectives
Write component tests with RTL
Test user interactions
Handle async operations
Test hooks and context
Follow testing best practices
Quick Start
Installation
npm install --save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event
Setup
import '@testing-library/jest-dom' ;
Basic Component Testing
import { render, screen } from '@testing-library/react' ;
import userEvent from '@testing-library/user-event' ;
import Button from './Button' ;
describe ('Button' , () => {
it ('renders button 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 ();
( );
userEvent. (screen. ( ));
(handleClick). ( );
});
( , {
( );
(screen. ( )). ();
});
});
render
<Button onClick ={handleClick} > Click me</Button >
await
click
getByRole
'button'
expect
toHaveBeenCalledTimes
1
it
'is disabled when disabled prop is true'
() =>
render
<Button disabled > Click me</Button >
expect
getByRole
'button'
toBeDisabled
Queries
Priority Order
screen.getByRole ('button' , { name : /submit/i });
screen.getByLabelText ('Email' );
screen.getByPlaceholderText ('Enter email' );
screen.getByText ('Welcome' );
screen.getByAltText ('Profile picture' );
screen.getByTitle ('Close' );
screen.getByTestId ('custom-element' );
Query Variants
screen.getByText ('Hello' );
screen.queryByText ('Hello' );
await screen.findByText ('Hello' );
Testing Forms
import { render, screen } from '@testing-library/react' ;
import userEvent from '@testing-library/user-event' ;
import LoginForm from './LoginForm' ;
describe ('LoginForm' , () => {
it ('submits form with correct data' , async () => {
const handleSubmit = jest.fn ();
render (<LoginForm onSubmit ={handleSubmit} /> );
await userEvent.type (screen.getByLabelText (/email/i ), 'test@example.com' );
await userEvent.type (screen.getByLabelText (/password/i ), 'password123' );
await userEvent.click (screen.getByRole ('button' , { name : /login/i }));
expect (handleSubmit).toHaveBeenCalledWith ({
email : 'test@example.com' ,
password : 'password123'
});
});
it ('shows validation errors' , async () => {
render (<LoginForm onSubmit ={jest.fn()} /> );
await userEvent.click (screen.getByRole ('button' , { name : /login/i }));
expect (await screen.findByText (/email is required/i )).toBeInTheDocument ();
});
});
Testing Async Operations
import { render, screen, waitFor } from '@testing-library/react' ;
import { rest } from 'msw' ;
import { setupServer } from 'msw/node' ;
import UserProfile from './UserProfile' ;
const server = setupServer (
rest.get ('/api/users/:userId' , (req, res, ctx ) => {
return res (ctx.json ({ id : 1 , name : 'John Doe' }));
})
);
beforeAll (() => server.listen ());
afterEach (() => server.resetHandlers ());
afterAll (() => server.close ());
describe ('UserProfile' , () => {
it ('loads and displays user data' , async () => {
render (<UserProfile userId ={1} /> );
expect (screen.getByText (/loading/i )).toBeInTheDocument ();
expect (await screen.findByText ('John Doe' )).toBeInTheDocument ();
expect (screen.queryByText (/loading/i )).not .toBeInTheDocument ();
});
it ('handles API errors' , async () => {
server.use (
rest.get ('/api/users/:userId' , (req, res, ctx ) => {
return res (ctx.status (500 ));
})
);
render (<UserProfile userId ={1} /> );
expect (await screen.findByText (/error/i )).toBeInTheDocument ();
});
});
Testing Hooks
import { renderHook, act } from '@testing-library/react' ;
import useCounter from './useCounter' ;
describe ('useCounter' , () => {
it ('increments counter' , () => {
const { result } = renderHook (() => useCounter ());
act (() => {
result.current .increment ();
});
expect (result.current .count ).toBe (1 );
});
it ('resets to initial value' , () => {
const { result } = renderHook (() => useCounter (10 ));
act (() => {
result.current .increment ();
result.current .reset ();
});
expect (result.current .count ).toBe (10 );
});
});
Testing Context
import { render, screen } from '@testing-library/react' ;
import userEvent from '@testing-library/user-event' ;
import { ThemeProvider } from './ThemeContext' ;
import ThemeToggle from './ThemeToggle' ;
describe ('ThemeToggle' , () => {
it ('toggles theme' , async () => {
render (
<ThemeProvider >
<ThemeToggle />
</ThemeProvider >
);
expect (screen.getByText (/current theme: light/i )).toBeInTheDocument ();
await userEvent.click (screen.getByRole ('button' ));
expect (screen.getByText (/current theme: dark/i )).toBeInTheDocument ();
});
});
Custom Render Utility
import { render } from '@testing-library/react' ;
import { BrowserRouter } from 'react-router-dom' ;
import { ThemeProvider } from './ThemeContext' ;
function AllProviders ({ children } ) {
return (
<BrowserRouter >
<ThemeProvider >
{children}
</ThemeProvider >
</BrowserRouter >
);
}
function customRender (ui, options ) {
return render (ui, { wrapper : AllProviders , ...options });
}
export * from '@testing-library/react' ;
export { customRender as render };
Best Practices
Test user behavior, not implementation
Use accessible queries (role, label)
Avoid testing internal state
Use userEvent for realistic interactions
Mock external dependencies (API calls)
Test error states and edge cases
Keep tests simple and focused
Common Patterns
await waitFor (() => {
expect (screen.queryByText (/loading/i )).not .toBeInTheDocument ();
});
await waitFor (() => {
expect (screen.getAllByRole ('listitem' )).toHaveLength (3 );
});
screen.debug ();
screen.logTestingPlaygroundURL ();
Practice Exercises
Test form validation
Test async data fetching
Test user authentication flow
Test routing navigation
Test modal interactions
Test list filtering
Test error boundaries
Resources
Flaky Test Prevention
module .exports = {
testRetry : process.env .CI ? 2 : 0 ,
testTimeout : 10000 ,
};
it ('handles async operations reliably' , async () => {
render (<AsyncComponent /> );
expect (await screen.findByText (/loaded/i , {}, { timeout : 5000 }))
.toBeInTheDocument ();
await waitFor (() => {
expect (screen.queryByText (/loading/i )).not .toBeInTheDocument ();
});
});
MSW 2.0 Setup
import { http, HttpResponse } from 'msw' ;
export const handlers = [
http.get ('/api/users' , () => {
return HttpResponse .json ([{ id : 1 , name : 'John' }]);
}),
http.post ('/api/users' , async ({ request }) => {
const user = await request.json ();
return HttpResponse .json ({ ...user, id : Date .now () }, { status : 201 });
}),
http.get ('/api/error' , () => {
return HttpResponse .json ({ message : 'Server Error' }, { status : 500 });
}),
];
Coverage Configuration
module .exports = {
collectCoverageFrom : ['src/**/*.{js,jsx,ts,tsx}' , '!src/**/*.d.ts' ],
coverageThreshold : {
global : {
branches : 80 ,
functions : 80 ,
lines : 80 ,
statements : 80 ,
},
},
};
Version : 2.0.0
Last Updated : 2025-12-30
SASMP Version : 2.0.0
Difficulty : Intermediate
Estimated Time : 2-3 weeks
Prerequisites : React Fundamentals, Jest Basics
Changelog : Added MSW 2.0, flaky test prevention, and coverage config