Skip to content

Latest commit

 

History

History
138 lines (104 loc) · 4.59 KB

guide-disappearance.md

File metadata and controls

138 lines (104 loc) · 4.59 KB
id title
guide-disappearance
Appearance and Disappearance

Sometimes you need to test that an element is present and then disappears or the other way around.

Waiting for appearance

If you need to wait for an element to appear, findBy and the async wait utility waitFor allow you to wait for an assertion to be satisfied before proceeding. The wait utilities retry until the query passes or times out.

Wait for appearance and return the element using findBy:

test('movie title appears', async () => {
  // element is initially not present...

  const movieTitle = await screen.findByText('the lion king')
  expect(movieTitle).toBeInTheDocument()
})

Or wait for appearance using waitFor and getBy:

test('movie title appears', async () => {
  // element is initially not present...

  await waitFor(() => {
    expect(screen.getByText('the lion king')).toBeInTheDocument()
  })
})

These do more or less the same thing (findBy uses waitFor under the hood), but the findBy version results in simpler code and a better error message.

Note: toBeInTheDocument() comes from @testing-library/jest-dom

Waiting for disappearance

When you want to wait until an element has disappeared, you can use waitForElementToBeRemoved or waitFor.

The waitForElementToBeRemoved async wait utility takes an element as an argument and waits until that element has been removed from the document.

test('movie title no longer present in document', async () => {
  // element is present
  const movie = screen.queryByText('the mummy')
  await waitForElementToBeRemoved(movie)

  // element has been removed
  expect(movie).not.toBeInTheDocument()
})

waitForElementToBeRemoved works by using a MutationObserver internally, which means it responds to the element being removed in a very efficient way.

You can also pass an array or a callback to waitForElementToBeRemoved - see the documentation for more options.

Another option is using the waitFor helper.

The waitFor async wait utility retries until the wrapped function stops throwing an error. Because expectations throw errors when they fail, putting one in the wrapped function can be used to wait for the element to be removed.

test('movie title goes away', async () => {
  // element is initially present...
  // note use of queryBy instead of getBy to return null
  // instead of throwing in the query itself
  await waitFor(() => {
    expect(screen.queryByText('i, robot')).not.toBeInTheDocument()
  })
})

Polling like this is not as efficient as observing for mutations using waitForElementToBeRemoved, but sometimes it's the best option.

Asserting elements are not present

As opposed to waiting for removal, this is for when you are at a point in your test where you know an element shouldn't be present.

You might reach for getBy to check that something is not present, but getBy queries throw an error when they can't find an element, which means you don't get the chance to use the result in an expectation. If you want to make an assertion that an element is not present in the document, you can use queryBy queries instead:

const submitButton = screen.queryByText('submit')
expect(submitButton).not.toBeInTheDocument() // it doesn't exist in the document

The queryAll query methods return an array of matching elements. The length of the array can be useful for assertions after elements are added or removed from the document.

const submitButtons = screen.queryAllByText('submit')
expect(submitButtons).toHaveLength(2) // expect 2 elements

Note: not.toBeInTheDocument() comes from @testing-library/jest-dom

The toBeInTheDocument() matcher

The @testing-library/jest-dom utility library provides the .toBeInTheDocument() matcher, which can be used to assert that an element is in the body of the document, or not. This can be more meaningful than asserting a query result is null, and it also provides more helpful error messages when your tests fail.

// use `queryBy` to avoid throwing an error with `getBy`
const submitButton = screen.queryByText('submit')
expect(submitButton).not.toBeInTheDocument()

Read about how to set this up in the documentation.