Skip to content

Pr/cleanup renderhooks #106

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@
"bug",
"code"
]
},
{
"login": "apostolidhs",
"name": "John Apostolidis",
"avatar_url": "https://avatars3.githubusercontent.com/u/2164902?v=4",
"profile": "http://apostolidis.me",
"contributions": [
"code",
"doc"
]
}
],
"commitConvention": "none"
Expand Down
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
[![downloads](https://img.shields.io/npm/dm/@testing-library/react-hooks.svg?style=flat-square)](http://www.npmtrends.com/@testing-library/react-hooks)
[![MIT License](https://img.shields.io/npm/l/@testing-library/react-hooks.svg?style=flat-square)](https://github.com/testing-library/react-hooks-testing-library/blob/master/LICENSE.md)

[![All Contributors](https://img.shields.io/badge/all_contributors-10-orange.svg?style=flat-square)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-11-orange.svg?style=flat-square)](#contributors)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
[![Code of Conduct](https://img.shields.io/badge/code%20of-conduct-ff69b4.svg?style=flat-square)](https://github.com/testing-library/react-hooks-testing-library/blob/master/CODE_OF_CONDUCT.md)
[![Netlify Status](https://api.netlify.com/api/v1/badges/9a8f27a5-df38-4910-a248-4908b1ba29a7/deploy-status)](https://app.netlify.com/sites/react-hooks-testing-library/deploys)
Expand Down Expand Up @@ -126,6 +126,17 @@ npm install --save-dev react-test-renderer@^x.y.z
Both of these dependecies must be installed as at least version `16.8.0` to be compatible with
`react-hooks-testing-library`.

### `cleanup()`

Unmounts any of the Hooks that were mounted with `renderHook`.

Optionally, it is possible to import `cleanup` in a global test file. Using that way, it isn't
necessary to run `afterEach(cleanup)` on every test script.

```js
import 'react-hooks-testing-library/cleanup-after-each'
```

## Documentation

There are some [work-in-progress docs here](https://react-hooks-testing-library.com/). Please leave
Expand All @@ -143,7 +154,23 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore -->
<table><tr><td align="center"><a href="https://github.com/mpeyper"><img src="https://avatars0.githubusercontent.com/u/23029903?v=4" width="100px;" alt="Michael Peyper"/><br /><sub><b>Michael Peyper</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=mpeyper" title="Code">💻</a> <a href="#design-mpeyper" title="Design">🎨</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=mpeyper" title="Documentation">📖</a> <a href="#ideas-mpeyper" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-mpeyper" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#platform-mpeyper" title="Packaging/porting to new platform">📦</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=mpeyper" title="Tests">⚠️</a> <a href="#tool-mpeyper" title="Tools">🔧</a></td><td align="center"><a href="https://github.com/otofu-square"><img src="https://avatars0.githubusercontent.com/u/10118235?v=4" width="100px;" alt="otofu-square"/><br /><sub><b>otofu-square</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=otofu-square" title="Code">💻</a></td><td align="center"><a href="https://github.com/ab18556"><img src="https://avatars2.githubusercontent.com/u/988696?v=4" width="100px;" alt="Patrick P. Henley"/><br /><sub><b>Patrick P. Henley</b></sub></a><br /><a href="#ideas-ab18556" title="Ideas, Planning, & Feedback">🤔</a> <a href="#review-ab18556" title="Reviewed Pull Requests">👀</a></td><td align="center"><a href="https://twitter.com/matiosfm"><img src="https://avatars3.githubusercontent.com/u/7120471?v=4" width="100px;" alt="Matheus Marques"/><br /><sub><b>Matheus Marques</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=marquesm91" title="Code">💻</a></td><td align="center"><a href="https://ca.linkedin.com/in/dhruvmpatel"><img src="https://avatars1.githubusercontent.com/u/19353311?v=4" width="100px;" alt="Dhruv Patel"/><br /><sub><b>Dhruv Patel</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/issues?q=author%3Adhruv-m-patel" title="Bug reports">🐛</a> <a href="#review-dhruv-m-patel" title="Reviewed Pull Requests">👀</a></td><td align="center"><a href="https://ntucker.true.io"><img src="https://avatars0.githubusercontent.com/u/866147?v=4" width="100px;" alt="Nathaniel Tucker"/><br /><sub><b>Nathaniel Tucker</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/issues?q=author%3Antucker" title="Bug reports">🐛</a> <a href="#review-ntucker" title="Reviewed Pull Requests">👀</a></td><td align="center"><a href="https://github.com/sgrishchenko"><img src="https://avatars3.githubusercontent.com/u/15995890?v=4" width="100px;" alt="Sergei Grishchenko"/><br /><sub><b>Sergei Grishchenko</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=sgrishchenko" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=sgrishchenko" title="Documentation">📖</a> <a href="#ideas-sgrishchenko" title="Ideas, Planning, & Feedback">🤔</a></td></tr><tr><td align="center"><a href="https://github.com/josepot"><img src="https://avatars1.githubusercontent.com/u/8620144?v=4" width="100px;" alt="Josep M Sobrepere"/><br /><sub><b>Josep M Sobrepere</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=josepot" title="Documentation">📖</a></td><td align="center"><a href="https://github.com/mtinner"><img src="https://avatars0.githubusercontent.com/u/5487448?v=4" width="100px;" alt="Marcel Tinner"/><br /><sub><b>Marcel Tinner</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=mtinner" title="Documentation">📖</a></td><td align="center"><a href="https://github.com/FredyC"><img src="https://avatars0.githubusercontent.com/u/1096340?v=4" width="100px;" alt="Daniel K."/><br /><sub><b>Daniel K.</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/issues?q=author%3AFredyC" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=FredyC" title="Code">💻</a></td></tr></table>
<table>
<tr>
<td align="center"><a href="https://github.com/mpeyper"><img src="https://avatars0.githubusercontent.com/u/23029903?v=4" width="100px;" alt="Michael Peyper"/><br /><sub><b>Michael Peyper</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=mpeyper" title="Code">💻</a> <a href="#design-mpeyper" title="Design">🎨</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=mpeyper" title="Documentation">📖</a> <a href="#ideas-mpeyper" title="Ideas, Planning, & Feedback">🤔</a> <a href="#infra-mpeyper" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#platform-mpeyper" title="Packaging/porting to new platform">📦</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=mpeyper" title="Tests">⚠️</a> <a href="#tool-mpeyper" title="Tools">🔧</a></td>
<td align="center"><a href="https://github.com/otofu-square"><img src="https://avatars0.githubusercontent.com/u/10118235?v=4" width="100px;" alt="otofu-square"/><br /><sub><b>otofu-square</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=otofu-square" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ab18556"><img src="https://avatars2.githubusercontent.com/u/988696?v=4" width="100px;" alt="Patrick P. Henley"/><br /><sub><b>Patrick P. Henley</b></sub></a><br /><a href="#ideas-ab18556" title="Ideas, Planning, & Feedback">🤔</a> <a href="#review-ab18556" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://twitter.com/matiosfm"><img src="https://avatars3.githubusercontent.com/u/7120471?v=4" width="100px;" alt="Matheus Marques"/><br /><sub><b>Matheus Marques</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=marquesm91" title="Code">💻</a></td>
<td align="center"><a href="https://ca.linkedin.com/in/dhruvmpatel"><img src="https://avatars1.githubusercontent.com/u/19353311?v=4" width="100px;" alt="Dhruv Patel"/><br /><sub><b>Dhruv Patel</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/issues?q=author%3Adhruv-m-patel" title="Bug reports">🐛</a> <a href="#review-dhruv-m-patel" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://ntucker.true.io"><img src="https://avatars0.githubusercontent.com/u/866147?v=4" width="100px;" alt="Nathaniel Tucker"/><br /><sub><b>Nathaniel Tucker</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/issues?q=author%3Antucker" title="Bug reports">🐛</a> <a href="#review-ntucker" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/sgrishchenko"><img src="https://avatars3.githubusercontent.com/u/15995890?v=4" width="100px;" alt="Sergei Grishchenko"/><br /><sub><b>Sergei Grishchenko</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=sgrishchenko" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=sgrishchenko" title="Documentation">📖</a> <a href="#ideas-sgrishchenko" title="Ideas, Planning, & Feedback">🤔</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/josepot"><img src="https://avatars1.githubusercontent.com/u/8620144?v=4" width="100px;" alt="Josep M Sobrepere"/><br /><sub><b>Josep M Sobrepere</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=josepot" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/mtinner"><img src="https://avatars0.githubusercontent.com/u/5487448?v=4" width="100px;" alt="Marcel Tinner"/><br /><sub><b>Marcel Tinner</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=mtinner" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/FredyC"><img src="https://avatars0.githubusercontent.com/u/1096340?v=4" width="100px;" alt="Daniel K."/><br /><sub><b>Daniel K.</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/issues?q=author%3AFredyC" title="Bug reports">🐛</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=FredyC" title="Code">💻</a></td>
<td align="center"><a href="http://apostolidis.me"><img src="https://avatars3.githubusercontent.com/u/2164902?v=4" width="100px;" alt="John Apostolidis"/><br /><sub><b>John Apostolidis</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=apostolidhs" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=apostolidhs" title="Documentation">📖</a></td>
</tr>
</table>

<!-- ALL-CONTRIBUTORS-LIST:END -->

Expand Down
1 change: 1 addition & 0 deletions cleanup-after-each.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
afterEach(require('./src').cleanup)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be requireing ./lib so that it picks up the compiled version after publishing.

23 changes: 17 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import React, { Suspense } from 'react'
import { act, create } from 'react-test-renderer'

const unmounts = []

function TestHook({ callback, hookProps, onError, children }) {
try {
children(callback(hookProps))
Expand Down Expand Up @@ -51,6 +53,11 @@ function resultContainer() {
}
}

function cleanup() {
unmounts.forEach((unmount) => unmount())
unmounts.length = 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there significant difference between this and unmounts = []? That feels a bit clearer what it's doing to me, but I'm not sure if there are some other hidden benefits to this approach?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking to use either mutable or immutable approach. Personally, i prefer the immutable way as i suggested in the issue.

let unmounts = [];
unmounts = [...unmounts, unmount];
unmounts = [];

but i saw the way that you are using the resolvers

const resolvers = []; 
resolvers.push(resolver);

and i tried to follow the same pattern for consistency (mutable). I don't have a strong opinion on this, it's up to you.

}

function renderHook(callback, { initialProps, wrapper } = {}) {
const { result, setValue, setError, addResolver } = resultContainer()
const hookProps = { current: initialProps }
Expand All @@ -73,6 +80,14 @@ function renderHook(callback, { initialProps, wrapper } = {}) {
})
const { unmount, update } = testRenderer

function unmountHook() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if someone calls this then then cleanup? does the second unmount fail? should unmountHook also remove the callback from unmounts (making this line no longer necessary at all)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see there is a test around this case. I personally feel that having unmountHook remove the callback from the unmounts array is bit clearer to what is happening rather than relying on the behaviour of unmount, but I don't care enough to block this for it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with you, i will fix it.

act(() => {
unmount()
})
}

unmounts.push(unmountHook)

return {
result,
waitForNextUpdate: () => new Promise((resolve) => addResolver(resolve)),
Expand All @@ -82,12 +97,8 @@ function renderHook(callback, { initialProps, wrapper } = {}) {
update(toRender())
})
},
unmount: () => {
act(() => {
unmount()
})
}
unmount: unmountHook
}
}

export { renderHook, act }
export { renderHook, cleanup, act }
50 changes: 50 additions & 0 deletions test/cleanup.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useEffect } from 'react'
import { renderHook, cleanup } from 'src'

describe('cleanup tests', () => {
let sideEffect = {}

function useEffectsCounter({ initialProps }) {
return renderHook(
({ id }) => {
useEffect(() => {
sideEffect[id] = 0
return () => {
sideEffect[id] = sideEffect[id] + 1
}
}, [id])
},
{ initialProps }
)
}

afterEach(() => (sideEffect = {}))

test('should unmount the tests', () => {
useEffectsCounter({ initialProps: { id: 1 } })
useEffectsCounter({ initialProps: { id: 10 } })
useEffectsCounter({ initialProps: { id: 100 } })

cleanup()

expect(sideEffect).toEqual({ 1: 1, 10: 1, 100: 1 })
})

test('should not cleanup a hook that have already unmounted', () => {
const { unmount } = useEffectsCounter({ initialProps: { id: 1 } })

unmount()
cleanup()

expect(sideEffect).toEqual({ 1: 1 })
})

test('should not unmount a hook that have already cleaned up', () => {
const { unmount } = useEffectsCounter({ initialProps: { id: 1 } })

cleanup()
unmount()

expect(sideEffect).toEqual({ 1: 1 })
})
})
2 changes: 2 additions & 0 deletions typings/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ export function renderHook<P, R>(
callback: (props: P) => R,
options?: RenderHookOptions<P>
): RenderHookResult<P, R>

export function cleanup(): void