Testing Library

Testing Library

  • Docs
  • Recipes
  • Help
  • Blog

›DOM Testing Library

Getting Started

  • Introduction
  • Guiding Principles

Frameworks

    DOM Testing Library

    • Introduction
    • Install
    • Example
    • Setup
    • Queries
    • Firing Events
    • Async Utilities
    • Helpers
    • Configuration
    • FAQ
    • Cheatsheet

    React Testing Library

    • Introduction
    • Example
    • Setup
    • API
    • FAQ
    • Cheatsheet

    ReasonReact Testing Library

    • Introduction
    • Examples

    Native Testing Library

    • Intro
    • Example
    • Setup
    • API

    Vue Testing Library

    • Intro
    • Examples
    • Setup
    • API
  • Cypress Testing Library
  • Svelte Testing Library
  • Angular Testing Library
  • Puppeteer Testing Library
  • Testcafe Testing Library

Ecosystem

  • user-event
  • jest-dom
  • bs-jest-dom
  • jest-native
  • react-select-event
Edit

Async Utilities

Several utilities are provided for dealing with asynchronous code. These can be useful to wait for an element to appear or disappear in response to an action. (See the guide to testing disappearance.)

wait

function wait(
  callback?: () => void,
  options?: {
    timeout?: number
    interval?: number
  }
): Promise<void>

When in need to wait for non-deterministic periods of time you can use wait, to wait for your expectations to pass. The wait function is a small wrapper around the wait-for-expect module. Here's a simple example:

// ...
// Wait until the callback does not throw an error. In this case, that means
// it'll wait until we can get a form control with a label that matches "username".
await wait(() => getByLabelText(container, 'username'))
getByLabelText(container, 'username').value = 'chucknorris'
// ...

This can be useful if you have a unit test that mocks API calls and you need to wait for your mock promises to all resolve.

The default callback is a no-op function (used like await wait()). This can be helpful if you only need to wait for one tick of the event loop (in the case of mocked API calls with promises that resolve immediately).

The default timeout is 4500ms which will keep you under Jest's default timeout of 5000ms.

The default interval is 50ms. However it will run your callback immediately on the next tick of the event loop (in a setTimeout) before starting the intervals.

waitForElement

function waitForElement<T>(
  callback: () => T,
  options?: {
    container?: HTMLElement
    timeout?: number
    mutationObserverOptions?: MutationObserverInit
  }
): Promise<T>

When in need to wait for DOM elements to appear, disappear, or change you can use waitForElement. The waitForElement function is a small wrapper around the MutationObserver.

Here's a simple example:

// ...
// Wait until the callback does not throw an error and returns a truthy value. In this case, that means
// it'll wait until we can get a form control with a label that matches "username".
// The difference from `wait` is that rather than running your callback on
// an interval, it's run as soon as there are DOM changes in the container
// and returns the value returned by the callback.
const usernameElement = await waitForElement(
  () => getByLabelText(container, 'username'),
  { container }
)
usernameElement.value = 'chucknorris'
// ...

You can also wait for multiple elements at once:

const [usernameElement, passwordElement] = await waitForElement(
  () => [
    getByLabelText(container, 'username'),
    getByLabelText(container, 'password'),
  ],
  { container }
)

Using MutationObserver is more efficient than polling the DOM at regular intervals with wait. This library sets up a 'mutationobserver-shim' on the global window object for cross-platform compatibility with older browsers and the jsdom that is usually used in Node-based tests.

The default container is the global document. Make sure the elements you wait for will be attached to it, or set a different container.

The default timeout is 4500ms which will keep you under Jest's default timeout of 5000ms.

The default mutationObserverOptions is {subtree: true, childList: true, attributes: true, characterData: true} which will detect additions and removals of child elements (including text nodes) in the container and any of its descendants. It will also detect attribute changes.

waitForDomChange

function waitForDomChange<T>(options?: {
  container?: HTMLElement
  timeout?: number
  mutationObserverOptions?: MutationObserverInit
}): Promise<T>

When in need to wait for the DOM to change you can use waitForDomChange. The waitForDomChange function is a small wrapper around the MutationObserver.

Here is an example where the promise will be resolved because the container is changed:

const container = document.createElement('div')
waitForDomChange({ container })
  .then(() => console.log('DOM changed!'))
  .catch(err => console.log(`Error you need to deal with: ${err}`))
container.append(document.createElement('p'))
// if 👆 was the only code affecting the container and it was not run,
// waitForDomChange would throw an error

The promise will resolve with a mutationsList which you can use to determine what kind of a change (or changes) affected the container

const container = document.createElement('div')
container.setAttribute('data-cool', 'true')
waitForDomChange({ container }).then(mutationsList => {
  const mutation = mutationsList[0]
  console.log(
    `was cool: ${mutation.oldValue}\ncurrently cool: ${
      mutation.target.dataset.cool
    }`
  )
})
container.setAttribute('data-cool', 'false')
/*
  logs:
    was cool: true
    currently cool: false
*/

Using MutationObserver is more efficient than polling the DOM at regular intervals with wait. This library sets up a 'mutationobserver-shim' on the global window object for cross-platform compatibility with older browsers and the jsdom that is usually used in Node-based tests.

The default container is the global document. Make sure the elements you wait for will be attached to it, or set a different container.

The default timeout is 4500ms which will keep you under Jest's default timeout of 5000ms.

The default mutationObserverOptions is {subtree: true, childList: true, attributes: true, characterData: true} which will detect additions and removals of child elements (including text nodes) in the container and any of its descendants. It will also detect attribute changes.

waitForElementToBeRemoved

function waitForElementToBeRemoved<T>(
  callback: () => T,
  options?: {
    container?: HTMLElement
    timeout?: number
    mutationObserverOptions?: MutationObserverInit
  }
): Promise<T>

To wait for the removal of element(s) from the DOM you can use waitForElementToBeRemoved. The waitForElementToBeRemoved function is a small wrapper around the MutationObserver.

The callback must return the pre-existing element or array of elements that are expected to be removed.

Here is an example where the promise resolves with true because the element is removed:

const el = document.querySelector('div.getOuttaHere')

waitForElementToBeRemoved(() =>
  document.querySelector('div.getOuttaHere')
).then(() => console.log('Element no longer in DOM'))

el.setAttribute('data-neat', true)
// other mutations are ignored...

el.parentElement.removeChild(el)
// logs 'Element no longer in DOM'

waitForElementToBeRemoved will throw an error when the provided callback does not return an element.

waitForElementToBeRemoved(() => null).catch(err => console.log(err))

// 'The callback function which was passed did not return an element
// or non-empty array of elements.
// waitForElementToBeRemoved requires that the element(s) exist
// before waiting for removal.'

Using MutationObserver is more efficient than polling the DOM at regular intervals with wait. This library sets up a 'mutationobserver-shim' on the global window object for cross-platform compatibility with older browsers and the jsdom that is usually used in Node-based tests.

The default container is the global document. Make sure the elements you wait for are descendants of container.

The default timeout is 4500ms which will keep you under Jest's default timeout of 5000ms.

The default mutationObserverOptions is {subtree: true, childList: true, attributes: true, characterData: true} which will detect additions and removals of child elements (including text nodes) in the container and any of its descendants. It will also detect attribute changes.

Last updated on 5/6/2019
← Firing EventsHelpers →
  • wait
  • waitForElement
  • waitForDomChange
  • waitForElementToBeRemoved
Testing Library
Docs
Getting StartedExamplesAPIHelp
Community
BlogStack OverflowReactiflux on DiscordSpectrum
More
StarGitHubEdit Docs on GitHub
Copyright © 2018-2019 Kent C. Dodds and contributors