How to Test React Fragments
React Fragments allow you to group multiple child elements without adding extra nodes to the DOM. Testing components that utilize fragments is straightforward because fragments themselves do not render any HTML tags. This guide demonstrates how to test React Fragments using React Testing Library (RTL) and Jest, focusing on querying child elements, checking DOM structure, and utilizing snapshot testing.
Understanding Fragments in the DOM
Because React Fragments (<React.Fragment> or the
shorthand <>) disappear once rendered, you cannot
query the fragment itself. Instead, your tests should focus on the
presence, accessibility, and behavior of the child elements contained
within the fragment.
For example, consider this component:
import React from 'react';
const UserProfile = () => {
return (
<>
<h1>User Profile</h1>
<button>Edit Profile</button>
</>
);
};
export default UserProfile;Querying Child Elements
When using React Testing Library, you should query the DOM elements
just as a user would interact with them. Since the fragment does not
introduce a wrapping div, the <h1> and
<button> elements are rendered as direct children of
the container’s parent element.
Here is how you test the rendering of these elements:
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
import UserProfile from './UserProfile';
test('renders child elements inside the fragment', () => {
render(<UserProfile />);
// Query and assert the heading is in the document
const headingElement = screen.getByRole('heading', { name: /user profile/i });
expect(headingElement).toBeInTheDocument();
// Query and assert the button is in the document
const buttonElement = screen.getByRole('button', { name: /edit profile/i });
expect(buttonElement).toBeInTheDocument();
});Verifying the Absence of Wrapping Elements
If you need to verify that your component does not introduce
unnecessary wrapper elements (like an extra div) to the
DOM, you can inspect the container’s child structure.
test('does not render a wrapping element', () => {
const { container } = render(<UserProfile />);
// The container's first child should be the h1, not a wrapping div
expect(container.firstChild?.nodeName).toBe('H1');
// The total number of direct children in the container should be 2
expect(container.childElementCount).toBe(2);
});Snapshot Testing React Fragments
Snapshot testing with Jest is an effective way to ensure that the structure of your fragments remains consistent. The generated snapshot will clearly show the elements rendered side-by-side without a parent wrapper.
import { render } from '@testing-library/react';
import UserProfile from './UserProfile';
test('matches snapshot', () => {
const { asFragment } = render(<UserProfile />);
expect(asFragment()).toMatchSnapshot();
});The resulting snapshot will look like this:
<DocumentFragment>
<h1>User Profile</h1>
<button>Edit Profile</button>
</DocumentFragment>Testing Keyed Fragments
When rendering lists, you must use the explicit
<React.Fragment> syntax instead of the shorthand
<> to assign a key prop.
const ItemList = ({ items }) => {
return (
dl>
{items.map((item) => (
<React.Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.details}</dd>
</React.Fragment>
))}
</dl>
);
};To test a keyed fragment, verify that the list renders the correct pairs of elements in the expected order:
test('renders list items inside keyed fragments correctly', () => {
const mockItems = [
{ id: '1', term: 'React', details: 'A JavaScript library' },
];
render(<ItemList items={mockItems} />);
expect(screen.getByText('React')).toBeInTheDocument();
expect(screen.getByText('A JavaScript library')).toBeInTheDocument();
});