This error occurs when React Testing Library's text matching queries (getByText, findByText) fail because the actual text content in the DOM does not match the expected text pattern. It often happens due to whitespace differences, text split across elements, or asynchronous content updates.
Fixes Text content does not match. Expected: "..." but received: "..."
// Problem: trailing space in DOM
<div>Login </div>
// Fails: exact match
screen.getByText("Login");
// Solution 1: trim text content
const element = screen.getByText((content, element) => {
return element.textContent.trim() === "Login";
});
// Solution 2: include whitespace in query
screen.getByText("Login ");
// Solution 3: use regex with optional whitespace
screen.getByText(/^Login\s*$/);// Problem: trailing space in DOM<div>Login </div>// Fails: exact matchscreen.getByText("Login");// Solution 1: trim text contentconst element = screen.getByText((content, element) => {return element.textContent.trim() === "Login";});// Solution 2: include whitespace in queryscreen.getByText("Login ");// Solution 3: use regex with optional whitespacescreen.getByText(/^Login\s*$/);Text content does not match. Expected: "..." but received: "..."
The "Text content does not match" error indicates that React Testing Library cannot find an element with the specified text content. This happens when the text query (using exact string, regex, or function) does not match any element's textContent in the rendered DOM. The error message shows both the expected text pattern and the actual text received, helping identify mismatches in whitespace, formatting, or element structure.
The most common cause is whitespace mismatches. Use .trim() on expected strings or include whitespace in your query. You can also use regex with \s* to match optional whitespace.
// Problem: trailing space in DOM
<div>Login </div>
// Fails: exact match
screen.getByText("Login");
// Solution 1: trim text content
const element = screen.getByText((content, element) => {
return element.textContent.trim() === "Login";
});
// Solution 2: include whitespace in query
screen.getByText("Login ");
// Solution 3: use regex with optional whitespace
screen.getByText(/^Login\s*$/);When text is broken by HTML elements, getByText looks at individual text nodes. Use a custom text matcher function or query by partial text.
// Problem: text split by <span>
<div>2<span>-</span>3</div>
// Fails: looks for "2-3" in a single text node
screen.getByText("2-3");
// Solution 1: query by partial text
screen.getByText("2");
screen.getByText("3");
// Solution 2: custom text matcher function
screen.getByText((content, element) => {
return element.textContent === "2-3";
});
// Solution 3: getByTextContent helper function
function getByTextContent(text) {
return screen.getByText((content, element) => {
return element.textContent === text;
});
}
const element = getByTextContent("2-3");If text content changes after initial render (loading states, API responses), use findByText instead of getByText. findByText returns a Promise and waits for matching text to appear.
// Using getByText (fails if text not immediately present)
// screen.getByText("Loading...");
// Using findByText (waits for text)
const loadingElement = await screen.findByText("Loading...");
// With custom timeout
const element = await screen.findByText("Data loaded", {}, { timeout: 5000 });
// For text that appears then disappears (like loading states)
await waitFor(() => {
expect(screen.queryByText("Loading...")).not.toBeInTheDocument();
});Regular expressions provide more flexible text matching. Use them for case-insensitive matches, partial matches, or patterns with dynamic content.
// Case insensitive matching
screen.getByText(/login/i);
// Partial text matching
screen.getByText(/Log/); // matches "Login", "Logout", "Logger"
// Match dynamic content (like counts)
screen.getByText(/Items: \d+/); // matches "Items: 5", "Items: 10"
// Match with optional whitespace
screen.getByText(/^\s*Login\s*$/);
// Complex pattern matching
screen.getByText(/User:\s*\w+\s*\(ID: \d+\)/);Use screen.debug() to see the exact DOM structure and text nodes. This helps identify whitespace issues, element splitting, or unexpected text content.
import { screen } from '@testing-library/react';
// Render your component
render(<MyComponent />);
// Print entire DOM to console
screen.debug();
// Print specific element
const element = screen.getByTestId('my-element');
screen.debug(element);
// Check textContent directly
console.log('Text content:', element.textContent);
console.log('Inner HTML:', element.innerHTML);
// Use logTestingPlaygroundURL for visual debugging
screen.logTestingPlaygroundURL();For complex text matching scenarios, create a helper function to normalize text content before comparison. This handles whitespace, case, and special characters consistently.
function normalizeText(text) {
return text
.trim()
.replace(/\s+/g, ' ') // collapse multiple spaces
.replace(/\n/g, ' ') // replace newlines with spaces
.toLowerCase(); // optional: for case-insensitive
}
// Use in custom matcher
screen.getByText((content, element) => {
const normalizedActual = normalizeText(element.textContent);
const normalizedExpected = normalizeText("Expected Text");
return normalizedActual === normalizedExpected;
});
// Or as a reusable query
function getByNormalizedText(expectedText) {
return screen.getByText((content, element) => {
return normalizeText(element.textContent) === normalizeText(expectedText);
});
}
const element = getByNormalizedText(" Login "); // handles extra spacesReact Testing Library's text matching uses the DOM textContent property, which includes text from all descendant nodes. However, it matches against individual text nodes when using string queries. The getByText function has three signatures: string (exact match), regex (pattern match), and function (custom matcher). For complex text scenarios, custom matcher functions provide the most control. Note that textContent includes hidden text (from display: none elements) but not text from aria-hidden="true" elements. When testing internationalized applications, consider text normalization for different languages and character sets.