Skip to content

Commit e1c2c0c

Browse files
author
Kent C. Dodds
committed
feat(act): Support async act 🎉
Closes #281
1 parent 7e6031f commit e1c2c0c

File tree

5 files changed

+98
-11
lines changed

5 files changed

+98
-11
lines changed

.github/PULL_REQUEST_TEMPLATE.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,11 @@ merge of your pull request!
3434

3535
<!-- to check an item, place an "x" in the box like so: "- [x] Documentation" -->
3636

37-
- [ ] Documentation added to the [docs site](https://github.com/alexkrolick/testing-library-docs)
37+
- [ ] Documentation added to the
38+
[docs site](https://github.com/alexkrolick/testing-library-docs)
3839
- [ ] Tests
3940
- [ ] Typescript definitions updated
4041
- [ ] Ready to be merged
4142
<!-- In your opinion, is this ready to be merged as soon as it's reviewed? -->
42-
- [ ] Added myself to contributors table
43-
<!-- this is optional, see the contributing guidelines for instructions -->
4443

4544
<!-- feel free to add additional comments -->

package.json

+3-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
"node": ">=8"
1010
},
1111
"scripts": {
12-
"add-contributor": "kcd-scripts contributors add",
1312
"build": "kcd-scripts build && kcd-scripts build --bundle --no-clean",
1413
"lint": "kcd-scripts lint",
1514
"test": "kcd-scripts test --config=other/jest.config.js",
@@ -43,7 +42,7 @@
4342
"license": "MIT",
4443
"dependencies": {
4544
"@babel/runtime": "^7.4.2",
46-
"dom-testing-library": "^3.18.2"
45+
"dom-testing-library": "^3.19.0"
4746
},
4847
"devDependencies": {
4948
"@reach/router": "^1.2.1",
@@ -56,8 +55,8 @@
5655
"jest-dom": "3.1.3",
5756
"jest-in-case": "^1.0.2",
5857
"kcd-scripts": "1.1.2",
59-
"react": "^16.8.5",
60-
"react-dom": "^16.8.5",
58+
"react": "16.9.0-alpha.0",
59+
"react-dom": "16.9.0-alpha.0",
6160
"react-intl": "^2.8.0",
6261
"react-redux": "6.0.1",
6362
"react-router": "^5.0.0",

src/__tests__/old-act.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import {asyncAct} from '../act-compat'
2+
3+
jest.mock('react-dom/test-utils', () => ({
4+
act: cb => {
5+
const promise = cb()
6+
return {
7+
then() {
8+
console.error('blah, do not do this')
9+
return promise
10+
},
11+
}
12+
},
13+
}))
14+
15+
test('async act works even when the act is an old one', async () => {
16+
jest.spyOn(console, 'error').mockImplementation(() => {})
17+
const callback = jest.fn()
18+
await asyncAct(async () => {
19+
await Promise.resolve()
20+
await callback()
21+
})
22+
expect(console.error.mock.calls).toMatchInlineSnapshot(`
23+
Array [
24+
Array [
25+
"It looks like you're using a version of react-dom that supports the \\"act\\" function, but not an awaitable version of \\"act\\" which you will need. Please upgrade to at least [email protected] to remove this warning.",
26+
],
27+
]
28+
`)
29+
expect(callback).toHaveBeenCalledTimes(1)
30+
31+
// and it doesn't warn you twice
32+
callback.mockClear()
33+
console.error.mockClear()
34+
35+
await asyncAct(async () => {
36+
await Promise.resolve()
37+
await callback()
38+
})
39+
expect(console.error).toHaveBeenCalledTimes(0)
40+
expect(callback).toHaveBeenCalledTimes(1)
41+
42+
console.error.mockRestore()
43+
})
44+
45+
/* eslint no-console:0 */

src/act-compat.js

+38-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,23 @@ import React from 'react'
22
import ReactDOM from 'react-dom'
33

44
let reactAct
5+
let actSupported = false
6+
let asyncActSupported = false
57
try {
68
reactAct = require('react-dom/test-utils').act
9+
actSupported = reactAct !== undefined
10+
11+
const originalError = console.error
12+
let errorCalled = false
13+
console.error = () => {
14+
errorCalled = true
15+
}
16+
console.error.calls = []
17+
reactAct(() => ({then: () => {}})).then(() => {})
18+
if (!errorCalled) {
19+
asyncActSupported = true
20+
}
21+
console.error = originalError
722
} catch (error) {
823
// ignore, this is to support old versions of react
924
}
@@ -19,8 +34,28 @@ function actPolyfill(cb) {
1934

2035
const act = reactAct || actPolyfill
2136

22-
function rtlAct(...args) {
23-
return act(...args)
37+
let youHaveBeenWarned = false
38+
// this will not avoid warnings that react-dom 16.8.0 logs for triggering
39+
// state updates asynchronously, but at least we can tell people they need
40+
// to upgrade to avoid the warnings.
41+
async function asyncActPolyfill(cb) {
42+
if (!youHaveBeenWarned && actSupported) {
43+
// if act is supported and async act isn't and they're trying to use async
44+
// act, then they need to upgrade from 16.8 to 16.9.
45+
// This is a seemless upgrade, so we'll add a warning
46+
console.error(
47+
`It looks like you're using a version of react-dom that supports the "act" function, but not an awaitable version of "act" which you will need. Please upgrade to at least [email protected] to remove this warning.`,
48+
)
49+
youHaveBeenWarned = true
50+
}
51+
await cb()
52+
// make all effects resolve after
53+
act(() => {})
2454
}
2555

26-
export default rtlAct
56+
const asyncAct = asyncActSupported ? reactAct : asyncActPolyfill
57+
58+
export default act
59+
export {asyncAct}
60+
61+
/* eslint no-console:0 */

src/index.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,13 @@ import {
44
getQueriesForElement,
55
prettyDOM,
66
fireEvent as dtlFireEvent,
7+
configure as configureDTL,
78
} from 'dom-testing-library'
8-
import act from './act-compat'
9+
import act, {asyncAct} from './act-compat'
10+
11+
configureDTL({
12+
asyncWrapper: asyncAct,
13+
})
914

1015
const mountedContainers = new Set()
1116

@@ -133,4 +138,8 @@ fireEvent.select = (node, init) => {
133138
export * from 'dom-testing-library'
134139
export {render, cleanup, fireEvent, act}
135140

141+
// NOTE: we're not going to export asyncAct because that's our own compatibility
142+
// thing for people using [email protected]. Anyone else doesn't need it and
143+
// people should just upgrade anyway.
144+
136145
/* eslint func-name-matching:0 */

0 commit comments

Comments
 (0)