@@ -16,7 +16,7 @@ let act;
16
16
17
17
describe ( 'ReactDOMSafariMicrotaskBug-test' , ( ) => {
18
18
let container ;
19
- let simulateSafariBug ;
19
+ let flushMicrotasksPrematurely ;
20
20
21
21
beforeEach ( ( ) => {
22
22
// In Safari, microtasks don't always run on clean stack.
@@ -27,9 +27,12 @@ describe('ReactDOMSafariMicrotaskBug-test', () => {
27
27
window . queueMicrotask = function ( cb ) {
28
28
queue . push ( cb ) ;
29
29
} ;
30
- simulateSafariBug = function ( ) {
31
- queue . forEach ( cb => cb ( ) ) ;
32
- queue = [ ] ;
30
+ flushMicrotasksPrematurely = function ( ) {
31
+ while ( queue . length > 0 ) {
32
+ const prevQueue = queue ;
33
+ queue = [ ] ;
34
+ prevQueue . forEach ( cb => cb ( ) ) ;
35
+ }
33
36
} ;
34
37
35
38
jest . resetModules ( ) ;
@@ -45,7 +48,7 @@ describe('ReactDOMSafariMicrotaskBug-test', () => {
45
48
document . body . removeChild ( container ) ;
46
49
} ) ;
47
50
48
- it ( 'should be resilient to buggy queueMicrotask ' , async ( ) => {
51
+ it ( 'should deal with premature microtask in commit phase ' , async ( ) => {
49
52
let ran = false ;
50
53
function Foo ( ) {
51
54
const [ state , setState ] = React . useState ( 0 ) ;
@@ -55,7 +58,7 @@ describe('ReactDOMSafariMicrotaskBug-test', () => {
55
58
if ( ! ran ) {
56
59
ran = true ;
57
60
setState ( 1 ) ;
58
- simulateSafariBug ( ) ;
61
+ flushMicrotasksPrematurely ( ) ;
59
62
}
60
63
} } >
61
64
{ state }
@@ -68,4 +71,30 @@ describe('ReactDOMSafariMicrotaskBug-test', () => {
68
71
} ) ;
69
72
expect ( container . textContent ) . toBe ( '1' ) ;
70
73
} ) ;
74
+
75
+ it ( 'should deal with premature microtask in event handler' , async ( ) => {
76
+ function Foo ( ) {
77
+ const [ state , setState ] = React . useState ( 0 ) ;
78
+ return (
79
+ < button
80
+ onClick = { ( ) => {
81
+ setState ( 1 ) ;
82
+ flushMicrotasksPrematurely ( ) ;
83
+ } } >
84
+ { state }
85
+ </ button >
86
+ ) ;
87
+ }
88
+ const root = ReactDOMClient . createRoot ( container ) ;
89
+ await act ( async ( ) => {
90
+ root . render ( < Foo /> ) ;
91
+ } ) ;
92
+ expect ( container . textContent ) . toBe ( '0' ) ;
93
+ await act ( async ( ) => {
94
+ container . firstChild . dispatchEvent (
95
+ new MouseEvent ( 'click' , { bubbles : true } ) ,
96
+ ) ;
97
+ } ) ;
98
+ expect ( container . textContent ) . toBe ( '1' ) ;
99
+ } ) ;
71
100
} ) ;
0 commit comments