Skip to content

Commit c48b501

Browse files
LaurensBosscherthreepointone
authored and
Kent C. Dodds
committedOct 30, 2019
fix: manually flush microtasks in afterEach (#514)
This PR replaces calling async act() in afterEach, with a version that still flushes microtasks, but doesn't wrap with act(). Explanation: If there are any hanging microtasks, that means a test ran without asserting on a valid state. Any async portion that causes updates should be asserted on, or atleast resolved within the scope of a test. This PR should still fire missing act warnings for a test, but won't let it leak to the next one. Co-authored-by: Sunil Pai <[email protected]>
1 parent 991dbfa commit c48b501

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed
 

‎src/flush-microtasks.js

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/* istanbul ignore file */
2+
// the part of this file that we need tested is definitely being run
3+
// and the part that is not cannot easily have useful tests written
4+
// anyway. So we're just going to ignore coverage for this file
5+
/**
6+
* copied from React's enqueueTask.js
7+
*/
8+
9+
let didWarnAboutMessageChannel = false
10+
let enqueueTask
11+
try {
12+
// read require off the module object to get around the bundlers.
13+
// we don't want them to detect a require and bundle a Node polyfill.
14+
const requireString = `require${Math.random()}`.slice(0, 7)
15+
const nodeRequire = module && module[requireString]
16+
// assuming we're in node, let's try to get node's
17+
// version of setImmediate, bypassing fake timers if any.
18+
enqueueTask = nodeRequire('timers').setImmediate
19+
} catch (_err) {
20+
// we're in a browser
21+
// we can't use regular timers because they may still be faked
22+
// so we try MessageChannel+postMessage instead
23+
enqueueTask = callback => {
24+
if (didWarnAboutMessageChannel === false) {
25+
didWarnAboutMessageChannel = true
26+
// eslint-disable-next-line no-console
27+
console.error(
28+
typeof MessageChannel !== 'undefined',
29+
'This browser does not have a MessageChannel implementation, ' +
30+
'so enqueuing tasks via await act(async () => ...) will fail. ' +
31+
'Please file an issue at https://github.com/facebook/react/issues ' +
32+
'if you encounter this warning.',
33+
)
34+
}
35+
const channel = new MessageChannel()
36+
channel.port1.onmessage = callback
37+
channel.port2.postMessage(undefined)
38+
}
39+
}
40+
41+
export default function flushMicroTasks() {
42+
return {
43+
then(resolve) {
44+
enqueueTask(resolve)
45+
},
46+
}
47+
}

‎src/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {asyncAct} from './act-compat'
1+
import flush from './flush-microtasks'
22
import {cleanup} from './pure'
33

44
// if we're running in a test runner that supports afterEach
@@ -8,7 +8,7 @@ import {cleanup} from './pure'
88
// or set the RTL_SKIP_AUTO_CLEANUP env variable to 'true'.
99
if (typeof afterEach === 'function' && !process.env.RTL_SKIP_AUTO_CLEANUP) {
1010
afterEach(async () => {
11-
await asyncAct(async () => {})
11+
await flush()
1212
cleanup()
1313
})
1414
}

0 commit comments

Comments
 (0)
Please sign in to comment.