Skip to content

Commit 183c3ce

Browse files
committed
Added cleanup and autocleanup functionality
1 parent eb400b1 commit 183c3ce

File tree

5 files changed

+148
-6
lines changed

5 files changed

+148
-6
lines changed

src/index.js

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import React, { Suspense } from 'react'
22
import { act, create } from 'react-test-renderer'
33

4+
let cleanupCallbacks = []
5+
46
function TestHook({ callback, hookProps, onError, children }) {
57
try {
68
children(callback(hookProps))
@@ -73,6 +75,15 @@ function renderHook(callback, { initialProps, wrapper } = {}) {
7375
})
7476
const { unmount, update } = testRenderer
7577

78+
function unmountHook() {
79+
act(() => {
80+
cleanupCallbacks = cleanupCallbacks.filter((cb) => cb !== unmountHook)
81+
unmount()
82+
})
83+
}
84+
85+
cleanupCallbacks.push(unmountHook)
86+
7687
let waitingForNextUpdate = null
7788
const resolveOnNextUpdate = (resolve) => {
7889
addResolver((...args) => {
@@ -93,12 +104,22 @@ function renderHook(callback, { initialProps, wrapper } = {}) {
93104
update(toRender())
94105
})
95106
},
96-
unmount: () => {
97-
act(() => {
98-
unmount()
99-
})
100-
}
107+
unmount: unmountHook
101108
}
102109
}
103110

104-
export { renderHook, act }
111+
async function cleanup() {
112+
await act(async () => {
113+
await act(async () => {})
114+
cleanupCallbacks.forEach((cb) => cb())
115+
cleanupCallbacks = []
116+
})
117+
}
118+
119+
if (typeof afterEach === 'function' && !process.env.RHTL_SKIP_AUTO_CLEANUP) {
120+
afterEach(async () => {
121+
await cleanup()
122+
})
123+
}
124+
125+
export { renderHook, cleanup, act }

test/autoCleanup.disabled.test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useEffect } from 'react'
2+
3+
// This verifies that if RHTL_SKIP_AUTO_CLEANUP is set
4+
// then we DON'T auto-wire up the afterEach for folks
5+
describe('skip auto cleanup (disabled) tests', () => {
6+
let cleanupCalled = false
7+
let renderHook
8+
9+
beforeAll(() => {
10+
process.env.RHTL_SKIP_AUTO_CLEANUP = 'true'
11+
renderHook = require('src').renderHook
12+
})
13+
14+
test('first', () => {
15+
const hookWithCleanup = () => {
16+
useEffect(() => {
17+
return () => {
18+
cleanupCalled = true
19+
}
20+
})
21+
}
22+
renderHook(() => hookWithCleanup())
23+
})
24+
25+
test('second', () => {
26+
expect(cleanupCalled).toBe(false)
27+
})
28+
})

test/autoCleanup.noAfterEach.test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useEffect } from 'react'
2+
3+
// This verifies that if RHTL_SKIP_AUTO_CLEANUP is set
4+
// then we DON'T auto-wire up the afterEach for folks
5+
describe('skip auto cleanup (no afterEach) tests', () => {
6+
let cleanupCalled = false
7+
let renderHook
8+
9+
beforeAll(() => {
10+
afterEach = false
11+
renderHook = require('src').renderHook
12+
})
13+
14+
test('first', () => {
15+
const hookWithCleanup = () => {
16+
useEffect(() => {
17+
return () => {
18+
cleanupCalled = true
19+
}
20+
})
21+
}
22+
renderHook(() => hookWithCleanup())
23+
})
24+
25+
test('second', () => {
26+
expect(cleanupCalled).toBe(false)
27+
})
28+
})

test/autoCleanup.test.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useEffect } from 'react'
2+
import { renderHook } from 'src'
3+
4+
// This verifies that by importing RHTL in an
5+
// environment which supports afterEach (like jest)
6+
// we'll get automatic cleanup between tests.
7+
describe('auto cleanup tests', () => {
8+
let cleanupCalled = false
9+
10+
test('first', () => {
11+
const hookWithCleanup = () => {
12+
useEffect(() => {
13+
return () => {
14+
cleanupCalled = true
15+
}
16+
})
17+
}
18+
renderHook(() => hookWithCleanup())
19+
})
20+
21+
test('second', () => {
22+
expect(cleanupCalled).toBe(true)
23+
})
24+
})

test/cleanup.test.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { useEffect } from 'react'
2+
import { renderHook, cleanup } from 'src'
3+
4+
describe('cleanup tests', () => {
5+
test('should flush effects on cleanup', async () => {
6+
let cleanupCalled = false
7+
8+
const hookWithCleanup = () => {
9+
useEffect(() => {
10+
return () => {
11+
cleanupCalled = true
12+
}
13+
})
14+
}
15+
16+
renderHook(() => hookWithCleanup())
17+
18+
await cleanup()
19+
20+
expect(cleanupCalled).toBe(true)
21+
})
22+
23+
test('should cleanup all rendered hooks', async () => {
24+
let cleanupCalled = []
25+
const hookWithCleanup = (id) => {
26+
useEffect(() => {
27+
return () => {
28+
cleanupCalled[id] = true
29+
}
30+
})
31+
}
32+
33+
renderHook(() => hookWithCleanup(1))
34+
renderHook(() => hookWithCleanup(2))
35+
36+
await cleanup()
37+
38+
expect(cleanupCalled[1]).toBe(true)
39+
expect(cleanupCalled[2]).toBe(true)
40+
})
41+
})

0 commit comments

Comments
 (0)