Build reliable applications with testing strategies and performance monitoring.
Welcome to Unit and Integration Testing with React! Writing tests ensures your components, hooks, and logic behave as expected. We'll use Jest and the React Testing Library to build a robust testing strategy.
Jest is a popular testing framework that provides an easy-to-use API for writing tests. The React Testing Library offers utilities specifically for testing React components.
// Sample test file
import { render, screen } from '@testing-library/react';
import MyComponent from './MyComponent';
test('renders component with correct text', () => {
render(<MyComponent />);
expect(screen.getByText(/Hello World/)).toBeInTheDocument();
});
Unit tests focus on individual components or functions in isolation. Write tests for different scenarios including: default state, user interactions, and edge cases.
// Testing component with state
import { render, fireEvent } from '@testing-library/react';
test('toggles state when clicked', () => {
const { getByRole } = render(<ToggleButton />);
const button = getByRole('button');
expect(button).toHaveTextContent(/Off/);
fireEvent.click(button);
expect(button).toHaveTextContent(/On/);
});
Integration tests verify components work together. Use mocks to simulate dependencies like APIs or external services.
// Mocking API calls
jest.mock('../api');
const mockApiResponse = {
data: { name: 'Test' }
};
api.fetchData.mockResolvedValue(mockApiResponse);
// Testing async behavior
import { act, render } from '@testing-library/react';
it('loads data asynchronously', async () => {
const { getByText } = render(<AsyncComponent />);
expect(getByText(/Loading/)).toBeInTheDocument();
await act(async () => {
// Simulate async operation
await new Promise(resolve => setTimeout(resolve, 100));
});
expect(getByText(/Loaded/)).toBeInTheDocument();
});
Start small and gradually add tests to your project. Focus on critical paths and components that are most likely to break.
Optimizing React applications is crucial for delivering smooth user experiences. In this section, we'll explore how to identify performance bottlenecks and implement effective optimizations.
The React DevTools Profiler is a powerful tool for analyzing performance. It helps you identify slow components, excessive re-renders, and inefficient state updates.
// Open the Profiler in React DevTools
// Analyze render times and component trees
React.memo
to prevent unnecessary re-renders of pure components.const MemoizedComponent = React.memo(() => {
// Component code
});
Use useMemo
to memoize expensive calculations and avoid redundant computations on every render.
const optimizedValue = useMemo(() => {
// Expensive calculation
}, [deps]);
The useCallback
hook allows you to stabilize function references and prevent unnecessary re-renders of dependent components.
const memoizedFunction = useCallback(() => {
// Function logic
}, [deps]);
Lazy loading improves initial load times by only loading components when they're needed.
// Implement code-splitting with React.lazy
const LazyComponent = React.lazy(() => import('./Component'));
// Use Suspense for fallback UI
<React.Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</React.Suspense>
Question 1 of 10