From c15707e5c0a9750b354b274125886edefe6b1bb6 Mon Sep 17 00:00:00 2001 From: Josh Ellis Date: Thu, 7 Jan 2021 13:58:55 +0000 Subject: [PATCH 01/14] docs: update readme --- README.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4674bda3..431bcbf2 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ + - [The problem](#the-problem) - [The solution](#the-solution) - [When to use this library](#when-to-use-this-library) @@ -141,17 +142,21 @@ npm install --save-dev @testing-library/react-hooks ### Peer Dependencies `react-hooks-testing-library` does not come bundled with a version of -[`react`](https://www.npmjs.com/package/react) or -[`react-test-renderer`](https://www.npmjs.com/package/react-test-renderer) to allow you to install -the specific version you want to test against. Generally, the installed versions for `react` and -`react-test-renderer` should have matching versions: +[`react`](https://www.npmjs.com/package/react) to allow you to install the specific version you want +to test against. It also does not come installed with a specific renderer, we currently support +[`react-test-renderer`](https://www.npmjs.com/package/react-test-renderer) and +[`react-dom`](https://www.npmjs.com/package/react-dom), you only need to install one of them. +However,you can install both, but `react-test-renderer` is the default, for more information see the +[installation docs](https://react-hooks-testing-library.com/#installation). Generally, the installed +versions for `react` and the selected renderer should have matching versions: ```sh npm install react@^16.9.0 npm install --save-dev react-test-renderer@^16.9.0 ``` -> **NOTE: The minimum supported version of `react` and `react-test-renderer` is `^16.9.0`.** +> **NOTE: The minimum supported version of `react`, `react-test-renderer` and `react-dom` is +> `^16.9.0`.** ## API From 34fa6829c9b8044b02bd7804806a5fa7e969ab4b Mon Sep 17 00:00:00 2001 From: Josh Ellis Date: Fri, 8 Jan 2021 12:02:17 +0000 Subject: [PATCH 02/14] docs: add renderer doc --- docs/renderer.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ doczrc.js | 1 + 2 files changed, 62 insertions(+) create mode 100644 docs/renderer.md diff --git a/docs/renderer.md b/docs/renderer.md new file mode 100644 index 00000000..ead03e69 --- /dev/null +++ b/docs/renderer.md @@ -0,0 +1,61 @@ +--- +name: Renderer +route: '/renderer' +--- + +# Render Engine + +## Overview + +React requires a rendering engine, typically when creating an application people use `react-dom`. +When running tests, React still requires an engine. We currently support two different engines – +`react-test-renderer` & `react-dom`. If you have both installed in your project, by default we will +use `react-test-renderer`, assuming you're using the default imports: + +```js +import { renderHook } from '@testing-library/react-hooks' +``` + +It does this because the library runs a check for available renderers, in the order: + +- `react-test-renderer` +- `react-dom` + +If neither are available you will see an error asking you to check that one of the above is +installed. If only one is installed, then it will use that renderer. + +## Being specific + +If, however, for certain tests you want to use a specific renderer (e.g. you want to use `react-dom` +for SSR) you can import the server module directly: + +```ts +import { renderHook } from '@testing-library/react-hooks/server` +``` + +We have the following exports available: + +```ts +import { renderHook, act } from '@testing-library/react-hooks' // will try to auto-detect + +import { renderHook, act } from '@testing-library/react-hooks/dom' // will use react-dom + +import { renderHook, act } from '@testing-library/react-hooks/native' // will use react-test-renderer + +import { renderHook, act } from '@testing-library/react-hooks/server' // will use react-dom +``` + +## Caveats + +### SSR + +While calling `renderHook` from `@testing-library/react-hooks/native` and +`@testing-library/react-hooks/dom` will return the same `RenderHookResult` as documented +[here](/reference/api#renderhook-result), using `@testing-library/react-hooks/server` will return an +additional function: + +```ts +hydrate: () => void +``` + +For more information on `hydrate` see the [API documentation](/reference/api#hydrate) diff --git a/doczrc.js b/doczrc.js index 965cfbe2..c370d14b 100644 --- a/doczrc.js +++ b/doczrc.js @@ -19,6 +19,7 @@ export default { menu: [ { name: 'Introduction' }, { name: 'Usage', menu: ['Basic Hooks', 'Advanced Hooks'] }, + { name: 'Renderer' }, { name: 'API Reference' } ] } From 684b2f14619ff331d75ee92f3889b056d8c6d172 Mon Sep 17 00:00:00 2001 From: Josh Ellis Date: Fri, 8 Jan 2021 12:03:09 +0000 Subject: [PATCH 03/14] docs: copy readme updates to introduction --- docs/introduction.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/introduction.md b/docs/introduction.md index 70d2f505..d803a91d 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -68,17 +68,21 @@ npm install --save-dev @testing-library/react-hooks ### Peer Dependencies `react-hooks-testing-library` does not come bundled with a version of -[`react`](https://www.npmjs.com/package/react) or -[`react-test-renderer`](https://www.npmjs.com/package/react-test-renderer) to allow you to install -the specific version you want to test against. Generally, the installed versions for `react` and -`react-test-renderer` should have matching versions: +[`react`](https://www.npmjs.com/package/react) to allow you to install the specific version you want +to test against. It also does not come installed with a specific renderer, we currently support +[`react-test-renderer`](https://www.npmjs.com/package/react-test-renderer) and +[`react-dom`](https://www.npmjs.com/package/react-dom), you only need to install one of them. +However,you can install both, but `react-test-renderer` is the default, for more information see the +[installation docs](https://react-hooks-testing-library.com/#installation). Generally, the installed +versions for `react` and the selected renderer should have matching versions: ```sh npm install react@^16.9.0 npm install --save-dev react-test-renderer@^16.9.0 ``` -> **NOTE: The minimum supported version of `react` and `react-test-renderer` is `^16.9.0`.** +> **NOTE: The minimum supported version of `react`, `react-test-renderer` and `react-dom` is +> `^16.9.0`.** ## Testing Framework From 8abd2f0186aa9e53b780bb5f9bab4624055d5ac9 Mon Sep 17 00:00:00 2001 From: Josh Ellis Date: Fri, 8 Jan 2021 12:03:56 +0000 Subject: [PATCH 04/14] docs: update api-reference Also update examples to be more (imo) TS like --- docs/api-reference.md | 63 +++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index fa7daf4b..c5c35495 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -11,16 +11,17 @@ route: '/reference/api' - [`act`](/reference/api#act) - [`cleanup`](/reference/api#cleanup) - [`addCleanup`](/reference/api#addcleanup) +- [`removeCleanup`](/reference/api#removecleanup) --- ## `renderHook` -```js -function renderHook( - callback: function(props?: any): any, +```ts +renderHook: ( + callback: (props?: any): any, options?: RenderHookOptions -): RenderHookResult +) => RenderHookResult ``` Renders a test component that will call the provided `callback`, including any hooks it calls, every @@ -61,7 +62,7 @@ The `renderHook` function returns an object that has the following properties: ### `result` -```js +```ts { all: Array current: any, @@ -77,8 +78,8 @@ returned at the time. ### `rerender` -```js -function rerender(newProps?: any): void +```ts +rerender: (newProps?: any) => void ``` A function to rerender the test component, causing any hooks to be recalculated. If `newProps` are @@ -86,13 +87,24 @@ passed, they will replace the `callback` function's `initialProps` for subsequen ### `unmount` -```js -function unmount(): void +```ts +unmount: () => void ``` A function to unmount the test component. This is commonly used to trigger cleanup effects for `useEffect` hooks. +### `hydrate` + +```ts +hydrate: () => void +``` + +> This is only used when using the `server` module. See [Rendering](/renderer) for more information + +A function to hydrate the component. This is commonly used before `act` calls and after `rerender` +calls. + ### `...asyncUtils` Utilities to assist with testing asynchronous behaviour. See the @@ -102,15 +114,15 @@ Utilities to assist with testing asynchronous behaviour. See the ## `act` -This is the same [`act` function](https://reactjs.org/docs/test-utils.html#act) that is exported by -`react-test-renderer`. +This is the same [`act` function](https://reactjs.org/docs/test-utils.html#act) function that is +exported from your chosen renderer. Although, they both work the same. --- ## `cleanup` -```js -function cleanup: Promise +```ts +cleanup: () => Promise ``` Unmounts any rendered hooks rendered with `renderHook`, ensuring all effects have been flushed. Any @@ -142,7 +154,8 @@ module.exports = { ``` Alternatively, you can change your test to import from `@testing-library/react-hooks/pure` instead -of the regular imports. +of the regular imports. This applys to any of our export methods documented in +[Rendering](/rendering#being-specific). ```diff - import { renderHook, cleanup, act } from '@testing-library/react-hooks' @@ -156,8 +169,8 @@ variable to `true` before importing `@testing-library/react-hooks` will also dis ## `addCleanup` -```js -function addCleanup(callback: function(): void|Promise): function(): void +```ts +addCleanup: (callback: () => void | Promise) => () => void ``` Add a callback to be called during [`cleanup`](/reference/api#cleanup), returning a function to @@ -173,8 +186,8 @@ be resolved before moving onto the next cleanup callback. ## `removeCleanup` -```js -function removeCleanup(callback: function(): void|Promise): void +```ts +removeCleanup: (callback: () => void | Promise) => void ``` Removes a cleanup callback previously added with [`addCleanup`](/reference/api#addCleanup). Once @@ -187,10 +200,8 @@ removed, the provided callback will no longer execute as part of running ### `waitForNextUpdate` -```js -function waitForNextUpdate(options?: { - timeout?: number -}): Promise +```ts +waitForNextUpdate: (options?: { timeout?: number }) => Promise ``` Returns a `Promise` that resolves the next time the hook renders, commonly when state is updated as @@ -203,11 +214,11 @@ The maximum amount of time in milliseconds (ms) to wait. By default, no timeout ### `waitFor` ```js -function waitFor(callback: function(): boolean|void, options?: { +waitFor: (callback: () => boolean | void, options?: { interval?: number, timeout?: number, suppressErrors?: boolean -}): Promise +}) => Promise ``` Returns a `Promise` that resolves if the provided callback executes without exception and returns a @@ -233,11 +244,11 @@ rejected. By default, errors are suppressed for this utility. ### `waitForValueToChange` ```js -function waitForValueToChange(selector: function(): any, options?: { +waitForValueToChange: (selector: () => any, options?: { interval?: number, timeout?: number, suppressErrors?: boolean -}): Promise +}) => Promise ``` Returns a `Promise` that resolves if the value returned from the provided selector changes. It is From f59f5683bbe22edfeea1ae49444ea2f2a3f6b5b5 Mon Sep 17 00:00:00 2001 From: Josh Ellis Date: Sun, 10 Jan 2021 21:48:19 +0000 Subject: [PATCH 05/14] refactor: revert examples --- docs/api-reference.md | 48 ++++++++++++++++++++++++------------------- docs/renderer.md | 2 +- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index c5c35495..189d7ea7 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -18,10 +18,10 @@ route: '/reference/api' ## `renderHook` ```ts -renderHook: ( +function renderHook( callback: (props?: any): any, options?: RenderHookOptions -) => RenderHookResult +): RenderHookResult ``` Renders a test component that will call the provided `callback`, including any hooks it calls, every @@ -79,7 +79,7 @@ returned at the time. ### `rerender` ```ts -rerender: (newProps?: any) => void +function rerender(newProps?: any): void ``` A function to rerender the test component, causing any hooks to be recalculated. If `newProps` are @@ -88,7 +88,7 @@ passed, they will replace the `callback` function's `initialProps` for subsequen ### `unmount` ```ts -unmount: () => void +function unmount(): void ``` A function to unmount the test component. This is commonly used to trigger cleanup effects for @@ -97,7 +97,7 @@ A function to unmount the test component. This is commonly used to trigger clean ### `hydrate` ```ts -hydrate: () => void +function hydrate(): void ``` > This is only used when using the `server` module. See [Rendering](/renderer) for more information @@ -122,7 +122,7 @@ exported from your chosen renderer. Although, they both work the same. ## `cleanup` ```ts -cleanup: () => Promise +function cleanup(): Promise ``` Unmounts any rendered hooks rendered with `renderHook`, ensuring all effects have been flushed. Any @@ -170,7 +170,7 @@ variable to `true` before importing `@testing-library/react-hooks` will also dis ## `addCleanup` ```ts -addCleanup: (callback: () => void | Promise) => () => void +function addCleanup(callback: () => void | Promise): (): void ``` Add a callback to be called during [`cleanup`](/reference/api#cleanup), returning a function to @@ -187,7 +187,7 @@ be resolved before moving onto the next cleanup callback. ## `removeCleanup` ```ts -removeCleanup: (callback: () => void | Promise) => void +function removeCleanup(callback: () => void | Promise): void ``` Removes a cleanup callback previously added with [`addCleanup`](/reference/api#addCleanup). Once @@ -201,7 +201,7 @@ removed, the provided callback will no longer execute as part of running ### `waitForNextUpdate` ```ts -waitForNextUpdate: (options?: { timeout?: number }) => Promise +function waitForNextUpdate(options?: { timeout?: number }): Promise ``` Returns a `Promise` that resolves the next time the hook renders, commonly when state is updated as @@ -213,12 +213,15 @@ The maximum amount of time in milliseconds (ms) to wait. By default, no timeout ### `waitFor` -```js -waitFor: (callback: () => boolean | void, options?: { - interval?: number, - timeout?: number, - suppressErrors?: boolean -}) => Promise +```ts +function waitFor( + callback: () => boolean | void, + options?: { + interval?: number + timeout?: number + suppressErrors?: boolean + } +): Promise ``` Returns a `Promise` that resolves if the provided callback executes without exception and returns a @@ -243,12 +246,15 @@ rejected. By default, errors are suppressed for this utility. ### `waitForValueToChange` -```js -waitForValueToChange: (selector: () => any, options?: { - interval?: number, - timeout?: number, - suppressErrors?: boolean -}) => Promise +```ts +function waitForValueToChange( + selector: () => any, + options?: { + interval?: number + timeout?: number + suppressErrors?: boolean + } +): Promise ``` Returns a `Promise` that resolves if the value returned from the provided selector changes. It is diff --git a/docs/renderer.md b/docs/renderer.md index ead03e69..a79a1971 100644 --- a/docs/renderer.md +++ b/docs/renderer.md @@ -55,7 +55,7 @@ While calling `renderHook` from `@testing-library/react-hooks/native` and additional function: ```ts -hydrate: () => void +function hydrate(): void ``` For more information on `hydrate` see the [API documentation](/reference/api#hydrate) From 71762aa56e21f02c2e8a23da5d694bdf589df61d Mon Sep 17 00:00:00 2001 From: Josh Ellis Date: Sun, 10 Jan 2021 21:50:17 +0000 Subject: [PATCH 06/14] refactor: Include more caveats --- docs/renderer.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/renderer.md b/docs/renderer.md index a79a1971..6fda903e 100644 --- a/docs/renderer.md +++ b/docs/renderer.md @@ -47,6 +47,10 @@ import { renderHook, act } from '@testing-library/react-hooks/server' // will us ## Caveats +## Auto detect + +The auto detection function may not work if tests are bundled to run in the browser. + ### SSR While calling `renderHook` from `@testing-library/react-hooks/native` and @@ -58,4 +62,5 @@ additional function: function hydrate(): void ``` -For more information on `hydrate` see the [API documentation](/reference/api#hydrate) +Remember, state will not update with SSR unless `hydrate` is called. For more information on +`hydrate` see the [API documentation](/reference/api#hydrate). From 7481d7764a32024f5e15d8469fa7a0c9e5abd6d4 Mon Sep 17 00:00:00 2001 From: Josh Ellis Date: Mon, 11 Jan 2021 10:57:47 +0000 Subject: [PATCH 07/14] docs: create installation page and remove SSR to be in own page --- docs/installation.md | 81 ++++++++++++++++++++++++++++++++++++++++++++ docs/introduction.md | 34 ------------------- docs/renderer.md | 66 ------------------------------------ doczrc.js | 2 +- 4 files changed, 82 insertions(+), 101 deletions(-) create mode 100644 docs/installation.md delete mode 100644 docs/renderer.md diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..6f36d2c4 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,81 @@ +--- +name: Installation +route: '/installation' +--- + +# Installation + +## Getting started + +This module is distributed via [npm](https://www.npmjs.com/) which is bundled with +[node](https://nodejs.org) and should be installed as one of your project's `devDependencies`: + +```sh +# if you're using npm +npm install --save-dev @testing-library/react-hooks +# if you're using yarn +yarn add --dev @testing-library/react-hooks +``` + +### Peer Dependencies + +`react-hooks-testing-library` does not come bundled with a version of +[`react`](https://www.npmjs.com/package/react) to allow you to install the specific version you want +to test against. It also does not come installed with a specific renderer, we currently support +[`react-test-renderer`](https://www.npmjs.com/package/react-test-renderer) and +[`react-dom`](https://www.npmjs.com/package/react-dom), you only need to install one of them. For +more information see [Renderer](/installation#renderer) + +```sh +npm install react@^16.9.0 +npm install --save-dev react-test-renderer@^16.9.0 +``` + +> **NOTE: The minimum supported version of `react`, `react-test-renderer` and `react-dom` is +> `^16.9.0`.** + +## Renderer + +React requires a rendering engine, typically when creating an application people use `react-dom`. +When running tests, React still requires an engine. We currently support two different engines: + +- `react-test-renderer` +- `react-dom` + +If you have both installed in your project, assuming you're using the default imports (see below) +the library defaults to using `react-test-renderer`. This is because rtr is the defacto test +renderer for `react-native` for tests and it enables hooks to be correctly tested that are written +for both `react` & `react-native`. + +```js +import { renderHook } from '@testing-library/react-hooks' +``` + +> The auto detection function may not work if tests are bundled to run in the browser. + +## Being specific + +If, however, for certain tests you want to use a specific renderer (e.g. you want to use `react-dom` +for SSR) you can import the server module directly: + +```ts +import { renderHook } from '@testing-library/react-hooks/server` +``` + +We have the following exports available: + +```ts +import { renderHook, act } from '@testing-library/react-hooks' // will try to auto-detect + +import { renderHook, act } from '@testing-library/react-hooks/dom' // will use react-dom + +import { renderHook, act } from '@testing-library/react-hooks/native' // will use react-test-renderer + +import { renderHook, act } from '@testing-library/react-hooks/server' // will use react-dom +``` + +## Testing Framework + +In order to run tests, you will probably want to be using a test framework. If you have not already +got one, we recommend using [Jest](https://jestjs.io/), but this library should work without issues +with any of the alternatives. diff --git a/docs/introduction.md b/docs/introduction.md index d803a91d..5c06f357 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -55,37 +55,3 @@ the results. 1. Your hook is defined alongside a component and is only used there 2. Your hook is easy to test by just testing the components using it - -## Installation - -This module is distributed via [npm](https://www.npmjs.com/) which is bundled with -[node](https://nodejs.org) and should be installed as one of your project's `devDependencies`: - -```sh -npm install --save-dev @testing-library/react-hooks -``` - -### Peer Dependencies - -`react-hooks-testing-library` does not come bundled with a version of -[`react`](https://www.npmjs.com/package/react) to allow you to install the specific version you want -to test against. It also does not come installed with a specific renderer, we currently support -[`react-test-renderer`](https://www.npmjs.com/package/react-test-renderer) and -[`react-dom`](https://www.npmjs.com/package/react-dom), you only need to install one of them. -However,you can install both, but `react-test-renderer` is the default, for more information see the -[installation docs](https://react-hooks-testing-library.com/#installation). Generally, the installed -versions for `react` and the selected renderer should have matching versions: - -```sh -npm install react@^16.9.0 -npm install --save-dev react-test-renderer@^16.9.0 -``` - -> **NOTE: The minimum supported version of `react`, `react-test-renderer` and `react-dom` is -> `^16.9.0`.** - -## Testing Framework - -In order to run tests, you will probably want to be using a test framework. If you have not already -got one, we recommend using [Jest](https://jestjs.io/), but this library should work without issues -with any of the alternatives. diff --git a/docs/renderer.md b/docs/renderer.md deleted file mode 100644 index 6fda903e..00000000 --- a/docs/renderer.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -name: Renderer -route: '/renderer' ---- - -# Render Engine - -## Overview - -React requires a rendering engine, typically when creating an application people use `react-dom`. -When running tests, React still requires an engine. We currently support two different engines – -`react-test-renderer` & `react-dom`. If you have both installed in your project, by default we will -use `react-test-renderer`, assuming you're using the default imports: - -```js -import { renderHook } from '@testing-library/react-hooks' -``` - -It does this because the library runs a check for available renderers, in the order: - -- `react-test-renderer` -- `react-dom` - -If neither are available you will see an error asking you to check that one of the above is -installed. If only one is installed, then it will use that renderer. - -## Being specific - -If, however, for certain tests you want to use a specific renderer (e.g. you want to use `react-dom` -for SSR) you can import the server module directly: - -```ts -import { renderHook } from '@testing-library/react-hooks/server` -``` - -We have the following exports available: - -```ts -import { renderHook, act } from '@testing-library/react-hooks' // will try to auto-detect - -import { renderHook, act } from '@testing-library/react-hooks/dom' // will use react-dom - -import { renderHook, act } from '@testing-library/react-hooks/native' // will use react-test-renderer - -import { renderHook, act } from '@testing-library/react-hooks/server' // will use react-dom -``` - -## Caveats - -## Auto detect - -The auto detection function may not work if tests are bundled to run in the browser. - -### SSR - -While calling `renderHook` from `@testing-library/react-hooks/native` and -`@testing-library/react-hooks/dom` will return the same `RenderHookResult` as documented -[here](/reference/api#renderhook-result), using `@testing-library/react-hooks/server` will return an -additional function: - -```ts -function hydrate(): void -``` - -Remember, state will not update with SSR unless `hydrate` is called. For more information on -`hydrate` see the [API documentation](/reference/api#hydrate). diff --git a/doczrc.js b/doczrc.js index c370d14b..9c6bd79e 100644 --- a/doczrc.js +++ b/doczrc.js @@ -18,8 +18,8 @@ export default { }, menu: [ { name: 'Introduction' }, + { name: 'Installation' }, { name: 'Usage', menu: ['Basic Hooks', 'Advanced Hooks'] }, - { name: 'Renderer' }, { name: 'API Reference' } ] } From e107bd9bc55c2df486aa8d7962f41a4b9fc1a62f Mon Sep 17 00:00:00 2001 From: Josh <37798644+joshuaellis@users.noreply.github.com> Date: Mon, 11 Jan 2021 12:17:35 +0000 Subject: [PATCH 08/14] docs: Update README.md with suggestion Co-authored-by: Michael Peyper --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 431bcbf2..bc2d9bcd 100644 --- a/README.md +++ b/README.md @@ -145,10 +145,11 @@ npm install --save-dev @testing-library/react-hooks [`react`](https://www.npmjs.com/package/react) to allow you to install the specific version you want to test against. It also does not come installed with a specific renderer, we currently support [`react-test-renderer`](https://www.npmjs.com/package/react-test-renderer) and -[`react-dom`](https://www.npmjs.com/package/react-dom), you only need to install one of them. -However,you can install both, but `react-test-renderer` is the default, for more information see the -[installation docs](https://react-hooks-testing-library.com/#installation). Generally, the installed -versions for `react` and the selected renderer should have matching versions: +[`react-dom`](https://www.npmjs.com/package/react-dom). You only need to install one of them, +however, if you do have both installed, we will use `react-test-renderer` as the default. For more +information see the [installation docs](https://react-hooks-testing-library.com/#installation). +Generally, the installed versions for `react` and the selected renderer should have matching +versions: ```sh npm install react@^16.9.0 From 05dad4f997b3128d629f8d3c1764ed9c9d379e7d Mon Sep 17 00:00:00 2001 From: Josh Ellis Date: Mon, 11 Jan 2021 12:53:43 +0000 Subject: [PATCH 09/14] docs: add dedicated SSR page --- docs/api-reference.md | 8 ++-- docs/usage/ssr-hooks.md | 96 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 docs/usage/ssr-hooks.md diff --git a/docs/api-reference.md b/docs/api-reference.md index 189d7ea7..e4e4585d 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -100,10 +100,12 @@ A function to unmount the test component. This is commonly used to trigger clean function hydrate(): void ``` -> This is only used when using the `server` module. See [Rendering](/renderer) for more information +> This is only used when using the `server` module. See [SSR](/usage/ssr-hooks) for more information +> on server-side rendering your hooks. -A function to hydrate the component. This is commonly used before `act` calls and after `rerender` -calls. +A function to hydrate the component. This is required before you can interact with the hook, whether +that is an `act` or `rerender` call. Some effects such as `useEffect` will not be called unless +`hydrate` is called. ### `...asyncUtils` diff --git a/docs/usage/ssr-hooks.md b/docs/usage/ssr-hooks.md new file mode 100644 index 00000000..7889f1ff --- /dev/null +++ b/docs/usage/ssr-hooks.md @@ -0,0 +1,96 @@ +--- +name: SSR Hooks +menu: Usage +route: '/usage/ssr-hooks' +--- + +# Server Side Renderering + +## Setup + +To SSR your hook, you must ensure `react-dom >= 16.9.0` is installed in your project and then import +the server module in your test: + +```ts +import { renderHook } from '@testing-library/react-hooks/server' +``` + +## Render Hook + +`renderHook` when called returns the same result as documented in the +[API](/reference/api#renderhook-result) but includes an additional argument, `hydrate`: + +```ts +function hydrate(): void +``` + +The `hydrate` function is a light wrapper around +[`ReactDOM.hydrate`](https://reactjs.org/docs/react-dom.html#hydrate) but no arguments are required +as the library will pass the element & container for you. Remember, certain effects such as +`useEffect` will not run server side and `hydrate` must be called before those effects are +ran.`hydrate`is also necessary before the first `act` or `rerender` call. For more information on +`hydrate` see the [API documentation](/reference/api#hydrate). There is also an +[example below](/usage/ssr-hooks#example) + +## Example + +### Hydration + +```js +import { renderHook, act } from '@testing-library/react-hooks/server' + +describe('custom hook tests', () => { + function useCounter() { + const [count, setCount] = useState(0) + + const increment = useCallback(() => setCount(count + 1), [count]) + const decrement = useCallback(() => setCount(count - 1), [count]) + + return { count, increment, decrement } + } + + test('should decrement counter', () => { + const { result, hydrate } = renderHook(() => useCounter()) + + expect(result.current.count).toBe(0) + + // hydrate is called because we want to interact with the hook + hydrate() + + act(() => result.current.decrement()) + + expect(result.current.count).toBe(-1) + }) +}) +``` + +### Effects + +```js +describe('useEffect tests', () => { + test('should handle useEffect hook', () => { + const sideEffect = { 1: false, 2: false } + + const useEffectHook = ({ id }) => { + useEffect(() => { + sideEffect[id] = true + return () => { + sideEffect[id] = false + } + }, [id]) + } + + const { hydrate, rerender, unmount } = renderHook((id) => useEffectHook({ id }), { + initialProps: { id: 1 } + }) + + expect(sideEffect[1]).toBe(false) + expect(sideEffect[2]).toBe(false) + + hydrate() + + expect(sideEffect[1]).toBe(true) + expect(sideEffect[2]).toBe(false) + }) +}) +``` From c88c743645cc56690b0641cab9eeab9e8c42fcff Mon Sep 17 00:00:00 2001 From: Josh <37798644+joshuaellis@users.noreply.github.com> Date: Mon, 11 Jan 2021 13:01:07 +0000 Subject: [PATCH 10/14] docs: update with suggestions Co-authored-by: Michael Peyper --- docs/installation.md | 48 ++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 6f36d2c4..33f17f25 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -36,42 +36,60 @@ npm install --save-dev react-test-renderer@^16.9.0 ## Renderer -React requires a rendering engine, typically when creating an application people use `react-dom`. -When running tests, React still requires an engine. We currently support two different engines: +When running tests, a renderer is required in order to render the React component we wrap around +your hook. We currently support two different renderers: - `react-test-renderer` - `react-dom` -If you have both installed in your project, assuming you're using the default imports (see below) -the library defaults to using `react-test-renderer`. This is because rtr is the defacto test -renderer for `react-native` for tests and it enables hooks to be correctly tested that are written -for both `react` & `react-native`. +When using standard import for this library (show below), we will attempt to auto-detect which +renderer you have installed and use it without needing any specific wiring up to make it happen. If +you have both installed in your project, and you use the standard import (see below) the library +will default to using `react-test-renderer`. + +> We use `react-test-renderer` by default as it enables hooks to be tested that are designed for +> either `react` or `react-native` and it is compatible with more test runners out-of-the-box as +> there is no DOM requirement to use it. + +The standard import looks like: ```js import { renderHook } from '@testing-library/react-hooks' ``` -> The auto detection function may not work if tests are bundled to run in the browser. +> Note: The auto detection function may not work if tests are bundles before execution (e.g. to be +> run in a browser) -## Being specific +### Act -If, however, for certain tests you want to use a specific renderer (e.g. you want to use `react-dom` -for SSR) you can import the server module directly: +Each render also provides a unique [`act` function](https://reactjs.org/docs/test-utils.html#act) +that cannot be used with other renderers. In order to simplify with `act `function you need to use, +we also export the correct one alongside the detected renderer for you: -```ts -import { renderHook } from '@testing-library/react-hooks/server` +```js +import { renderHook, act } from '@testing-library/react-hooks' ``` -We have the following exports available: +## Being specific + +Auto-detection is great for simplifying setup and getting out of your way, but sometimes you do need +a little but more control. If a test needs requires a specific type of environment, the import can +be appended to force a specific renderer to be use. The supported environments are: + +- `dom` +- `native` +- `server` + +The imports for each type of renderer are as follows: ```ts -import { renderHook, act } from '@testing-library/react-hooks' // will try to auto-detect +import { renderHook, act } from '@testing-library/react-hooks' // will attempt to auto-detect import { renderHook, act } from '@testing-library/react-hooks/dom' // will use react-dom import { renderHook, act } from '@testing-library/react-hooks/native' // will use react-test-renderer -import { renderHook, act } from '@testing-library/react-hooks/server' // will use react-dom +import { renderHook, act } from '@testing-library/react-hooks/server' // will use react-dom/server ``` ## Testing Framework From 05c9af5669b82cc6065c96b31b684f272aee3832 Mon Sep 17 00:00:00 2001 From: Josh <37798644+joshuaellis@users.noreply.github.com> Date: Mon, 11 Jan 2021 22:55:57 +0000 Subject: [PATCH 11/14] docs: update with suggestions Co-authored-by: Michael Peyper --- docs/api-reference.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index e4e4585d..006b8360 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -19,7 +19,7 @@ route: '/reference/api' ```ts function renderHook( - callback: (props?: any): any, + callback: (props?: any) => any, options?: RenderHookOptions ): RenderHookResult ``` @@ -103,9 +103,10 @@ function hydrate(): void > This is only used when using the `server` module. See [SSR](/usage/ssr-hooks) for more information > on server-side rendering your hooks. -A function to hydrate the component. This is required before you can interact with the hook, whether -that is an `act` or `rerender` call. Some effects such as `useEffect` will not be called unless -`hydrate` is called. +A function to hydrate a server rendered component into the DOM. This is required before you can +interact with the hook, whether that is an `act` or `rerender` call. Effects created using +`useEffect` or `useLayoutEffect` are also not run on server rendered hooks until `hydrate` is +called. ### `...asyncUtils` @@ -117,7 +118,7 @@ Utilities to assist with testing asynchronous behaviour. See the ## `act` This is the same [`act` function](https://reactjs.org/docs/test-utils.html#act) function that is -exported from your chosen renderer. Although, they both work the same. +exported from your [chosen renderer](/installation#renderer). --- @@ -157,7 +158,7 @@ module.exports = { Alternatively, you can change your test to import from `@testing-library/react-hooks/pure` instead of the regular imports. This applys to any of our export methods documented in -[Rendering](/rendering#being-specific). +[Rendering](/installation#being-specific). ```diff - import { renderHook, cleanup, act } from '@testing-library/react-hooks' From 1aa5465968c0725cba292b5ee6951d6085dbec9f Mon Sep 17 00:00:00 2001 From: Josh <37798644+joshuaellis@users.noreply.github.com> Date: Tue, 12 Jan 2021 08:56:10 +0000 Subject: [PATCH 12/14] docs: update with suggestions Co-authored-by: Michael Peyper --- docs/usage/ssr-hooks.md | 149 ++++++++++++++++++++++++++-------------- 1 file changed, 96 insertions(+), 53 deletions(-) diff --git a/docs/usage/ssr-hooks.md b/docs/usage/ssr-hooks.md index 7889f1ff..29c5df52 100644 --- a/docs/usage/ssr-hooks.md +++ b/docs/usage/ssr-hooks.md @@ -1,96 +1,139 @@ --- -name: SSR Hooks +--- +name: Server-Side Rendering menu: Usage route: '/usage/ssr-hooks' --- -# Server Side Renderering +# Server-Side Rendering (SSR) ## Setup -To SSR your hook, you must ensure `react-dom >= 16.9.0` is installed in your project and then import -the server module in your test: +To test how your hook will behave when rendered on the server, you can change your import to the use +the `server` module: ```ts import { renderHook } from '@testing-library/react-hooks/server' ``` -## Render Hook +> SSR is only available when using the `react-dom` renderer. Please refer to the +> [installation guide](/installation#peer-dependencies) for instructions and supported versions. -`renderHook` when called returns the same result as documented in the -[API](/reference/api#renderhook-result) but includes an additional argument, `hydrate`: +This import has the same [API as the standard import](/reference/api) except the behaviour changes +to use SSR semantics. -```ts -function hydrate(): void -``` +## Example -The `hydrate` function is a light wrapper around -[`ReactDOM.hydrate`](https://reactjs.org/docs/react-dom.html#hydrate) but no arguments are required -as the library will pass the element & container for you. Remember, certain effects such as -`useEffect` will not run server side and `hydrate` must be called before those effects are -ran.`hydrate`is also necessary before the first `act` or `rerender` call. For more information on -`hydrate` see the [API documentation](/reference/api#hydrate). There is also an -[example below](/usage/ssr-hooks#example) +## Hydration -## Example +The result of rendering you hook is static are not interactive until it is hydrated into the DOM. +This can be done using the `hydrate` function that is returned from `renderHook`. + +Consider the `useCounter` example from the [Basic Hooks section](/usage/basic-hooks): + +```js +import { useState, useCallback } from 'react' + +export default function useCounter() { + const [count, setCount] = useState(0) + const increment = useCallback(() => setCount((x) => x + 1), []) + return { count, increment } +} +``` -### Hydration +If we try to call `increment` immediately after server rendering, nothing happens and the hook is +not interactive: ```js import { renderHook, act } from '@testing-library/react-hooks/server' +import useCounter from './useCounter' -describe('custom hook tests', () => { - function useCounter() { - const [count, setCount] = useState(0) +test('should increment counter', () => { + const { result } = renderHook(() => useCounter(0)) - const increment = useCallback(() => setCount(count + 1), [count]) - const decrement = useCallback(() => setCount(count - 1), [count]) + act(() => { + result.current.increment() + }) - return { count, increment, decrement } - } + expect(result.current.count).toBe(1) // fails as result.current.count is still 0 +}) +``` - test('should decrement counter', () => { - const { result, hydrate } = renderHook(() => useCounter()) +We can make the hook interactive by calling the `hydrate` function that is returned from +`renderHook`: - expect(result.current.count).toBe(0) +```js +import { renderHook, act } from '@testing-library/react-hooks/server' +import useCounter from './useCounter' - // hydrate is called because we want to interact with the hook - hydrate() +test('should increment counter', () => { + const { result, hydrate } = renderHook(() => useCounter(0)) - act(() => result.current.decrement()) + hydrate() - expect(result.current.count).toBe(-1) + act(() => { + result.current.increment() }) + + expect(result.current.count).toBe(1) // now it passes }) ``` +Anything that causes the hook's state to change will not work until `hydrate` is called. This +includes both the [`rerender`](http://localhost:3000/reference/api#rerender) and +[`unmount`](http://localhost:3000/reference/api#unmount) functionality. + ### Effects +Another caveat of SSR is that `useEffect` and `useLayoutEffect` hooks, by design, do not run on when +rendering. + +Consider this `useTimer` hook: + ```js -describe('useEffect tests', () => { - test('should handle useEffect hook', () => { - const sideEffect = { 1: false, 2: false } - - const useEffectHook = ({ id }) => { - useEffect(() => { - sideEffect[id] = true - return () => { - sideEffect[id] = false - } - }, [id]) +import { useState, useCallback, useEffect } from 'react' + +export default function useTimer() { + const [count, setCount] = useState(0) + const reset = useCallback(() => setCount(0), []) + useEffect(() => { + const intervalId = setInterval(() => setCount((c) => c + 1, 1000)) + return () => { + clearInterval(intervalId) } + }) + return { count, reset } +} +``` - const { hydrate, rerender, unmount } = renderHook((id) => useEffectHook({ id }), { - initialProps: { id: 1 } - }) +Upon initial render, the interval will not start: - expect(sideEffect[1]).toBe(false) - expect(sideEffect[2]).toBe(false) +```js +import { renderHook, act } from '@testing-library/react-hooks/server' +import useTimer from './useTimer' - hydrate() +test('should start the timer', async () => { + const { result, waitForValueToChange } = renderHook(() => useTimer(0)) - expect(sideEffect[1]).toBe(true) - expect(sideEffect[2]).toBe(false) - }) + await waitForValueToChange(() => result.current.count) // times out as the value never changes + + expect(result.current.count).toBe(1) // fails as result.current.count is still 0 +}) +``` + +Similarly to updating the hooks state, the effect will start after `hydrate` is called: + +```js +import { renderHook, act } from '@testing-library/react-hooks/server' +import useTimer from './useTimer' + +test('should start the timer', async () => { + const { result, hydrate, waitForValueToChange } = renderHook(() => useTimer(0)) + + hydrate() + + await waitForValueToChange(() => result.current.count) // now resolves when the interval fires + + expect(result.current.count).toBe(1) }) ``` From a461a6c4fbed0f545a5c1dbc16a3bebe8c9ad95b Mon Sep 17 00:00:00 2001 From: Josh Ellis Date: Tue, 12 Jan 2021 09:05:15 +0000 Subject: [PATCH 13/14] docs: change ssr-hooks to ssr --- docs/api-reference.md | 9 +++------ docs/usage/ssr-hooks.md | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/api-reference.md b/docs/api-reference.md index 006b8360..b6d946aa 100644 --- a/docs/api-reference.md +++ b/docs/api-reference.md @@ -18,10 +18,7 @@ route: '/reference/api' ## `renderHook` ```ts -function renderHook( - callback: (props?: any) => any, - options?: RenderHookOptions -): RenderHookResult +function renderHook(callback: (props?: any) => any, options?: RenderHookOptions): RenderHookResult ``` Renders a test component that will call the provided `callback`, including any hooks it calls, every @@ -100,8 +97,8 @@ A function to unmount the test component. This is commonly used to trigger clean function hydrate(): void ``` -> This is only used when using the `server` module. See [SSR](/usage/ssr-hooks) for more information -> on server-side rendering your hooks. +> This is only used when using the `server` module. See [SSR](/usage/ssr) for more information on +> server-side rendering your hooks. A function to hydrate a server rendered component into the DOM. This is required before you can interact with the hook, whether that is an `act` or `rerender` call. Effects created using diff --git a/docs/usage/ssr-hooks.md b/docs/usage/ssr-hooks.md index 29c5df52..58a493c3 100644 --- a/docs/usage/ssr-hooks.md +++ b/docs/usage/ssr-hooks.md @@ -1,8 +1,7 @@ --- ---- name: Server-Side Rendering menu: Usage -route: '/usage/ssr-hooks' +route: '/usage/ssr' --- # Server-Side Rendering (SSR) From aa8b1748d009670e7ff4eb6377b3f019fde0adb1 Mon Sep 17 00:00:00 2001 From: Michael Peyper Date: Tue, 12 Jan 2021 20:18:02 +1100 Subject: [PATCH 14/14] docs: add explicit menu entry for new page --- doczrc.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doczrc.js b/doczrc.js index 9c6bd79e..3027121d 100644 --- a/doczrc.js +++ b/doczrc.js @@ -19,7 +19,7 @@ export default { menu: [ { name: 'Introduction' }, { name: 'Installation' }, - { name: 'Usage', menu: ['Basic Hooks', 'Advanced Hooks'] }, + { name: 'Usage', menu: ['Basic Hooks', 'Advanced Hooks', 'Server-Side Rendering'] }, { name: 'API Reference' } ] }