Skip to content

Commit 563f333

Browse files
committed
This PR:
- exports a new top level function cleanupAsync - that awaits an `act(async () => {})` before unmounting containers - and uses it in cleanup-after-each Some possible Q&A: - why not do the same in sync cleanup()?: if peeps are using react-testing-library already, it's suuuper unlikely they'll have hanging sync effects/updates. Decided not to add code without a good reason. - why have a new export? why not make `cleanup()` return a promise?: that would be a breaking change, especially for people already using `cleanup()` in their tests. You could consider it for a next major. - where are the docs for `cleanupAsync`?: I recommend not exposing this as a publicly supported api. let its usage be via cleanup-after-each. gives a little breathing room without exposing the api surface. (bonus: fixes a lint violation in act-compat.js)
1 parent 4c8ca23 commit 563f333

File tree

4 files changed

+30
-4
lines changed

4 files changed

+30
-4
lines changed

cleanup-after-each.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
afterEach(require('./dist').cleanup)
1+
afterEach(() => require('./dist').cleanupAsync())

src/__tests__/render.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react'
22
import ReactDOM from 'react-dom'
3-
import {render, cleanup} from '../'
3+
import {render, cleanup, cleanupAsync} from '../'
44

55
test('renders div into document', () => {
66
const ref = React.createRef()
@@ -90,6 +90,27 @@ it('supports fragments', () => {
9090
expect(document.body.innerHTML).toBe('')
9191
})
9292

93+
it('cleanupAsync does not leave any hanging microtasks', async () => {
94+
const log = []
95+
let ctr = 0
96+
function App() {
97+
async function somethingAsync() {
98+
await null
99+
log.push(ctr++)
100+
}
101+
React.useEffect(() => {
102+
somethingAsync()
103+
}, [])
104+
return 123
105+
}
106+
render(<App />)
107+
expect(document.body.textContent).toBe('123')
108+
expect(log).toEqual([])
109+
await cleanupAsync()
110+
expect(log).toEqual([0])
111+
expect(document.body.innerHTML).toBe('')
112+
})
113+
93114
test('renders options.wrapper around node', () => {
94115
const WrapperComponent = ({children}) => (
95116
<div data-testid="wrapper">{children}</div>

src/act-compat.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react'
22
import ReactDOM from 'react-dom'
3-
import {reactDomSixteenPointNineIsReleased} from './react-dom-16.9.0-is-released'
43
import * as testUtils from 'react-dom/test-utils'
4+
import {reactDomSixteenPointNineIsReleased} from './react-dom-16.9.0-is-released'
55

66
const reactAct = testUtils.act
77
const actSupported = reactAct !== undefined

src/index.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,11 @@ function cleanup() {
8888
mountedContainers.forEach(cleanupAtContainer)
8989
}
9090

91+
async function cleanupAsync() {
92+
await asyncAct(async () => {})
93+
cleanup()
94+
}
95+
9196
// maybe one day we'll expose this (perhaps even as a utility returned by render).
9297
// but let's wait until someone asks for it.
9398
function cleanupAtContainer(container) {
@@ -144,7 +149,7 @@ fireEvent.select = (node, init) => {
144149

145150
// just re-export everything from dom-testing-library
146151
export * from '@testing-library/dom'
147-
export {render, cleanup, fireEvent, act}
152+
export {render, cleanup, cleanupAsync, fireEvent, act}
148153

149154
// NOTE: we're not going to export asyncAct because that's our own compatibility
150155
// thing for people using [email protected]. Anyone else doesn't need it and

0 commit comments

Comments
 (0)