How to Test Conditional Rendering in React
Testing conditional rendering in React ensures that your user interface correctly adapts to different states, user inputs, and API responses. This article provides a straightforward guide on how to test conditional UI changes in React using Jest and React Testing Library (RTL). You will learn how to verify that components render the correct elements under specific conditions and successfully hide them when those conditions are not met.
The Strategy for Testing Conditional Rendering
When testing conditional rendering, your main goal is to assert that specific elements are either present or absent in the Document Object Model (DOM) based on the props or state of the component.
React Testing Library provides two key query types for this: *
getBy...: Throws an error immediately if
the element is not found. Use this to assert that an element
should be rendered. *
queryBy...: Returns null if
the element is not found. Use this to assert that an element
should not be rendered.
Scenario 1:
Testing Logical && Rendering (Show/Hide)
The logical AND (&&) operator is commonly used
to show or hide an element based on a boolean value.
The Component
// WelcomeBanner.js
import React from 'react';
export default function WelcomeBanner({ isLoggedIn, username }) {
return (
<div>
<h1>Welcome to our App</h1>
{isLoggedIn && <p data-testid="welcome-message">Hello, {username}!</p>}
</div>
);
}The Test
To test this component, write two test cases: one where
isLoggedIn is true (the message should
render), and one where it is false (the message should not
render).
// WelcomeBanner.test.js
import { render, screen } from '@testing-library/react';
import WelcomeBanner from './WelcomeBanner';
describe('WelcomeBanner Conditional Rendering', () => {
test('renders welcome message when user is logged in', () => {
render(<WelcomeBanner isLoggedIn={true} username="John" />);
// Use getByTestId because we expect the element to exist
const message = screen.getByTestId('welcome-message');
expect(message).toBeInTheDocument();
expect(message).toHaveTextContent('Hello, John!');
});
test('does not render welcome message when user is logged out', () => {
render(<WelcomeBanner isLoggedIn={false} username="John" />);
// Use queryByTestId because getByTestId would throw an error
const message = screen.queryByTestId('welcome-message');
expect(message).not.toBeInTheDocument();
expect(message).toBeNull();
});
});Scenario 2: Testing Ternary Operators (Either/Or Rendering)
Ternary operators are used to switch between two different elements depending on a condition, such as toggling between a “Login” and “Logout” button.
The Component
// AuthButton.js
import React from 'react';
export default function AuthButton({ isLoggedIn, onLogin, onLogout }) {
return (
<div>
{isLoggedIn ? (
<button onClick={onLogout}>Log Out</button>
) : (
<button onClick={onLogin}>Log In</button>
)}
</div>
);
}The Test
For ternary logic, verify that the first element renders and the second does not, and then test the reverse scenario.
// AuthButton.test.js
import { render, screen } from '@testing-library/react';
import AuthButton from './AuthButton';
describe('AuthButton Conditional Rendering', () => {
test('renders "Log Out" button when logged in', () => {
render(<AuthButton isLoggedIn={true} />);
expect(screen.getByRole('button', { name: /log out/i })).toBeInTheDocument();
expect(screen.queryByRole('button', { name: /log in/i })).not.toBeInTheDocument();
});
test('renders "Log In" button when logged out', () => {
render(<AuthButton isLoggedIn={false} />);
expect(screen.getByRole('button', { name: /log in/i })).toBeInTheDocument();
expect(screen.queryByRole('button', { name: /log out/i })).not.toBeInTheDocument();
});
});Key Best Practices
- Always use
queryByfor non-existence: UsinggetByRoleorgetByTextto assert that an element is missing will cause your test suite to crash before the assertion runs. - Test user interactions that trigger state changes:
If the conditional rendering is controlled by internal component state
(like clicking a dropdown menu), use
fireEventoruserEventto trigger the click, then assert that the conditional content appears in the DOM.