From 720668c890e3bc54941d1653e65faa47b1cacb99 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 13:28:55 +0200 Subject: [PATCH 01/12] Wrapped waitFor call in act to support async waitFor/findBy --- src/waitFor.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/waitFor.js b/src/waitFor.js index 5275643e5..60b1b66d9 100644 --- a/src/waitFor.js +++ b/src/waitFor.js @@ -1,5 +1,6 @@ // @flow +import act from './act'; import { throwRemovedFunctionError } from './helpers/errors'; const DEFAULT_TIMEOUT = 4500; @@ -10,7 +11,7 @@ export type WaitForOptions = { interval?: number, }; -export default function waitFor( +function waitForInternal( expectation: () => T, options?: WaitForOptions ): Promise { @@ -38,6 +39,21 @@ export default function waitFor( }); } +export default async function waitFor( + expectation: () => T, + options?: WaitForOptions +): Promise { + let result: T; + + //$FlowFixMe: this is just too complicated for flow + await act(async () => { + result = await waitForInternal(expectation, options); + }); + + //$FlowFixMe: either we have result or `waitFor` there error + return result; +} + export function waitForElement( expectation: () => T, _timeout: number = 4500, From 0ce1c10a9b05dc9c19a2f6940d61c0e578e8d867 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 13:40:59 +0200 Subject: [PATCH 02/12] Updated docs --- website/docs/API.md | 6 +++++- website/docs/GettingStarted.md | 4 ++++ website/docs/Queries.md | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/website/docs/API.md b/website/docs/API.md index 5d2adc734..c1290d92c 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 (featuing 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..8cab45ebe 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 (featuing 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/Queries.md b/website/docs/Queries.md index a0c0fd705..0be5a912e 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 (featuing 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. ::: From 4e6de626c30df08a0907d958054110d099d74a43 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 13:53:08 +0200 Subject: [PATCH 03/12] Spelling mistake --- src/waitFor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/waitFor.js b/src/waitFor.js index 60b1b66d9..bdd652071 100644 --- a/src/waitFor.js +++ b/src/waitFor.js @@ -50,7 +50,7 @@ export default async function waitFor( result = await waitForInternal(expectation, options); }); - //$FlowFixMe: either we have result or `waitFor` there error + //$FlowFixMe: either we have result or `waitFor` threw error return result; } From b14a61a7979c89075ab8923d5e117276871056e3 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 13:58:28 +0200 Subject: [PATCH 04/12] Added short info in migration guide --- website/docs/MigrationV2.md | 2 ++ 1 file changed, 2 insertions(+) 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. ::: From 83ded1bdf3c4d29e9ba1cfa4b271235c47949368 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 14:02:32 +0200 Subject: [PATCH 05/12] Corrected spelling --- website/docs/API.md | 2 +- website/docs/GettingStarted.md | 2 +- website/docs/Queries.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/API.md b/website/docs/API.md index c1290d92c..a5ad19ed1 100644 --- a/website/docs/API.md +++ b/website/docs/API.md @@ -337,7 +337,7 @@ 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 (featuing async `act`) or React Native >=0.60 (which comes with React >=16.9.0). +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 diff --git a/website/docs/GettingStarted.md b/website/docs/GettingStarted.md index 8cab45ebe..ebe68f750 100644 --- a/website/docs/GettingStarted.md +++ b/website/docs/GettingStarted.md @@ -67,7 +67,7 @@ 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 (featuing async `act`) or React Native >=0.60 (which comes with React >=16.9.0). +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 diff --git a/website/docs/Queries.md b/website/docs/Queries.md index 0be5a912e..5a288b119 100644 --- a/website/docs/Queries.md +++ b/website/docs/Queries.md @@ -33,7 +33,7 @@ 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 (featuing async `act`) or React Native >=0.60 (which comes with React >=16.9.0). +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 From 0059fd52f80c645c245e6e1fe84dab39727511d7 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 14:47:29 +0200 Subject: [PATCH 06/12] Clarified comments --- src/waitFor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/waitFor.js b/src/waitFor.js index bdd652071..829b297e7 100644 --- a/src/waitFor.js +++ b/src/waitFor.js @@ -45,7 +45,7 @@ export default async function waitFor( ): Promise { let result: T; - //$FlowFixMe: this is just too complicated for flow + //$FlowFixMe: `act` has incorrect typing await act(async () => { result = await waitForInternal(expectation, options); }); From 4a84f33a8a98405c7fa67654cb40a7a54c1912aa Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 15:27:08 +0200 Subject: [PATCH 07/12] Added async act implementation conditional on React version --- src/waitFor.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/waitFor.js b/src/waitFor.js index 829b297e7..a9cfa1126 100644 --- a/src/waitFor.js +++ b/src/waitFor.js @@ -1,11 +1,21 @@ // @flow +import 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((n) => parseInt(n, 10)); + + return actualMajor > major || (actualMajor == major && actualMinor >= minor); +} + export type WaitForOptions = { timeout?: number, interval?: number, @@ -43,9 +53,13 @@ export default async function waitFor( expectation: () => T, options?: WaitForOptions ): Promise { + if (!checkReactVersionAtLeast(16, 9)) { + return await waitForInternal(expectation, options); + } + let result: T; - //$FlowFixMe: `act` has incorrect typing + //$FlowFixMe: `act` has incorrect flow typing await act(async () => { result = await waitForInternal(expectation, options); }); From c7eeb07c0d8fede6ce6857f5178116daf6c49f11 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 15:35:20 +0200 Subject: [PATCH 08/12] Code review changes --- src/waitFor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/waitFor.js b/src/waitFor.js index a9cfa1126..d27f7bb15 100644 --- a/src/waitFor.js +++ b/src/waitFor.js @@ -54,7 +54,7 @@ export default async function waitFor( options?: WaitForOptions ): Promise { if (!checkReactVersionAtLeast(16, 9)) { - return await waitForInternal(expectation, options); + return waitForInternal(expectation, options); } let result: T; From d5464b16fbb71ed4619cfaf0f13cd01fa84c4bea Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 15:36:47 +0200 Subject: [PATCH 09/12] Update src/waitFor.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michał Pierzchała --- src/waitFor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/waitFor.js b/src/waitFor.js index d27f7bb15..a68fea603 100644 --- a/src/waitFor.js +++ b/src/waitFor.js @@ -11,7 +11,7 @@ function checkReactVersionAtLeast(major: number, minor: number): boolean { if (React.version === undefined) return false; const [actualMajor, actualMinor] = React.version .split('.') - .map((n) => parseInt(n, 10)); + .map(Number); return actualMajor > major || (actualMajor == major && actualMinor >= minor); } From e23fcefc9350fa5da2e5ef1dccf1118c6d72f0c0 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 15:36:54 +0200 Subject: [PATCH 10/12] Update src/waitFor.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michał Pierzchała --- src/waitFor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/waitFor.js b/src/waitFor.js index a68fea603..376b6b5cc 100644 --- a/src/waitFor.js +++ b/src/waitFor.js @@ -13,7 +13,7 @@ function checkReactVersionAtLeast(major: number, minor: number): boolean { .split('.') .map(Number); - return actualMajor > major || (actualMajor == major && actualMinor >= minor); + return actualMajor > major || (actualMajor === major && actualMinor >= minor); } export type WaitForOptions = { From f6b0fe4bba33eb7d78b9ed00acdb73e097b137dc Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 15:40:04 +0200 Subject: [PATCH 11/12] Fixed prettier --- src/waitFor.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/waitFor.js b/src/waitFor.js index 376b6b5cc..ffa0bd143 100644 --- a/src/waitFor.js +++ b/src/waitFor.js @@ -9,9 +9,7 @@ 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); + const [actualMajor, actualMinor] = React.version.split('.').map(Number); return actualMajor > major || (actualMajor === major && actualMinor >= minor); } From 99421af417d07077d7eacd177e26106976fc5bb7 Mon Sep 17 00:00:00 2001 From: Maciej Jastrzebski Date: Thu, 21 May 2020 15:49:31 +0200 Subject: [PATCH 12/12] Update src/waitFor.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Michał Pierzchała --- src/waitFor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/waitFor.js b/src/waitFor.js index ffa0bd143..1820dbe88 100644 --- a/src/waitFor.js +++ b/src/waitFor.js @@ -1,6 +1,6 @@ // @flow -import React from 'react'; +import * as React from 'react'; import act from './act'; import { throwRemovedFunctionError } from './helpers/errors';