diff --git a/.all-contributorsrc b/.all-contributorsrc
index be8f304a..dc53c0ec 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -183,6 +183,17 @@
"contributions": [
"test"
]
+ },
+ {
+ "login": "huchenme",
+ "name": "Hu Chen",
+ "avatar_url": "https://avatars3.githubusercontent.com/u/2078389?v=4",
+ "profile": "https://huchen.dev/",
+ "contributions": [
+ "code",
+ "doc",
+ "example"
+ ]
}
],
"commitConvention": "none"
diff --git a/README.md b/README.md
index e40d2ad9..edef6733 100644
--- a/README.md
+++ b/README.md
@@ -164,11 +164,13 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Roman Gusev 📖 |
Adam Seckel 💻 |
keiya sasaki ⚠️ |
+ Hu Chen 💻 📖 💡 |
-
+
+
This project follows the [all-contributors](https://allcontributors.org/) specification.
diff --git a/docs/api-reference.md b/docs/api-reference.md
index 53c7623a..16413d8f 100644
--- a/docs/api-reference.md
+++ b/docs/api-reference.md
@@ -10,6 +10,7 @@ route: '/reference/api'
- [`renderHook`](/reference/api#renderhook)
- [`act`](/reference/api#act)
- [`cleanup`](/reference/api#cleanup)
+- [`addCleanup`](/reference/api#addcleanup)
---
@@ -147,6 +148,31 @@ variable to `true` before importing `@testing-library/react-hooks` will also dis
---
+## `addCleanup`
+
+```js
+function addCleanup(
+ callback: function(props?: any): any
+): void
+```
+
+Callback to be called after `cleanup`.
+
+In some cases you might want to run some callback after internal `cleanup` happen, especially after
+`unmount` happens in `cleanup`. If the sequence matters to you, you could use `addCleanup`.
+
+```js
+import { addCleanup } from '@testing-library/react-hooks'
+
+jest.useFakeTimers()
+
+addCleanup(() => {
+ jest.runOnlyPendingTimers()
+})
+```
+
+---
+
## Async Utilities
### `waitForNextUpdate`
diff --git a/src/cleanup.js b/src/cleanup.js
index c240b5e1..60fd5be8 100644
--- a/src/cleanup.js
+++ b/src/cleanup.js
@@ -1,19 +1,25 @@
import flushMicroTasks from './flush-microtasks'
-let cleanupCallbacks = []
+let internalCleanupCbs = []
+let cleanupCbs = []
async function cleanup() {
await flushMicroTasks()
- cleanupCallbacks.forEach((cb) => cb())
- cleanupCallbacks = []
+ internalCleanupCbs.forEach((cb) => cb())
+ internalCleanupCbs = []
+ cleanupCbs.forEach((cb) => cb())
+}
+
+function addInternalCleanup(callback) {
+ internalCleanupCbs.push(callback)
}
function addCleanup(callback) {
- cleanupCallbacks.push(callback)
+ cleanupCbs.push(callback)
}
-function removeCleanup(callback) {
- cleanupCallbacks = cleanupCallbacks.filter((cb) => cb !== callback)
+function removeInternalCleanup(callback) {
+ internalCleanupCbs = internalCleanupCbs.filter((cb) => cb !== callback)
}
-export { cleanup, addCleanup, removeCleanup }
+export { cleanup, addCleanup, addInternalCleanup, removeInternalCleanup }
diff --git a/src/pure.js b/src/pure.js
index 3b4a475d..e2427f64 100644
--- a/src/pure.js
+++ b/src/pure.js
@@ -1,7 +1,7 @@
import React, { Suspense } from 'react'
import { act, create } from 'react-test-renderer'
import asyncUtils from './asyncUtils'
-import { cleanup, addCleanup, removeCleanup } from './cleanup'
+import { cleanup, addCleanup, addInternalCleanup, removeInternalCleanup } from './cleanup'
function TestHook({ callback, hookProps, onError, children }) {
try {
@@ -84,12 +84,12 @@ function renderHook(callback, { initialProps, wrapper } = {}) {
function unmountHook() {
act(() => {
- removeCleanup(unmountHook)
+ removeInternalCleanup(unmountHook)
unmount()
})
}
- addCleanup(unmountHook)
+ addInternalCleanup(unmountHook)
return {
result,
@@ -99,4 +99,4 @@ function renderHook(callback, { initialProps, wrapper } = {}) {
}
}
-export { renderHook, cleanup, act }
+export { renderHook, cleanup, act, addCleanup }
diff --git a/test/addCleanup.test.js b/test/addCleanup.test.js
new file mode 100644
index 00000000..8e74e73a
--- /dev/null
+++ b/test/addCleanup.test.js
@@ -0,0 +1,27 @@
+import { useEffect } from 'react'
+import { renderHook, addCleanup } from 'src'
+
+let callSequence = []
+addCleanup(() => {
+ callSequence.push('cleanup')
+})
+addCleanup(() => {
+ callSequence.push('another cleanup')
+})
+
+describe('addCleanup tests', () => {
+ test('first', () => {
+ const hookWithCleanup = () => {
+ useEffect(() => {
+ return () => {
+ callSequence.push('unmount')
+ }
+ })
+ }
+ renderHook(() => hookWithCleanup())
+ })
+
+ test('second', () => {
+ expect(callSequence).toEqual(['unmount', 'cleanup', 'another cleanup'])
+ })
+})