diff --git a/src/waitFor.js b/src/waitFor.js index 5275643e5..1820dbe88 100644 --- a/src/waitFor.js +++ b/src/waitFor.js @@ -1,16 +1,25 @@ // @flow +import * as React from 'react'; +import act from './act'; import { throwRemovedFunctionError } from './helpers/errors'; const DEFAULT_TIMEOUT = 4500; const DEFAULT_INTERVAL = 50; +function checkReactVersionAtLeast(major: number, minor: number): boolean { + if (React.version === undefined) return false; + const [actualMajor, actualMinor] = React.version.split('.').map(Number); + + return actualMajor > major || (actualMajor === major && actualMinor >= minor); +} + export type WaitForOptions = { timeout?: number, interval?: number, }; -export default function waitFor( +function waitForInternal( expectation: () => T, options?: WaitForOptions ): Promise { @@ -38,6 +47,25 @@ export default function waitFor( }); } +export default async function waitFor( + expectation: () => T, + options?: WaitForOptions +): Promise { + if (!checkReactVersionAtLeast(16, 9)) { + return waitForInternal(expectation, options); + } + + let result: T; + + //$FlowFixMe: `act` has incorrect flow typing + await act(async () => { + result = await waitForInternal(expectation, options); + }); + + //$FlowFixMe: either we have result or `waitFor` threw error + return result; +} + export function waitForElement( expectation: () => T, _timeout: number = 4500, diff --git a/website/docs/API.md b/website/docs/API.md index 5d2adc734..a5ad19ed1 100644 --- a/website/docs/API.md +++ b/website/docs/API.md @@ -336,6 +336,10 @@ function waitFor( Waits for non-deterministic periods of time until your element appears or times out. `waitFor` periodically calls `expectation` every `interval` milliseconds to determine whether the element appeared or not. +:::info +In order to properly use `waitFor` you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.60 (which comes with React >=16.9.0). +::: + ```jsx import { render, waitFor } from 'react-testing-library'; @@ -403,4 +407,4 @@ expect(submitButtons).toHaveLength(3); // expect 3 elements ## `act` -Useful function to help testing components that use hooks API. By default any `render`, `update`, and `fireEvent` calls are wrapped by this function, so there is no need to wrap it manually. This method is re-exported from [`react-test-renderer`](https://github.com/facebook/react/blob/master/packages/react-test-renderer/src/ReactTestRenderer.js#L567]). +Useful function to help testing components that use hooks API. By default any `render`, `update`, `fireEvent`, and `waitFor` calls are wrapped by this function, so there is no need to wrap it manually. This method is re-exported from [`react-test-renderer`](https://github.com/facebook/react/blob/master/packages/react-test-renderer/src/ReactTestRenderer.js#L567]). diff --git a/website/docs/GettingStarted.md b/website/docs/GettingStarted.md index dc69fac3e..ebe68f750 100644 --- a/website/docs/GettingStarted.md +++ b/website/docs/GettingStarted.md @@ -66,6 +66,10 @@ This library has a peerDependencies listing for `react-test-renderer` and, of co As you may have noticed, it's not tied to React Native at all – you can safely use it in your React components if you feel like not interacting directly with DOM. +:::info +In order to properly use helpers for async tests (`findBy` queries and `waitFor`) you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.60 (which comes with React >=16.9.0). +::: + ### Additional Jest matchers In order to use addtional React Native-specific jest matchers from [@testing-library/jest-native](https://github.com/testing-library/jest-native) package add it to your project: diff --git a/website/docs/MigrationV2.md b/website/docs/MigrationV2.md index 9c1c08f53..2a0a5a98c 100644 --- a/website/docs/MigrationV2.md +++ b/website/docs/MigrationV2.md @@ -58,6 +58,8 @@ export default function waitFor( Both changes should improve code readibility. +`waitFor` calls (and hence also `findBy` queries) are now wrapped in `act` by default, so that you should no longer need to use `act` directly in your tests. + :::tip You can usually avoid `waitFor` by a proper use of `findBy` asynchronous queries. It will result in more streamlined testing experience. ::: diff --git a/website/docs/Queries.md b/website/docs/Queries.md index a0c0fd705..5a288b119 100644 --- a/website/docs/Queries.md +++ b/website/docs/Queries.md @@ -32,6 +32,10 @@ title: Queries `findAllBy` queries return a promise which resolves to an array when any matching elements are found. The promise is rejected if no elements match after a default timeout of 4500ms. +:::info +In order to properly use `findBy` and `findAllBy` queries you need at least React >=16.9.0 (featuring async `act`) or React Native >=0.60 (which comes with React >=16.9.0). +::: + :::info `findBy` and `findAllBy` queries accept optional `waitForOptions` object argument which can contain `timeout` and `interval` properies which have the same meaning as respective options for [`waitFor`](https://callstack.github.io/react-native-testing-library/docs/api#waitfor) function. :::