GithubHelp home page GithubHelp logo

dom-testing-addon-async's Introduction

dom-testing-addon-async

Build Status

Async query addon for dom-testing-library

Why?

dom-testing-library handles asynchronocity by providing waitForElement to wrap and retry function calls that may error. But in some cases it may be helpful to invert the default expectation and treat sync queries like getByText as special cases rather than the other way around. For example:

  • In test environments with lots of async behavior it can be cumbersome to always use wait or waitForElement.
  • Asynchronicity may be sometimes be considered an implementation detail - for example, async form validation states, or a React Suspense or Hook that may sometimes resolve after a timeout.

Before

const usernameElement = await waitForElement(() =>
  getByLabelText(container, 'username'))

After

const usernameElement = await findByLabelText(container, 'username'))

API

find*

Each of the get and getAll queries from dom-testing-library are wrapped in an async find API.

The find APIs return a Promise and retry automatically until they time out. The timeout can be specified as an option in the last argument.

import { findByLabelText, findByText } from 'dom-testing-addon-async'
import { getByRole} from 'dom-testing-library'

const container = document;

// trigger an action
fireEvent.click(getByRole('log-in'))

// This element doesn't appear immediately:
const usernameElement = await findByLabelText(container, 'username')

usernameElement.value = 'chucknorris'

// wait for error state
expect(await findByText(container, 'Error: Name must be capitalized')).not.toBeNull()

// expect NOT to see success state
await expect(findByText(container, 'Everything OK!')).rejects.toMatchInlineSnapshot()

waitFor

Note

You probably won't need waitFor unless you are building your own queries. Otherwise, use dom-testing-library's wait or waitForElement.

waitFor is a utility function that lets you retry queries until they succeed or time out. It is used internally to create the find APIs.

The first argument is the query. A new async function is returned if this is the only argument. You can create your own async queries this way:

const waitForText = waitFor(getByText)

const headline = await waitForText('news flash')

expect(headline).toBeDefined() // do something

If there are two or more arguments, waitFor returns a Promise which resolves with the result of calling the async function with the arguments. If the last argument is an object with a "timeout" key, it will be used as the timeout for the retries. The Promise is rejected with the last error thrown by the callback.

const usernameElement = await waitFor(getByLabelText, container, 'username')
usernameElement.value = 'chucknorris'

with react-testing-library

You can add the queries to react-testing-libary's render method as described here

- import { render, fireEvent } from 'react-testing-library';
+ import { render, fireEvent } from '../test-utils';
test('shows errors when form is invalid', async () => {
  const { findByLabelText, findByText, getByRole } = render(<MyForm />)
  
  // trigger an action
  fireEvent.click(getByRole('log-in')) // can still use sync queries

  // This element doesn't appear immediately:
  const usernameElement = await findByLabelText(container, 'username')
  
  // type in the box
  fireEvent('change', userNameElement, {value: 'chucknorris'})

  // wait for error state
  expect(await findByText(container, 'Error: Name must be capitalized')).not.toBeNull()

  // expect NOT to see success state
  await expect(findByText(container, 'Everything OK!')).rejects.toMatchInlineSnapshot()
})
// test-utils.js
import {render} from 'react-testing-library'
import * as syncQueries from 'dom-testing-library/dist/queries'
import * as asyncQueries from 'dom-testing-addon-async/dist/queries'

const allQueries = {
   ...syncQueries,
   ...asyncQueries,
}

function customRender(ui, {queries = allQueries, ...rest} = {}) {
  // Note: you may also need to wrap the result's `rerender` method
  return render(ui, {queries, ...rest})
}

// re-export everything
export * from 'react-testing-library'

// override render method
export {customRender as render}

Note

In the future, React may provide more APIs for controlling whether a component tree is synchronous or concurrent/suspendable.

dom-testing-addon-async's People

Contributors

alexkrolick avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.