Skip to content

feat(act): Support async act 🎉 #343

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

Merged
merged 1 commit into from
Apr 5, 2019
Merged
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
5 changes: 2 additions & 3 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ merge of your pull request!

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

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

<!-- feel free to add additional comments -->
7 changes: 3 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"node": ">=8"
},
"scripts": {
"add-contributor": "kcd-scripts contributors add",
"build": "kcd-scripts build && kcd-scripts build --bundle --no-clean",
"lint": "kcd-scripts lint",
"test": "kcd-scripts test --config=other/jest.config.js",
Expand Down Expand Up @@ -43,7 +42,7 @@
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.4.2",
"dom-testing-library": "^3.18.2"
"dom-testing-library": "^3.19.0"
},
"devDependencies": {
"@reach/router": "^1.2.1",
Expand All @@ -56,8 +55,8 @@
"jest-dom": "3.1.3",
"jest-in-case": "^1.0.2",
"kcd-scripts": "1.1.2",
"react": "^16.8.5",
"react-dom": "^16.8.5",
"react": "16.9.0-alpha.0",
"react-dom": "16.9.0-alpha.0",
"react-intl": "^2.8.0",
"react-redux": "6.0.1",
"react-router": "^5.0.0",
Expand Down
45 changes: 45 additions & 0 deletions src/__tests__/old-act.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {asyncAct} from '../act-compat'

jest.mock('react-dom/test-utils', () => ({
act: cb => {
const promise = cb()
return {
then() {
console.error('blah, do not do this')
return promise
},
}
},
}))

test('async act works even when the act is an old one', async () => {
jest.spyOn(console, 'error').mockImplementation(() => {})
const callback = jest.fn()
await asyncAct(async () => {
await Promise.resolve()
await callback()
})
expect(console.error.mock.calls).toMatchInlineSnapshot(`
Array [
Array [
"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.",
],
]
`)
expect(callback).toHaveBeenCalledTimes(1)

// and it doesn't warn you twice
Copy link
Member Author

Choose a reason for hiding this comment

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

callback.mockClear()
console.error.mockClear()

await asyncAct(async () => {
await Promise.resolve()
await callback()
})
expect(console.error).toHaveBeenCalledTimes(0)
expect(callback).toHaveBeenCalledTimes(1)

console.error.mockRestore()
})

/* eslint no-console:0 */
41 changes: 38 additions & 3 deletions src/act-compat.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,23 @@ import React from 'react'
import ReactDOM from 'react-dom'

let reactAct
let actSupported = false
let asyncActSupported = false
try {
reactAct = require('react-dom/test-utils').act
actSupported = reactAct !== undefined

const originalError = console.error
let errorCalled = false
console.error = () => {
errorCalled = true
}
console.error.calls = []
reactAct(() => ({then: () => {}})).then(/* istanbul ignore next */ () => {})
if (!errorCalled) {
asyncActSupported = true
}
console.error = originalError
} catch (error) {
// ignore, this is to support old versions of react
}
Expand All @@ -19,8 +34,28 @@ function actPolyfill(cb) {

const act = reactAct || actPolyfill

function rtlAct(...args) {
return act(...args)
let youHaveBeenWarned = false
Copy link
Collaborator

Choose a reason for hiding this comment

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

😂

// this will not avoid warnings that react-dom 16.8.0 logs for triggering
// state updates asynchronously, but at least we can tell people they need
// to upgrade to avoid the warnings.
async function asyncActPolyfill(cb) {
if (!youHaveBeenWarned && actSupported) {
// if act is supported and async act isn't and they're trying to use async
// act, then they need to upgrade from 16.8 to 16.9.
// This is a seemless upgrade, so we'll add a warning
console.error(
`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.`,
)
youHaveBeenWarned = true
}
await cb()
// make all effects resolve after
act(() => {})
}

export default rtlAct
const asyncAct = asyncActSupported ? reactAct : asyncActPolyfill

export default act
export {asyncAct}

/* eslint no-console:0 */
11 changes: 10 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ import {
getQueriesForElement,
prettyDOM,
fireEvent as dtlFireEvent,
configure as configureDTL,
} from 'dom-testing-library'
import act from './act-compat'
import act, {asyncAct} from './act-compat'

configureDTL({
asyncWrapper: asyncAct,
})

const mountedContainers = new Set()

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

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

/* eslint func-name-matching:0 */