SkillByAIOpen interactive version →

Lesson 15 / 25

get, query and find Variants

Throw, return null, or wait.

Choose by what you expect

Each query comes in three flavours (plus All versions that return arrays). getBy... returns the element or throws if there is no match or more than one; use it when the element should be there now. queryBy... returns null instead of throwing; use it only to assert something is absent (expect(screen.queryByText('Error')).not.toBeInTheDocument()). findBy... returns a promise that retries until the element appears or a timeout (1000 ms by default) passes; use it for content that appears after async work. getAllBy / queryAllBy / findAllBy handle multiple matches. Prefer screen over destructuring queries from render, so you do not have to keep the return value in sync.

Picking the right variant

One line each.

render(<Inbox />);

// present now -> get (throws a helpful error if missing)
expect(screen.getByRole('heading', { name: 'Inbox' })).toBeInTheDocument();

// asserting absence -> query (returns null)
expect(screen.queryByRole('alert')).not.toBeInTheDocument();

// appears after a fetch -> find (awaits, retries until timeout)
expect(await screen.findByRole('listitem', { name: /welcome email/i })).toBeInTheDocument();

// many matches -> *All
expect(screen.getAllByRole('listitem')).toHaveLength(3);

Do not use queryBy to check presence

expect(screen.queryByText('Saved')).toBeInTheDocument() works but gives a worse error than getByText when it fails. Reserve queryBy for absence.

Quick check: Which variant should you use to wait for text that appears after a fetch?

  • findByText, which returns a promise that retries until it appears
  • getByText, which throws immediately
  • queryByText, which returns null
  • getAllByText inside a setTimeout
Answer

findByText, which returns a promise that retries until it appears — find* combines get* with waiting.