Skip to content

Commit 69a395f

Browse files
author
Kent C. Dodds
committed
fix(waitForExpect): rename to wait
We avoid a major version bump by continuing to export `waitForExpect` as well.
1 parent 4adbc1d commit 69a395f

File tree

6 files changed

+97
-108
lines changed

6 files changed

+97
-108
lines changed

README.md

+66-103
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,18 @@ facilitate testing implementation details). Read more about this in
7676

7777
* [Installation](#installation)
7878
* [Usage](#usage)
79-
* [`Simulate`](#simulate)
80-
* [`flushPromises`](#flushpromises)
81-
* [`waitForExpect`](#waitforexpect)
8279
* [`render`](#render)
80+
* [`Simulate`](#simulate)
81+
* [`wait`](#wait)
8382
* [Custom Jest Matchers](#custom-jest-matchers)
8483
* [`toBeInTheDOM`](#tobeinthedom)
8584
* [`toHaveTextContent`](#tohavetextcontent)
8685
* [`TextMatch`](#textmatch)
8786
* [`query` APIs](#query-apis)
8887
* [Examples](#examples)
8988
* [FAQ](#faq)
89+
* [Deprecated APIs](#deprecated-apis)
90+
* [`flushPromises`](#flushpromises)
9091
* [Other Solutions](#other-solutions)
9192
* [Guiding Principles](#guiding-principles)
9293
* [Contributors](#contributors)
@@ -110,8 +111,9 @@ This library has a `peerDependencies` listing for `react-dom`.
110111
```javascript
111112
// __tests__/fetch.js
112113
import React from 'react'
113-
import {render, Simulate, flushPromises} from 'react-testing-library'
114-
import axiosMock from 'axios'
114+
import {render, Simulate, wait} from 'react-testing-library'
115+
import 'react-testing-library/extend-expect' // this adds custom expect matchers
116+
import axiosMock from 'axios' // the mock lives in a __mocks__ directory
115117
import Fetch from '../fetch' // see the tests for a full implementation
116118

117119
test('Fetch makes an API call and displays the greeting when load-greeting is clicked', async () => {
@@ -128,61 +130,18 @@ test('Fetch makes an API call and displays the greeting when load-greeting is cl
128130
Simulate.click(getByText('Load Greeting'))
129131

130132
// let's wait for our mocked `get` request promise to resolve
131-
await flushPromises()
133+
// wait will wait until the callback doesn't throw an error
134+
await wait(() => getByTestId('greeting-text'))
132135

133136
// Assert
134137
expect(axiosMock.get).toHaveBeenCalledTimes(1)
135138
expect(axiosMock.get).toHaveBeenCalledWith(url)
136-
expect(getByTestId('greeting-text').textContent).toBe('hello there')
139+
expect(getByTestId('greeting-text')).toHaveTextContent('hello there')
140+
// snapshots work great with regular DOM nodes!
137141
expect(container.firstChild).toMatchSnapshot()
138142
})
139143
```
140144

141-
### `Simulate`
142-
143-
This is simply a re-export from the `Simulate` utility from
144-
`react-dom/test-utils`. See [the docs](https://reactjs.org/docs/test-utils.html#simulate).
145-
146-
### `flushPromises`
147-
148-
This is a simple utility that's useful for when your component is doing some
149-
async work that you've mocked out, but you still need to wait until the next
150-
tick of the event loop before you can continue your assertions. It simply
151-
returns a promise that resolves in a `setImmediate`. Especially useful when
152-
you make your test function an `async` function and use
153-
`await flushPromises()`.
154-
155-
See an example in the section about `render` below.
156-
157-
### `waitForExpect`
158-
159-
Defined as:
160-
161-
```javascript
162-
waitForExpect(expectation: () => void, timeout?: number, interval?: number) => Promise<{}>;
163-
```
164-
165-
When in need to wait for non-deterministic periods of time you can use waitForExpect,
166-
to wait for your expectations to pass. Take a look at [`Is there a different way to wait for things to happen?`](#waitForExpect) part of the FAQ,
167-
or the function documentation here: [`wait-for-expect`](https://github.com/TheBrainFamily/wait-for-expect)
168-
or just take a look at this simple example:
169-
170-
```javascript
171-
...
172-
await waitForExpect(() => expect(queryByLabelText('username')).not.toBeNull())
173-
getByLabelText('username').value = 'chucknorris'
174-
...
175-
```
176-
177-
Another advantage of waitForExpect in comparison to flushPromises, is that
178-
flushPromises will not flush promises that have not been queued up already,
179-
for example, if they will queue up as a result of the initial promises.
180-
In consequence of that, you might have to call flushPromises multiple times to get your components
181-
to your desired state.
182-
183-
This can happen for example, when you integration test your apollo-connected react components
184-
that go a couple level deep, with queries fired up in consequent components.
185-
186145
### `render`
187146

188147
In the example above, the `render` method returns an object that has a few
@@ -283,6 +242,44 @@ const usernameInputElement = getByTestId('username-input')
283242
> Learn more about `data-testid`s from the blog post
284243
> ["Making your UI tests resilient to change"][data-testid-blog-post]
285244
245+
### `Simulate`
246+
247+
This is simply a re-export from the `Simulate` utility from
248+
`react-dom/test-utils`. See [the docs](https://reactjs.org/docs/test-utils.html#simulate).
249+
250+
### `wait`
251+
252+
Defined as:
253+
254+
```typescript
255+
function wait(
256+
callback?: () => void,
257+
options?: {
258+
timeout?: number
259+
interval?: number
260+
},
261+
): Promise<void>
262+
```
263+
264+
When in need to wait for non-deterministic periods of time you can use `wait`,
265+
to wait for your expectations to pass. The `wait` function is a small wrapper
266+
around the
267+
[`wait-for-expect`](https://github.com/TheBrainFamily/wait-for-expect) module.
268+
Here's a simple example:
269+
270+
```javascript
271+
// ...
272+
// wait until the callback does not throw an error. In this case, that means
273+
// it'll wait until we can get a form control with a label that matches "username"
274+
await wait(() => getByLabelText('username'))
275+
getByLabelText('username').value = 'chucknorris'
276+
// ...
277+
```
278+
279+
This can be useful when (for example) you integration test your apollo-connected
280+
react components that go a couple level deep, with queries fired up in
281+
consequent components.
282+
286283
## Custom Jest Matchers
287284

288285
There are two simple API which extend the `expect` API of jest for making assertions easier.
@@ -600,60 +597,26 @@ react components.
600597

601598
</details>
602599

603-
<details>
604-
605-
<summary>How does flushPromises work and why would I need it?</summary>
606-
607-
As mentioned [before](#flushpromises), `flushPromises` uses
608-
[`setImmediate`][set-immediate] to schedule resolving a promise after any pending
609-
tasks in
610-
[the message queue](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop)
611-
are processed. This includes any promises fired before in your test.
600+
## Deprecated APIs
612601

613-
If there are promise callbacks already in JavaScript's message queue pending to be
614-
processed at the time `flushPromises` is called, then these will be processed before
615-
the promise returned by `flushPromises` is resolved. So when you
616-
`await flushPromises()` the code immediately after it is guaranteed to occur after
617-
all the side effects of your async requests have ocurred. This includes any data
618-
your test components might have requested.
619-
620-
This is useful for instance, if your components perform any data requests and update
621-
their state with the results when the request is resolved. It's important to note
622-
that this is only effective if you've mocked out your async requests to resolve
623-
immediately (like the `axios` mock we have in the examples). It will not `await`
624-
for promises that are not already resolved by the time you attempt to flush them.
625-
626-
In case this doesn't work for you the way you would expect, take a look at the
627-
waitForExpect function that should be much more intuitive to use.
628-
629-
</details>
630-
631-
<details>
632-
633-
<summary><a name="waitForExpectFAQ"></a>Is there a different way to wait for things to happen? For example for end to end or contract tests?</summary>
634-
Definitely! There is an abstraction called `waitForExpect` that will keep
635-
calling your expectations until a timeout or the expectation passes - whatever happens first.
636-
637-
Please take a look at this example (taken from [`here`](https://github.com/kentcdodds/react-testing-library/blob/master/src/__tests__/end-to-end.js)):
638-
639-
```javascript
640-
import {render, waitForExpect} from 'react-testing-library'
641-
test('it waits for the data to be loaded', async () => {
642-
const {queryByText, queryByTestId} = render(<ComponentWithLoader />)
643-
644-
// Initially the loader shows
645-
expect(queryByText('Loading...')).toBeTruthy()
646-
647-
// This will pass when the state of the component changes once the data is available
648-
// the loader will disappear, and the data will be shown
649-
await waitForExpect(() => expect(queryByText('Loading...')).toBeNull())
650-
expect(queryByTestId('message').textContent).toMatch(/Hello World/)
651-
})
652-
```
602+
### `flushPromises`
653603

654-
For consistency and making your tests easier to understand, you can use it instead of flushPromises.
604+
> This API was deprecated in favor of [`wait`](#wait). We try to avoid having
605+
> two ways to do the same thing and you can accomplish everything with `wait`
606+
> that you could with `flushPromises`. A big advantage of `wait`, is that
607+
> `flushPromises` will not flush promises that have not been queued up already,
608+
> for example, if they will queue up as a result of the initial promises. In
609+
> consequence of that, you might have to call `flushPromises` multiple times to
610+
> get your components to your desired state. You can accomplish the exact same
611+
> behavior with `wait` as you had with `flushPromises` by calling `wait` with
612+
> no arguments: `await wait()`
655613

656-
</details>
614+
This is a simple utility that's useful for when your component is doing some
615+
async work that you've mocked out, but you still need to wait until the next
616+
tick of the event loop before you can continue your assertions. It simply
617+
returns a promise that resolves in a `setImmediate`. Especially useful when
618+
you make your test function an `async` function and use
619+
`await flushPromises()`.
657620

658621
## Other Solutions
659622

src/__tests__/deprecated.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {flushPromises, waitForExpect} from '../'
2+
3+
test('flushPromises (DEPRECATED) still works', async () => {
4+
const fn = jest.fn()
5+
Promise.resolve().then(fn)
6+
await flushPromises()
7+
expect(fn).toHaveBeenCalledTimes(1)
8+
})
9+
10+
test('waitForExpect (DEPRECATED) still works', async () => {
11+
const fn = jest.fn()
12+
Promise.resolve().then(fn)
13+
await waitForExpect(() => expect(fn).toHaveBeenCalledTimes(1))
14+
})

src/__tests__/end-to-end.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react'
2-
import {render, waitForExpect} from '../'
2+
import {render, wait} from '../'
33

44
const fetchAMessage = () =>
55
new Promise(resolve => {
@@ -35,6 +35,6 @@ test('it waits for the data to be loaded', async () => {
3535

3636
expect(queryByText('Loading...')).toBeTruthy()
3737

38-
await waitForExpect(() => expect(queryByText('Loading...')).toBeNull())
38+
await wait(() => expect(queryByText('Loading...')).toBeNull())
3939
expect(queryByTestId('message').textContent).toMatch(/Hello World/)
4040
})

src/__tests__/fetch.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react'
22
import axiosMock from 'axios'
3-
import {render, Simulate, flushPromises} from '../'
3+
import {render, Simulate, wait} from '../'
44

55
// instead of importing it, we'll define it inline here
66
// import Fetch from '../fetch'
@@ -40,7 +40,7 @@ test('Fetch makes an API call and displays the greeting when load-greeting is cl
4040
// Act
4141
Simulate.click(getByText('Fetch'))
4242

43-
await flushPromises()
43+
await wait()
4444

4545
// Assert
4646
expect(axiosMock.get).toHaveBeenCalledTimes(1)

src/index.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,8 @@ function flushPromises() {
2525
return new Promise(resolve => setImmediate(resolve))
2626
}
2727

28-
export {render, flushPromises, Simulate, waitForExpect}
28+
function wait(callback = () => {}, {timeout, interval} = {}) {
29+
return waitForExpect(callback, timeout, interval)
30+
}
31+
32+
export {render, flushPromises, Simulate, wait, waitForExpect}

typings/index.d.ts

+8
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,11 @@ export function flushPromises(): Promise<void>
2424
export const Simulate: typeof ReactSimulate
2525

2626
export function waitForExpect(): typeof waitForExpect
27+
28+
export default function wait(
29+
callback?: () => void,
30+
options?: {
31+
timeout?: number
32+
interval?: number
33+
},
34+
): Promise<void>

0 commit comments

Comments
 (0)