How to Mock Conditional Rendering in React
Testing how your React components behave under different states is crucial for building reliable user interfaces. This article explains how to mock conditional rendering in React using Jest and React Testing Library. You will learn how to test conditional outcomes by altering component props, mocking internal React state, and mocking custom hooks or external modules.
Scenario 1: Mocking via Props
The simplest form of conditional rendering depends on the props passed to a component. You do not need complex mocking libraries for this scenario; you simply render the component with different prop values in your test cases.
Consider this component:
// Notification.jsx
export default function Notification({ hasError, message }) {
if (hasError) {
return <div className="error">Error: {message}</div>;
}
return <div className="success">Success!</div>;
}To test both rendering paths, write tests that pass different values
for hasError:
// Notification.test.jsx
import { render, screen } from '@testing-library/react';
import Notification from './Notification';
test('renders error message when hasError is true', () => {
render(<Notification hasError={true} message="Failed to save" />);
expect(screen.getByText('Error: Failed to save')).toBeInTheDocument();
expect(screen.queryByText('Success!')).not.toBeInTheDocument();
});
test('renders success message when hasError is false', () => {
render(<Notification hasError={false} />);
expect(screen.getByText('Success!')).toBeInTheDocument();
expect(screen.queryByText(/Error:/)).not.toBeInTheDocument();
});Scenario 2: Mocking Custom Hooks and Context
When conditional rendering depends on a custom hook (like authentication status or feature flags), you must mock the hook’s return value to control what the component displays.
Consider this dashboard component:
// Dashboard.jsx
import { useAuth } from './useAuth';
export default function Dashboard() {
const { user } = useAuth();
return user ? <h1>Welcome, {user.name}</h1> : <h1>Please Log In</h1>;
}To mock the behavior of useAuth, use
jest.mock to intercept the hook and define its return value
for each test:
// Dashboard.test.jsx
import { render, screen } from '@testing-library/react';
import Dashboard from './Dashboard';
import { useAuth } from './useAuth';
// Mock the entire module
jest.mock('./useAuth', () => ({
useAuth: jest.fn(),
}));
describe('Dashboard Conditional Rendering', () => {
test('renders welcome message when user is authenticated', () => {
// Force the mock hook to return an authenticated user
useAuth.mockReturnValue({ user: { name: 'Alex' } });
render(<Dashboard />);
expect(screen.getByText('Welcome, Alex')).toBeInTheDocument();
expect(screen.queryByText('Please Log In')).not.toBeInTheDocument();
});
test('renders login prompt when user is null', () => {
// Force the mock hook to return no user
useAuth.mockReturnValue({ user: null });
render(<Dashboard />);
expect(screen.getByText('Please Log In')).toBeInTheDocument();
expect(screen.queryByText(/Welcome/)).not.toBeInTheDocument();
});
});Scenario 3: Mocking Sub-Components
Sometimes a parent component conditionally renders complex child components. Instead of rendering the actual child components, you can mock them to return simple placeholder elements. This isolates the parent component’s conditional logic.
Consider this parent component:
// MainContainer.jsx
import AdminPanel from './AdminPanel';
import UserPanel from './UserPanel';
export default function MainContainer({ isAdmin }) {
return isAdmin ? <AdminPanel /> : <UserPanel />;
}You can mock AdminPanel and UserPanel to
verify that MainContainer calls the correct one:
// MainContainer.test.jsx
import { render, screen } from '@testing-library/react';
import MainContainer from './MainContainer';
// Mock the child components to return simple text identifiers
jest.mock('./AdminPanel', () => () => <div data-testid="admin-mock">Admin Panel</div>);
jest.mock('./UserPanel', () => () => <div data-testid="user-mock">User Panel</div>);
describe('MainContainer', () => {
test('renders AdminPanel when isAdmin is true', () => {
render(<MainContainer isAdmin={true} />);
expect(screen.getByTestId('admin-mock')).toBeInTheDocument();
expect(screen.queryByTestId('user-mock')).not.toBeInTheDocument();
});
test('renders UserPanel when isAdmin is false', () => {
render(<MainContainer isAdmin={false} />);
expect(screen.getByTestId('user-mock')).toBeInTheDocument();
expect(screen.queryByTestId('admin-mock')).not.toBeInTheDocument();
});
});