← Back to React Course | Chapter 12: Testing React Applications | Lesson 3 of 9

Rendering and Querying Elements

Render queries are like different ways of asking wheres the thing I'm looking for' — sometimes you search by name tag, sometimes by role, sometimes by what label is stuck on it.

getBy vs. queryBy vs. findBy

getBy* throws an error immediately if no matching element exists, making it ideal for asserting something IS present. queryBy* returns null instead of throwing, making it the right choice for asserting something is ABSENT. findBy* returns a Promise and waits, ideal for elements that appear after an async action.

Note: A simple mental model: getBy for 'this should exist right now', queryBy for 'this should NOT exist', findBy for 'this will exist soon'.

Warning: Using getBy* to check something is absent throws an unhelpful error instead of a clean assertion failure — use queryBy* + toBeNull() or not.toBeInTheDocument() instead.

Example: getBy vs. queryBy vs. findBy

markup
// Run in your local React project (npm install required)
import { render, screen } from '@testing-library/react';
import Alert from './Alert';

test('alert is not shown initially', () => {
  render(<Alert show={false} />);
  expect(screen.queryByText('Warning!')).not.toBeInTheDocument();
});

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

Waiting for Async Content with findBy

When content appears after an asynchronous action (like a fetch resolving), findBy* queries return a Promise that repeatedly checks for the element until it appears or a timeout is reached, avoiding the need for manual waiting or arbitrary setTimeout calls in tests.

Note: Always await a findBy* query — forgetting the await means the test moves on before the element has actually appeared.

Warning: findBy* has a default timeout (usually 1000ms) — a genuinely slow-loading element might need an explicit longer timeout passed as an option.

Example: Waiting for Async Content with findBy

markup
// Run in your local React project (npm install required)
import { render, screen } from '@testing-library/react';
import UserProfile from './UserProfile';

test('shows user name after loading', async () => {
  render(<UserProfile userId={1} />);
  const name = await screen.findByText('Asha');
  expect(name).toBeInTheDocument();
});

⚠️ This example uses an npm package with no CDN build available here — run this in your local React project.

The Recommended Query Priority

Testing Library recommends a priority order for which query to reach for first: getByRole is preferred (it reflects real accessibility semantics), then getByLabelText for form fields, then getByText for general content, with test-ID-based queries as a last resort when nothing else fits.

Note: Following this priority order tends to naturally push your components toward better accessibility, since you're forced to think about roles and labels.

Warning: Reaching straight for getByTestId as a default habit skips the accessibility benefits the other queries encourage, and misses catching accessibility issues your tests could otherwise reveal.

Example: The Recommended Query Priority

markup
// Run in your local React project (npm install required)
// Priority order (most to least preferred):
screen.getByRole('button', { name: 'Save' });   // 1st choice
screen.getByLabelText('Email address');           // 2nd choice
screen.getByText('Welcome back');                 // 3rd choice
screen.getByTestId('save-button');                // last resort
Common Mistakes
  1. Using getByText for elements identified better by role, missing accessibility semantics the test could otherwise verify.
  2. Not knowing the difference between getBy, queryBy, and findBy — each behaves differently for missing or async elements.
  3. Overusing container.querySelector, bypassing Testing Library's user-centric query system entirely.
Chapter Summary
  • getBy* queries throw if zero or multiple matches are found — use for elements expected to exist right now.
  • queryBy* returns null instead of throwing — use to assert something does NOT exist.
  • findBy* returns a Promise, waiting for an element to appear — use for content that shows up asynchronously.
  • Query priority (recommended order): getByRole, getByLabelText, getByText, then more implementation-specific options.
Browser Support

Requires npm install @testing-library/react — runs in a Node test environment, not this browser sandbox.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.