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

  1. Always use queryBy for non-existence: Using getByRole or getByText to assert that an element is missing will cause your test suite to crash before the assertion runs.
  2. Test user interactions that trigger state changes: If the conditional rendering is controlled by internal component state (like clicking a dropdown menu), use fireEvent or userEvent to trigger the click, then assert that the conditional content appears in the DOM.