Repository: facebook/react
Pull request: Convert ReactFreshIntegration-test to createRoot

Convert ReactFreshIntegration-test to createRoot


Changed files:
filename: packages/react-refresh/src/__tests__/ReactFreshIntegration-test.js
patch: @@ -12,16 +12,19 @@
 'use strict';
 
 let React;
-let ReactDOM;
+let ReactDOMClient;
 let ReactFreshRuntime;
+let Scheduler;
 let act;
+let assertLog;
 
 const babel = require('@babel/core');
 const freshPlugin = require('react-refresh/babel');
 const ts = require('typescript');
 
 describe('ReactFreshIntegration', () => {
   let container;
+  let root;
   let exportsObj;
 
   beforeEach(() => {
@@ -30,17 +33,19 @@ describe('ReactFreshIntegration', () => {
       React = require('react');
       ReactFreshRuntime = require('react-refresh/runtime');
       ReactFreshRuntime.injectIntoGlobalHook(global);
-      ReactDOM = require('react-dom');
-      act = React.unstable_act;
+      ReactDOMClient = require('react-dom/client');
+      Scheduler = require('scheduler/unstable_mock');
+      ({act, assertLog} = require('internal-test-utils'));
       container = document.createElement('div');
       document.body.appendChild(container);
+      root = ReactDOMClient.createRoot(container);
       exportsObj = undefined;
     }
   });
 
   afterEach(() => {
     if (__DEV__) {
-      ReactDOM.unmountComponentAtNode(container);
+      root.unmount();
       // Ensure we don't leak memory by holding onto dead roots.
       expect(ReactFreshRuntime._getMountedRootCount()).toBe(0);
       document.body.removeChild(container);
@@ -82,11 +87,12 @@ describe('ReactFreshIntegration', () => {
     new Function(
       'global',
       'React',
+      'Scheduler',
       'exports',
       '$RefreshReg$',
       '$RefreshSig$',
       compiled,
-    )(global, React, exportsObj, $RefreshReg$, $RefreshSig$);
+    )(global, React, Scheduler, exportsObj, $RefreshReg$, $RefreshSig$);
     // Module systems will register exports as a fallback.
     // This is useful for cases when e.g. a class is exported,
     // and we don't want to propagate the update beyond this module.
@@ -115,16 +121,16 @@ describe('ReactFreshIntegration', () => {
     ],
     ['TypeScript syntax', executeTypescript, testTypeScript],
   ])('%s', (language, execute, test) => {
-    function render(source) {
+    async function render(source) {
       const Component = execute(source);
-      act(() => {
-        ReactDOM.render(<Component />, container);
+      await act(() => {
+        root.render(<Component />);
       });
       // Module initialization shouldn't be counted as a hot update.
       expect(ReactFreshRuntime.performReactRefresh()).toBe(null);
     }
 
-    function patch(source) {
+    async function patch(source) {
       const prevExports = exportsObj;
       execute(source);
       const nextExports = exportsObj;
@@ -142,11 +148,11 @@ describe('ReactFreshIntegration', () => {
         // This makes adding/removing/renaming exports re-render references to them.
         // Here, we'll just force a re-render using the newer type to emulate this.
         const NextComponent = nextExports.default;
-        act(() => {
-          ReactDOM.render(<NextComponent />, container);
+        await act(() => {
+          root.render(<NextComponent />);
         });
       }
-      act(() => {
+      await act(() => {
         const result = ReactFreshRuntime.performReactRefresh();
         if (!didExportsChange) {
           // Normally we expect that some components got updated in our tests.
@@ -164,9 +170,9 @@ describe('ReactFreshIntegration', () => {
   });
 
   function testJavaScript(render, patch) {
-    it('reloads function declarations', () => {
+    it('reloads function declarations', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           function Parent() {
             return <Child prop="A" />;
           };
@@ -179,7 +185,7 @@ describe('ReactFreshIntegration', () => {
         `);
         const el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           function Parent() {
             return <Child prop="B" />;
           };
@@ -195,9 +201,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('reloads arrow functions', () => {
+    it('reloads arrow functions', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const Parent = () => {
             return <Child prop="A" />;
           };
@@ -210,7 +216,7 @@ describe('ReactFreshIntegration', () => {
         `);
         const el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           const Parent = () => {
             return <Child prop="B" />;
           };
@@ -226,9 +232,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('reloads a combination of memo and forwardRef', () => {
+    it('reloads a combination of memo and forwardRef', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {memo} = React;
 
           const Parent = memo(React.forwardRef(function (props, ref) {
@@ -243,7 +249,7 @@ describe('ReactFreshIntegration', () => {
         `);
         const el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           const {memo} = React;
 
           const Parent = memo(React.forwardRef(function (props, ref) {
@@ -261,9 +267,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('reloads default export with named memo', () => {
+    it('reloads default export with named memo', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {memo} = React;
 
           const Child = React.memo(({prop}) => {
@@ -276,7 +282,7 @@ describe('ReactFreshIntegration', () => {
         `);
         const el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           const {memo} = React;
 
           const Child = React.memo(({prop}) => {
@@ -292,9 +298,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('reloads HOCs if they return functions', () => {
+    it('reloads HOCs if they return functions', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           function hoc(letter) {
             return function() {
               return <h1>{letter}1</h1>;
@@ -309,7 +315,7 @@ describe('ReactFreshIntegration', () => {
         `);
         const el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           function hoc(letter) {
             return function() {
               return <h1>{letter}2</h1>;
@@ -327,9 +333,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('resets state when renaming a state variable', () => {
+    it('resets state when renaming a state variable', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useState} = React;
           const S = 1;
 
@@ -341,7 +347,7 @@ describe('ReactFreshIntegration', () => {
         const el = container.firstChild;
         expect(el.textContent).toBe('A1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 2;
 
@@ -354,7 +360,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 3;
 
@@ -370,9 +376,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('resets state when renaming a state variable in a HOC', () => {
+    it('resets state when renaming a state variable in a HOC', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useState} = React;
           const S = 1;
 
@@ -390,7 +396,7 @@ describe('ReactFreshIntegration', () => {
         const el = container.firstChild;
         expect(el.textContent).toBe('A1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 2;
 
@@ -409,7 +415,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 3;
 
@@ -431,9 +437,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('resets state when renaming a state variable in a HOC with indirection', () => {
+    it('resets state when renaming a state variable in a HOC with indirection', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useState} = React;
           const S = 1;
 
@@ -453,7 +459,7 @@ describe('ReactFreshIntegration', () => {
         const el = container.firstChild;
         expect(el.textContent).toBe('A1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 2;
 
@@ -474,7 +480,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 3;
 
@@ -498,9 +504,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('resets state when renaming a state variable inside a HOC with direct call', () => {
+    it('resets state when renaming a state variable inside a HOC with direct call', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useState} = React;
           const S = 1;
 
@@ -518,7 +524,7 @@ describe('ReactFreshIntegration', () => {
         const el = container.firstChild;
         expect(el.textContent).toBe('A1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 2;
 
@@ -537,7 +543,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 3;
 
@@ -559,9 +565,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('does not crash when changing Hook order inside a HOC with direct call', () => {
+    it('does not crash when changing Hook order inside a HOC with direct call', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useEffect} = React;
 
           function hocWithDirectCall(Wrapped) {
@@ -578,7 +584,7 @@ describe('ReactFreshIntegration', () => {
         const el = container.firstChild;
         expect(el.textContent).toBe('A');
 
-        patch(`
+        await patch(`
           const {useEffect} = React;
 
           function hocWithDirectCall(Wrapped) {
@@ -600,9 +606,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('does not crash when changing Hook order inside a memo-ed HOC with direct call', () => {
+    it('does not crash when changing Hook order inside a memo-ed HOC with direct call', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useEffect, memo} = React;
 
           function hocWithDirectCall(Wrapped) {
@@ -619,7 +625,7 @@ describe('ReactFreshIntegration', () => {
         const el = container.firstChild;
         expect(el.textContent).toBe('A');
 
-        patch(`
+        await patch(`
           const {useEffect, memo} = React;
 
           function hocWithDirectCall(Wrapped) {
@@ -641,9 +647,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('does not crash when changing Hook order inside a memo+forwardRef-ed HOC with direct call', () => {
+    it('does not crash when changing Hook order inside a memo+forwardRef-ed HOC with direct call', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useEffect, memo, forwardRef} = React;
 
           function hocWithDirectCall(Wrapped) {
@@ -660,7 +666,7 @@ describe('ReactFreshIntegration', () => {
         const el = container.firstChild;
         expect(el.textContent).toBe('A');
 
-        patch(`
+        await patch(`
           const {useEffect, memo, forwardRef} = React;
 
           function hocWithDirectCall(Wrapped) {
@@ -682,9 +688,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('does not crash when changing Hook order inside a HOC returning an object', () => {
+    it('does not crash when changing Hook order inside a HOC returning an object', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useEffect} = React;
 
           function hocWithDirectCall(Wrapped) {
@@ -699,7 +705,7 @@ describe('ReactFreshIntegration', () => {
         const el = container.firstChild;
         expect(el.textContent).toBe('A');
 
-        patch(`
+        await patch(`
           const {useEffect} = React;
 
           function hocWithDirectCall(Wrapped) {
@@ -719,9 +725,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('resets effects while preserving state', () => {
+    it('resets effects while preserving state', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useState} = React;
 
           export default function App() {
@@ -733,41 +739,39 @@ describe('ReactFreshIntegration', () => {
         expect(el.textContent).toBe('A0');
 
         // Add an effect.
-        patch(`
+        await patch(`
           const {useState} = React;
 
           export default function App() {
             const [value, setValue] = useState(0);
             React.useEffect(() => {
-              const id = setInterval(() => {
-                setValue(v => v + 1);
-              }, 1000);
-              return () => clearInterval(id);
+              Scheduler.log('B mount');
+              setValue(1)
+              return () => {
+                Scheduler.log('B unmount');
+              };
             }, []);
             return <h1>B{value}</h1>;
           }
         `);
+
         // We added an effect, thereby changing Hook order.
         // This causes a remount.
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
-        expect(el.textContent).toBe('B0');
-
-        act(() => {
-          jest.advanceTimersByTime(1000);
-        });
         expect(el.textContent).toBe('B1');
+        assertLog(['B mount']);
 
-        patch(`
+        await patch(`
           const {useState} = React;
 
           export default function App() {
             const [value, setValue] = useState(0);
             React.useEffect(() => {
-              const id = setInterval(() => {
-                setValue(v => v + 10);
-              }, 1000);
-              return () => clearInterval(id);
+              Scheduler.log('C mount');
+              return () => {
+                Scheduler.log('C unmount');
+              };
             }, []);
             return <h1>C{value}</h1>;
           }
@@ -776,14 +780,10 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('C1');
 
-        // Effects are always reset, so timer was reinstalled.
-        // The new version increments by 10 rather than 1.
-        act(() => {
-          jest.advanceTimersByTime(1000);
-        });
-        expect(el.textContent).toBe('C11');
+        // Effects are always reset, so effect B was unmounted and C was mounted.
+        assertLog(['B unmount', 'C mount']);
 
-        patch(`
+        await patch(`
           const {useState} = React;
 
           export default function App() {
@@ -796,12 +796,13 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
         expect(el.textContent).toBe('D0');
+        assertLog(['C unmount']);
       }
     });
 
-    it('does not get confused when custom hooks are reordered', () => {
+    it('does not get confused when custom hooks are reordered', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           function useFancyState(initialState) {
             return React.useState(initialState);
           }
@@ -817,7 +818,7 @@ describe('ReactFreshIntegration', () => {
         let el = container.firstChild;
         expect(el.textContent).toBe('AXY');
 
-        patch(`
+        await patch(`
           function useFancyState(initialState) {
             return React.useState(initialState);
           }
@@ -834,7 +835,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('BXY');
 
-        patch(`
+        await patch(`
           function useFancyState(initialState) {
             return React.useState(initialState);
           }
@@ -855,9 +856,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('does not get confused when component is called early', () => {
+    it('does not get confused when component is called early', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           // This isn't really a valid pattern but it's close enough
           // to simulate what happens when you call ReactDOM.render
           // in the same file. We want to ensure this doesn't confuse
@@ -881,7 +882,7 @@ describe('ReactFreshIntegration', () => {
         let el = container.firstChild;
         expect(el.textContent).toBe('AXY');
 
-        patch(`
+        await patch(`
           // This isn't really a valid pattern but it's close enough
           // to simulate what happens when you call ReactDOM.render
           // in the same file. We want to ensure this doesn't confuse
@@ -906,7 +907,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('BXY');
 
-        patch(`
+        await patch(`
           // This isn't really a valid pattern but it's close enough
           // to simulate what happens when you call ReactDOM.render
           // in the same file. We want to ensure this doesn't confuse
@@ -935,10 +936,10 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('does not get confused by Hooks defined inline', () => {
+    it('does not get confused by Hooks defined inline', async () => {
       // This is not a recommended pattern but at least it shouldn't break.
       if (__DEV__) {
-        render(`
+        await render(`
           const App = () => {
             const useFancyState = (initialState) => {
               const result = React.useState(initialState);
@@ -954,7 +955,7 @@ describe('ReactFreshIntegration', () => {
         let el = container.firstChild;
         expect(el.textContent).toBe('AX1Y1');
 
-        patch(`
+        await patch(`
           const App = () => {
             const useFancyState = (initialState) => {
               const result = React.useState(initialState);
@@ -978,9 +979,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('remounts component if custom hook it uses changes order', () => {
+    it('remounts component if custom hook it uses changes order', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const App = () => {
             const [x, setX] = useFancyState('X');
             const [y, setY] = useFancyState('Y');
@@ -1001,7 +1002,7 @@ describe('ReactFreshIntegration', () => {
         let el = container.firstChild;
         expect(el.textContent).toBe('AXY');
 
-        patch(`
+        await patch(`
           const App = () => {
             const [x, setX] = useFancyState('X');
             const [y, setY] = useFancyState('Y');
@@ -1024,7 +1025,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('BXY');
 
-        patch(`
+        await patch(`
           const App = () => {
             const [x, setX] = useFancyState('X');
             const [y, setY] = useFancyState('Y');
@@ -1049,7 +1050,7 @@ describe('ReactFreshIntegration', () => {
         el = container.firstChild;
         expect(el.textContent).toBe('CXY');
 
-        patch(`
+        await patch(`
           const App = () => {
             const [x, setX] = useFancyState('X');
             const [y, setY] = useFancyState('Y');
@@ -1075,9 +1076,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('does not lose the inferred arrow names', () => {
+    it('does not lose the inferred arrow names', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const Parent = () => {
             return <Child/>;
           };
@@ -1097,9 +1098,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('does not lose the inferred function names', () => {
+    it('does not lose the inferred function names', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           var Parent = function() {
             return <Child/>;
           };
@@ -1119,9 +1120,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('resets state on every edit with @refresh reset annotation', () => {
+    it('resets state on every edit with @refresh reset annotation', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useState} = React;
           const S = 1;
 
@@ -1133,7 +1134,7 @@ describe('ReactFreshIntegration', () => {
         let el = container.firstChild;
         expect(el.textContent).toBe('A1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 2;
 
@@ -1146,7 +1147,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 3;
 
@@ -1162,7 +1163,7 @@ describe('ReactFreshIntegration', () => {
         el = container.firstChild;
         expect(el.textContent).toBe('C3');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 4;
 
@@ -1179,7 +1180,7 @@ describe('ReactFreshIntegration', () => {
         el = container.firstChild;
         expect(el.textContent).toBe('D4');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 5;
 
@@ -1193,7 +1194,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('E4');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 6;
 
@@ -1206,7 +1207,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('F4');
 
-        patch(`
+        await patch(`
           const {useState} = React;
           const S = 7;
 
@@ -1227,9 +1228,9 @@ describe('ReactFreshIntegration', () => {
 
     // This is best effort for simple cases.
     // We won't attempt to resolve identifiers.
-    it('resets state when useState initial state is edited', () => {
+    it('resets state when useState initial state is edited', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useState} = React;
 
           export default function App() {
@@ -1240,7 +1241,7 @@ describe('ReactFreshIntegration', () => {
         let el = container.firstChild;
         expect(el.textContent).toBe('A1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
 
           export default function App() {
@@ -1252,7 +1253,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B1');
 
-        patch(`
+        await patch(`
           const {useState} = React;
 
           export default function App() {
@@ -1269,9 +1270,9 @@ describe('ReactFreshIntegration', () => {
 
     // This is best effort for simple cases.
     // We won't attempt to resolve identifiers.
-    it('resets state when useReducer initial state is edited', () => {
+    it('resets state when useReducer initial state is edited', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           const {useReducer} = React;
 
           export default function App() {
@@ -1282,7 +1283,7 @@ describe('ReactFreshIntegration', () => {
         let el = container.firstChild;
         expect(el.textContent).toBe('A1');
 
-        patch(`
+        await patch(`
           const {useReducer} = React;
 
           export default function App() {
@@ -1294,7 +1295,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B1');
 
-        patch(`
+        await patch(`
           const {useReducer} = React;
 
           export default function App() {
@@ -1309,16 +1310,16 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('remounts when switching export from function to class', () => {
+    it('remounts when switching export from function to class', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           export default function App() {
             return <h1>A1</h1>;
           }
         `);
         let el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>A2</h1>;
           }
@@ -1327,7 +1328,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('A2');
 
-        patch(`
+        await patch(`
           export default class App extends React.Component {
             render() {
               return <h1>B1</h1>
@@ -1338,7 +1339,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
         expect(el.textContent).toBe('B1');
-        patch(`
+        await patch(`
           export default class App extends React.Component {
             render() {
               return <h1>B2</h1>
@@ -1350,7 +1351,7 @@ describe('ReactFreshIntegration', () => {
         el = container.firstChild;
         expect(el.textContent).toBe('B2');
 
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>C1</h1>;
           }
@@ -1359,22 +1360,22 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
         expect(el.textContent).toBe('C1');
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>C2</h1>;
           }
         `);
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('C2');
 
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>D1</h1>;
           }
         `);
         el = container.firstChild;
         expect(el.textContent).toBe('D1');
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>D2</h1>;
           }
@@ -1385,9 +1386,9 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('remounts when switching export from class to function', () => {
+    it('remounts when switching export from class to function', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           export default class App extends React.Component {
             render() {
               return <h1>A1</h1>
@@ -1396,7 +1397,7 @@ describe('ReactFreshIntegration', () => {
         `);
         let el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           export default class App extends React.Component {
             render() {
               return <h1>A2</h1>
@@ -1408,7 +1409,7 @@ describe('ReactFreshIntegration', () => {
         el = container.firstChild;
         expect(el.textContent).toBe('A2');
 
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>B1</h1>;
           }
@@ -1417,7 +1418,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
         expect(el.textContent).toBe('B1');
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>B2</h1>;
           }
@@ -1426,7 +1427,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B2');
 
-        patch(`
+        await patch(`
           export default class App extends React.Component {
             render() {
               return <h1>C1</h1>
@@ -1440,16 +1441,16 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('remounts when wrapping export in a HOC', () => {
+    it('remounts when wrapping export in a HOC', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           export default function App() {
             return <h1>A1</h1>;
           }
         `);
         let el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>A2</h1>;
           }
@@ -1458,7 +1459,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('A2');
 
-        patch(`
+        await patch(`
           function hoc(Inner) {
             return function Wrapper() {
               return <Inner />;
@@ -1475,7 +1476,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
         expect(el.textContent).toBe('B1');
-        patch(`
+        await patch(`
           function hoc(Inner) {
             return function Wrapper() {
               return <Inner />;
@@ -1492,7 +1493,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B2');
 
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>C1</h1>;
           }
@@ -1501,7 +1502,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
         expect(el.textContent).toBe('C1');
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>C2</h1>;
           }
@@ -1511,16 +1512,16 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('remounts when wrapping export in memo()', () => {
+    it('remounts when wrapping export in memo()', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           export default function App() {
             return <h1>A1</h1>;
           }
         `);
         let el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>A2</h1>;
           }
@@ -1529,7 +1530,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('A2');
 
-        patch(`
+        await patch(`
           function App() {
             return <h1>B1</h1>;
           }
@@ -1540,7 +1541,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
         expect(el.textContent).toBe('B1');
-        patch(`
+        await patch(`
           function App() {
             return <h1>B2</h1>;
           }
@@ -1551,7 +1552,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B2');
 
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>C1</h1>;
           }
@@ -1560,7 +1561,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
         expect(el.textContent).toBe('C1');
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>C2</h1>;
           }
@@ -1570,16 +1571,16 @@ describe('ReactFreshIntegration', () => {
       }
     });
 
-    it('remounts when wrapping export in forwardRef()', () => {
+    it('remounts when wrapping export in forwardRef()', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           export default function App() {
             return <h1>A1</h1>;
           }
         `);
         let el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>A2</h1>;
           }
@@ -1588,7 +1589,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('A2');
 
-        patch(`
+        await patch(`
           function App() {
             return <h1>B1</h1>;
           }
@@ -1599,7 +1600,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
         expect(el.textContent).toBe('B1');
-        patch(`
+        await patch(`
           function App() {
             return <h1>B2</h1>;
           }
@@ -1610,7 +1611,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).toBe(el);
         expect(el.textContent).toBe('B2');
 
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>C1</h1>;
           }
@@ -1619,7 +1620,7 @@ describe('ReactFreshIntegration', () => {
         expect(container.firstChild).not.toBe(el);
         el = container.firstChild;
         expect(el.textContent).toBe('C1');
-        patch(`
+        await patch(`
           export default function App() {
             return <h1>C2</h1>;
           }
@@ -1630,10 +1631,10 @@ describe('ReactFreshIntegration', () => {
     });
 
     if (!require('shared/ReactFeatureFlags').disableModulePatternComponents) {
-      it('remounts deprecated factory components', () => {
+      it('remounts deprecated factory components', async () => {
         if (__DEV__) {
-          expect(() => {
-            render(`
+          await expect(async () => {
+            await render(`
               function Parent() {
                 return {
                   render() {
@@ -1654,7 +1655,7 @@ describe('ReactFreshIntegration', () => {
           );
           const el = container.firstChild;
           expect(el.textContent).toBe('A1');
-          patch(`
+          await patch(`
             function Parent() {
               return {
                 render() {
@@ -1686,14 +1687,14 @@ describe('ReactFreshIntegration', () => {
         delete global.FakeModuleSystem;
       });
 
-      it('remounts component if custom hook it uses changes order on first edit', () => {
+      it('remounts component if custom hook it uses changes order on first edit', async () => {
         // This test verifies that remounting works even if calls to custom Hooks
         // were transformed with an inline requires transform, like we have on RN.
         // Inline requires make it harder to compare previous and next signatures
         // because useFancyState inline require always resolves to the newest version.
         // We're not actually using inline requires in the test, but it has similar semantics.
         if (__DEV__) {
-          render(`
+          await render(`
             const FakeModuleSystem = global.FakeModuleSystem;
 
             FakeModuleSystem.useFancyState = function(initialState) {
@@ -1711,7 +1712,7 @@ describe('ReactFreshIntegration', () => {
           let el = container.firstChild;
           expect(el.textContent).toBe('AXY');
 
-          patch(`
+          await patch(`
             const FakeModuleSystem = global.FakeModuleSystem;
 
             FakeModuleSystem.useFancyState = function(initialState) {
@@ -1733,7 +1734,7 @@ describe('ReactFreshIntegration', () => {
           el = container.firstChild;
           expect(el.textContent).toBe('BXY');
 
-          patch(`
+          await patch(`
             const FakeModuleSystem = global.FakeModuleSystem;
 
             FakeModuleSystem.useFancyState = function(initialState) {
@@ -1756,9 +1757,9 @@ describe('ReactFreshIntegration', () => {
         }
       });
 
-      it('remounts component if custom hook it uses changes order on second edit', () => {
+      it('remounts component if custom hook it uses changes order on second edit', async () => {
         if (__DEV__) {
-          render(`
+          await render(`
             const FakeModuleSystem = global.FakeModuleSystem;
 
             FakeModuleSystem.useFancyState = function(initialState) {
@@ -1776,7 +1777,7 @@ describe('ReactFreshIntegration', () => {
           let el = container.firstChild;
           expect(el.textContent).toBe('AXY');
 
-          patch(`
+          await patch(`
             const FakeModuleSystem = global.FakeModuleSystem;
 
             FakeModuleSystem.useFancyState = function(initialState) {
@@ -1794,7 +1795,7 @@ describe('ReactFreshIntegration', () => {
           expect(container.firstChild).toBe(el);
           expect(el.textContent).toBe('BXY');
 
-          patch(`
+          await patch(`
             const FakeModuleSystem = global.FakeModuleSystem;
 
             FakeModuleSystem.useFancyState = function(initialState) {
@@ -1816,7 +1817,7 @@ describe('ReactFreshIntegration', () => {
           el = container.firstChild;
           expect(el.textContent).toBe('CXY');
 
-          patch(`
+          await patch(`
             const FakeModuleSystem = global.FakeModuleSystem;
 
             FakeModuleSystem.useFancyState = function(initialState) {
@@ -1839,9 +1840,9 @@ describe('ReactFreshIntegration', () => {
         }
       });
 
-      it('recovers if evaluating Hook list throws', () => {
+      it('recovers if evaluating Hook list throws', async () => {
         if (__DEV__) {
-          render(`
+          await render(`
           let FakeModuleSystem = null;
 
           global.FakeModuleSystem.useFancyState = function(initialState) {
@@ -1860,7 +1861,7 @@ describe('ReactFreshIntegration', () => {
           let el = container.firstChild;
           expect(el.textContent).toBe('AXY');
 
-          patch(`
+          await patch(`
           let FakeModuleSystem = null;
 
           global.FakeModuleSystem.useFancyState = function(initialState) {
@@ -1885,9 +1886,9 @@ describe('ReactFreshIntegration', () => {
         }
       });
 
-      it('remounts component if custom hook it uses changes order behind an indirection', () => {
+      it('remounts component if custom hook it uses changes order behind an indirection', async () => {
         if (__DEV__) {
-          render(`
+          await render(`
             const FakeModuleSystem = global.FakeModuleSystem;
 
             FakeModuleSystem.useFancyState = function(initialState) {
@@ -1913,7 +1914,7 @@ describe('ReactFreshIntegration', () => {
           let el = container.firstChild;
           expect(el.textContent).toBe('AXY');
 
-          patch(`
+          await patch(`
             const FakeModuleSystem = global.FakeModuleSystem;
 
             FakeModuleSystem.useFancyState = function(initialState) {
@@ -1944,7 +1945,7 @@ describe('ReactFreshIntegration', () => {
           el = container.firstChild;
           expect(el.textContent).toBe('BXY');
 
-          patch(`
+          await patch(`
             const FakeModuleSystem = global.FakeModuleSystem;
 
             FakeModuleSystem.useFancyState = function(initialState) {
@@ -1978,9 +1979,9 @@ describe('ReactFreshIntegration', () => {
   }
 
   function testTypeScript(render, patch) {
-    it('reloads component exported in typescript namespace', () => {
+    it('reloads component exported in typescript namespace', async () => {
       if (__DEV__) {
-        render(`
+        await render(`
           namespace Foo {
             export namespace Bar {
               export const Child = ({prop}) => {
@@ -1995,7 +1996,7 @@ describe('ReactFreshIntegration', () => {
         `);
         const el = container.firstChild;
         expect(el.textContent).toBe('A1');
-        patch(`
+        await patch(`
           namespace Foo {
             export namespace Bar {
               export const Child = ({prop}) => {