From 703c67560d1b5e5d32170cd513cda52559933527 Mon Sep 17 00:00:00 2001 From: Andrew Clark Date: Tue, 7 Mar 2023 10:15:34 -0500 Subject: [PATCH] Codemod act -> await act (1/?) (#26334) Similar to the rationale for `waitFor` (see https://github.com/facebook/react/pull/26285), we should always await the result of an `act` call so that microtasks have a chance to fire. This only affects the internal `act` that we use in our repo, for now. In the public `act` API, we don't yet require this; however, we effectively will for any update that triggers suspense once `use` lands. So we likely will start warning in an upcoming minor. --- .../ReactHooksInspectionIntegration-test.js | 42 +++--- .../ReactDOMConsoleErrorReporting-test.js | 124 +++++++++--------- .../src/__tests__/ReactDOMFiberAsync-test.js | 4 +- .../ReactDOMNativeEventHeuristic-test.js | 2 +- ...DOMServerPartialHydration-test.internal.js | 42 +++--- .../ReactErrorBoundaries-test.internal.js | 4 +- .../src/__tests__/ReactUpdates-test.js | 32 +++-- .../__tests__/useFocusWithin-test.internal.js | 20 +-- .../__tests__/ReactProfiler-test.internal.js | 100 +++++++------- .../__tests__/ReactStartTransition-test.js | 12 +- .../ReactStrictMode-test.internal.js | 16 +-- .../src/__tests__/ReactStrictMode-test.js | 16 +-- 12 files changed, 202 insertions(+), 212 deletions(-) diff --git a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js index 0b95cf215abcb..78c7e0ee21b44 100644 --- a/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js +++ b/packages/react-debug-tools/src/__tests__/ReactHooksInspectionIntegration-test.js @@ -26,7 +26,7 @@ describe('ReactHooksInspectionIntegration', () => { ReactDebugTools = require('react-debug-tools'); }); - it('should inspect the current state of useState hooks', () => { + it('should inspect the current state of useState hooks', async () => { const useState = React.useState; function Foo(props) { const [state1, setState1] = useState('hello'); @@ -61,7 +61,7 @@ describe('ReactHooksInspectionIntegration', () => { const {onMouseDown: setStateA, onMouseUp: setStateB} = renderer.root.findByType('div').props; - act(() => setStateA('Hi')); + await act(async () => setStateA('Hi')); childFiber = renderer.root.findByType(Foo)._currentFiber(); tree = ReactDebugTools.inspectHooksOfFiber(childFiber); @@ -83,7 +83,7 @@ describe('ReactHooksInspectionIntegration', () => { }, ]); - act(() => setStateB('world!')); + await act(async () => setStateB('world!')); childFiber = renderer.root.findByType(Foo)._currentFiber(); tree = ReactDebugTools.inspectHooksOfFiber(childFiber); @@ -106,7 +106,7 @@ describe('ReactHooksInspectionIntegration', () => { ]); }); - it('should inspect the current state of all stateful hooks', () => { + it('should inspect the current state of all stateful hooks', async () => { const outsideRef = React.createRef(); function effect() {} function Foo(props) { @@ -129,12 +129,8 @@ describe('ReactHooksInspectionIntegration', () => { React.useMemo(() => state1 + state2, [state1]); function update() { - act(() => { - setState('A'); - }); - act(() => { - dispatch({value: 'B'}); - }); + setState('A'); + dispatch({value: 'B'}); ref.current = 'C'; } const memoizedUpdate = React.useCallback(update, []); @@ -145,7 +141,7 @@ describe('ReactHooksInspectionIntegration', () => { ); } let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create(); }); @@ -207,7 +203,9 @@ describe('ReactHooksInspectionIntegration', () => { }, ]); - updateStates(); + await act(async () => { + updateStates(); + }); childFiber = renderer.root.findByType(Foo)._currentFiber(); tree = ReactDebugTools.inspectHooksOfFiber(childFiber); @@ -266,7 +264,7 @@ describe('ReactHooksInspectionIntegration', () => { ]); }); - it('should inspect the current state of all stateful hooks, including useInsertionEffect', () => { + it('should inspect the current state of all stateful hooks, including useInsertionEffect', async () => { const useInsertionEffect = React.useInsertionEffect; const outsideRef = React.createRef(); function effect() {} @@ -290,13 +288,9 @@ describe('ReactHooksInspectionIntegration', () => { React.useMemo(() => state1 + state2, [state1]); - function update() { - act(() => { - setState('A'); - }); - act(() => { - dispatch({value: 'B'}); - }); + async function update() { + setState('A'); + dispatch({value: 'B'}); ref.current = 'C'; } const memoizedUpdate = React.useCallback(update, []); @@ -307,7 +301,7 @@ describe('ReactHooksInspectionIntegration', () => { ); } let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create(); }); @@ -376,7 +370,9 @@ describe('ReactHooksInspectionIntegration', () => { }, ]); - updateStates(); + await act(async () => { + updateStates(); + }); childFiber = renderer.root.findByType(Foo)._currentFiber(); tree = ReactDebugTools.inspectHooksOfFiber(childFiber); @@ -967,7 +963,7 @@ describe('ReactHooksInspectionIntegration', () => { // This test case is based on an open source bug report: // https://github.com/facebookincubator/redux-react-hook/issues/34#issuecomment-466693787 - it('should properly advance the current hook for useContext', () => { + it('should properly advance the current hook for useContext', async () => { const MyContext = React.createContext(1); let incrementCount; diff --git a/packages/react-dom/src/__tests__/ReactDOMConsoleErrorReporting-test.js b/packages/react-dom/src/__tests__/ReactDOMConsoleErrorReporting-test.js index 03c4f97c4946a..8764c1907bac7 100644 --- a/packages/react-dom/src/__tests__/ReactDOMConsoleErrorReporting-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMConsoleErrorReporting-test.js @@ -17,6 +17,7 @@ describe('ReactDOMConsoleErrorReporting', () => { let NoError; let container; let windowOnError; + let waitForThrow; beforeEach(() => { jest.resetModules(); @@ -25,6 +26,9 @@ describe('ReactDOMConsoleErrorReporting', () => { ReactDOM = require('react-dom'); ReactDOMClient = require('react-dom/client'); + const InternalTestUtils = require('internal-test-utils'); + waitForThrow = InternalTestUtils.waitForThrow; + ErrorBoundary = class extends React.Component { state = {error: null}; static getDerivedStateFromError(error) { @@ -53,7 +57,7 @@ describe('ReactDOMConsoleErrorReporting', () => { }); describe('ReactDOMClient.createRoot', () => { - it('logs errors during event handlers', () => { + it('logs errors during event handlers', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -68,11 +72,11 @@ describe('ReactDOMConsoleErrorReporting', () => { } const root = ReactDOMClient.createRoot(container); - act(() => { + await act(async () => { root.render(); }); - act(() => { + await act(async () => { container.firstChild.dispatchEvent( new MouseEvent('click', { bubbles: true, @@ -142,7 +146,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { root.render(); }); expect(container.textContent).toBe('OK'); @@ -152,7 +156,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs render errors without an error boundary', () => { + it('logs render errors without an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -160,11 +164,10 @@ describe('ReactDOMConsoleErrorReporting', () => { } const root = ReactDOMClient.createRoot(container); - expect(() => { - act(() => { - root.render(); - }); - }).toThrow('Boom'); + await act(async () => { + root.render(); + await waitForThrow('Boom'); + }); if (__DEV__) { expect(windowOnError.mock.calls).toEqual([ @@ -226,7 +229,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { root.render(); }); expect(container.textContent).toBe('OK'); @@ -236,7 +239,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs render errors with an error boundary', () => { + it('logs render errors with an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -244,7 +247,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } const root = ReactDOMClient.createRoot(container); - act(() => { + await act(async () => { root.render( @@ -312,7 +315,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { root.render(); }); expect(container.textContent).toBe('OK'); @@ -322,7 +325,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs layout effect errors without an error boundary', () => { + it('logs layout effect errors without an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -333,11 +336,10 @@ describe('ReactDOMConsoleErrorReporting', () => { } const root = ReactDOMClient.createRoot(container); - expect(() => { - act(() => { - root.render(); - }); - }).toThrow('Boom'); + await act(async () => { + root.render(); + await waitForThrow('Boom'); + }); if (__DEV__) { expect(windowOnError.mock.calls).toEqual([ @@ -382,7 +384,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { root.render(); }); expect(container.textContent).toBe('OK'); @@ -392,7 +394,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs layout effect errors with an error boundary', () => { + it('logs layout effect errors with an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -403,7 +405,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } const root = ReactDOMClient.createRoot(container); - act(() => { + await act(async () => { root.render( @@ -454,7 +456,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { root.render(); }); expect(container.textContent).toBe('OK'); @@ -464,7 +466,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs passive effect errors without an error boundary', () => { + it('logs passive effect errors without an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -475,11 +477,10 @@ describe('ReactDOMConsoleErrorReporting', () => { } const root = ReactDOMClient.createRoot(container); - expect(() => { - act(() => { - root.render(); - }); - }).toThrow('Boom'); + await act(async () => { + root.render(); + await waitForThrow('Boom'); + }); if (__DEV__) { expect(windowOnError.mock.calls).toEqual([ @@ -524,7 +525,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { root.render(); }); expect(container.textContent).toBe('OK'); @@ -534,7 +535,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs passive effect errors with an error boundary', () => { + it('logs passive effect errors with an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -545,7 +546,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } const root = ReactDOMClient.createRoot(container); - act(() => { + await act(async () => { root.render( @@ -596,7 +597,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { root.render(); }); expect(container.textContent).toBe('OK'); @@ -608,7 +609,7 @@ describe('ReactDOMConsoleErrorReporting', () => { }); describe('ReactDOM.render', () => { - it('logs errors during event handlers', () => { + it('logs errors during event handlers', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -622,11 +623,11 @@ describe('ReactDOMConsoleErrorReporting', () => { ); } - act(() => { + await act(async () => { ReactDOM.render(, container); }); - act(() => { + await act(async () => { container.firstChild.dispatchEvent( new MouseEvent('click', { bubbles: true, @@ -697,7 +698,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { ReactDOM.render(, container); }); expect(container.textContent).toBe('OK'); @@ -709,7 +710,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs render errors without an error boundary', () => { + it('logs render errors without an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -717,9 +718,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } expect(() => { - act(() => { - ReactDOM.render(, container); - }); + ReactDOM.render(, container); }).toThrow('Boom'); if (__DEV__) { @@ -766,7 +765,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { ReactDOM.render(, container); }); expect(container.textContent).toBe('OK'); @@ -778,14 +777,14 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs render errors with an error boundary', () => { + it('logs render errors with an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { throw Error('Boom'); } - act(() => { + await act(async () => { ReactDOM.render( @@ -838,7 +837,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { ReactDOM.render(, container); }); expect(container.textContent).toBe('OK'); @@ -850,7 +849,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs layout effect errors without an error boundary', () => { + it('logs layout effect errors without an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -861,9 +860,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } expect(() => { - act(() => { - ReactDOM.render(, container); - }); + ReactDOM.render(, container); }).toThrow('Boom'); if (__DEV__) { @@ -910,7 +907,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { ReactDOM.render(, container); }); expect(container.textContent).toBe('OK'); @@ -922,7 +919,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs layout effect errors with an error boundary', () => { + it('logs layout effect errors with an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -932,7 +929,7 @@ describe('ReactDOMConsoleErrorReporting', () => { return null; } - act(() => { + await act(async () => { ReactDOM.render( @@ -985,7 +982,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { ReactDOM.render(, container); }); expect(container.textContent).toBe('OK'); @@ -997,7 +994,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs passive effect errors without an error boundary', () => { + it('logs passive effect errors without an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -1007,11 +1004,10 @@ describe('ReactDOMConsoleErrorReporting', () => { return null; } - expect(() => { - act(() => { - ReactDOM.render(, container); - }); - }).toThrow('Boom'); + await act(async () => { + ReactDOM.render(, container); + await waitForThrow('Boom'); + }); if (__DEV__) { expect(windowOnError.mock.calls).toEqual([ @@ -1057,7 +1053,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { ReactDOM.render(, container); }); expect(container.textContent).toBe('OK'); @@ -1069,7 +1065,7 @@ describe('ReactDOMConsoleErrorReporting', () => { } }); - it('logs passive effect errors with an error boundary', () => { + it('logs passive effect errors with an error boundary', async () => { spyOnDevAndProd(console, 'error'); function Foo() { @@ -1079,7 +1075,7 @@ describe('ReactDOMConsoleErrorReporting', () => { return null; } - act(() => { + await act(async () => { ReactDOM.render( @@ -1132,7 +1128,7 @@ describe('ReactDOMConsoleErrorReporting', () => { // Check next render doesn't throw. windowOnError.mockReset(); console.error.mockReset(); - act(() => { + await act(async () => { ReactDOM.render(, container); }); expect(container.textContent).toBe('OK'); diff --git a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js index 5fc2b2b9744a0..c89ba90866e04 100644 --- a/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMFiberAsync-test.js @@ -620,7 +620,7 @@ describe('ReactDOMFiberAsync', () => { expect(container.textContent).toEqual('ABC'); }); - it('unmounted roots should never clear newer root content from a container', () => { + it('unmounted roots should never clear newer root content from a container', async () => { const ref = React.createRef(); function OldApp() { @@ -643,7 +643,7 @@ describe('ReactDOMFiberAsync', () => { } const oldRoot = ReactDOMClient.createRoot(container); - act(() => { + await act(async () => { oldRoot.render(); }); diff --git a/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js b/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js index ead8b54eb519b..fd49b824efd71 100644 --- a/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMNativeEventHeuristic-test.js @@ -74,7 +74,7 @@ describe('ReactDOMNativeEventHeuristic-test', () => { } const root = ReactDOMClient.createRoot(container); - await act(() => { + await act(async () => { root.render(
); }); diff --git a/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js b/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js index 24ce917a18d5a..18833b0f64da4 100644 --- a/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactDOMServerPartialHydration-test.internal.js @@ -509,8 +509,8 @@ describe('ReactDOMServerPartialHydration', () => { expect(container.innerHTML).toContain('B'); expect(ref.current).toBe(null); - expect(() => { - act(() => { + await expect(async () => { + await act(async () => { ReactDOMClient.hydrateRoot(container, , { onRecoverableError(error) { Scheduler.log(error.message); @@ -579,7 +579,7 @@ describe('ReactDOMServerPartialHydration', () => { expect(ref.current).toBe(null); shouldSuspend = true; - act(() => { + await act(async () => { ReactDOMClient.hydrateRoot(container, ); }); @@ -635,8 +635,8 @@ describe('ReactDOMServerPartialHydration', () => { expect(container.innerHTML).toContain('B'); expect(ref.current).toBe(null); - expect(() => { - act(() => { + await expect(async () => { + await act(async () => { ReactDOMClient.hydrateRoot(container, , { onRecoverableError(error) { Scheduler.log(error.message); @@ -698,7 +698,7 @@ describe('ReactDOMServerPartialHydration', () => { expect(deleted.length).toBe(0); - act(() => { + await act(async () => { root.render(); }); @@ -743,8 +743,8 @@ describe('ReactDOMServerPartialHydration', () => { // On the client we try to hydrate. suspend = true; - expect(() => { - act(() => { + await expect(async () => { + await act(async () => { ReactDOM.hydrate(, container); }); }).toErrorDev( @@ -785,7 +785,7 @@ describe('ReactDOMServerPartialHydration', () => { expect(container.textContent).toBe('Hello'); }); - it('can insert siblings before the dehydrated boundary', () => { + it('can insert siblings before the dehydrated boundary', async () => { let suspend = false; const promise = new Promise(() => {}); let showSibling; @@ -829,20 +829,20 @@ describe('ReactDOMServerPartialHydration', () => { // hydrating anyway. suspend = true; - act(() => { + await act(async () => { ReactDOMClient.hydrateRoot(container, ); }); expect(container.firstChild.firstChild.tagName).not.toBe('DIV'); // In this state, we can still update the siblings. - act(() => showSibling()); + await act(async () => showSibling()); expect(container.firstChild.firstChild.tagName).toBe('DIV'); expect(container.firstChild.firstChild.textContent).toBe('First'); }); - it('can delete the dehydrated boundary before it is hydrated', () => { + it('can delete the dehydrated boundary before it is hydrated', async () => { let suspend = false; const promise = new Promise(() => {}); let hideMiddle; @@ -885,14 +885,14 @@ describe('ReactDOMServerPartialHydration', () => { // On the client we don't have all data yet but we want to start // hydrating anyway. suspend = true; - act(() => { + await act(async () => { ReactDOMClient.hydrateRoot(container, ); }); expect(container.firstChild.children[1].textContent).toBe('Middle'); // In this state, we can still delete the boundary. - act(() => hideMiddle()); + await act(async () => hideMiddle()); expect(container.firstChild.children[1].textContent).toBe('After'); }); @@ -1880,7 +1880,7 @@ describe('ReactDOMServerPartialHydration', () => { expect(container.textContent).toBe('AB'); // Add more rows before we've hydrated the first two. - act(() => { + await act(async () => { root.render(); }); @@ -3414,8 +3414,8 @@ describe('ReactDOMServerPartialHydration', () => { document.body.appendChild(container); container.innerHTML = finalHTML; - expect(() => { - act(() => { + await expect(async () => { + await act(async () => { ReactDOMClient.hydrateRoot(container, , { onRecoverableError(error) { Scheduler.log('Log recoverable error: ' + error.message); @@ -3461,8 +3461,8 @@ describe('ReactDOMServerPartialHydration', () => { container.innerHTML = ReactDOMServer.renderToString( , ); - expect(() => { - act(() => { + await expect(async () => { + await act(async () => { ReactDOMClient.hydrateRoot(container, , { onRecoverableError(error) { Scheduler.log(error.message); @@ -3502,8 +3502,8 @@ describe('ReactDOMServerPartialHydration', () => { container2.innerHTML = ReactDOMServer.renderToString( , ); - expect(() => { - act(() => { + await expect(async () => { + await act(async () => { ReactDOMClient.hydrateRoot( container2, , diff --git a/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js b/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js index 93e3a04494e43..f9a2a10e74b7a 100644 --- a/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js +++ b/packages/react-dom/src/__tests__/ReactErrorBoundaries-test.internal.js @@ -1862,9 +1862,9 @@ describe('ReactErrorBoundaries', () => { assertLog(['ErrorBoundary componentWillUnmount']); }); - it('catches errors in useEffect', () => { + it('catches errors in useEffect', async () => { const container = document.createElement('div'); - act(() => { + await act(async () => { ReactDOM.render( Initial value diff --git a/packages/react-dom/src/__tests__/ReactUpdates-test.js b/packages/react-dom/src/__tests__/ReactUpdates-test.js index 5555e1b0746c9..5e39cb88d59c3 100644 --- a/packages/react-dom/src/__tests__/ReactUpdates-test.js +++ b/packages/react-dom/src/__tests__/ReactUpdates-test.js @@ -1622,7 +1622,7 @@ describe('ReactUpdates', () => { // TODO: Replace this branch with @gate pragmas if (__DEV__) { - it('warns about a deferred infinite update loop with useEffect', () => { + it('warns about a deferred infinite update loop with useEffect', async () => { function NonTerminating() { const [step, setStep] = React.useState(0); React.useEffect(() => { @@ -1646,24 +1646,22 @@ describe('ReactUpdates', () => { try { const container = document.createElement('div'); expect(() => { - act(() => { - ReactDOM.render(, container); - while (error === null) { - Scheduler.unstable_flushNumberOfYields(1); - Scheduler.unstable_clearLog(); - } - expect(error).toContain('Warning: Maximum update depth exceeded.'); - expect(stack).toContain(' NonTerminating'); - // rethrow error to prevent going into an infinite loop when act() exits - throw error; - }); + ReactDOM.render(, container); + while (error === null) { + Scheduler.unstable_flushNumberOfYields(1); + Scheduler.unstable_clearLog(); + } + expect(error).toContain('Warning: Maximum update depth exceeded.'); + expect(stack).toContain(' NonTerminating'); + // rethrow error to prevent going into an infinite loop when act() exits + throw error; }).toThrow('Maximum update depth exceeded.'); } finally { console.error = originalConsoleError; } }); - it('can have nested updates if they do not cross the limit', () => { + it('can have nested updates if they do not cross the limit', async () => { let _setStep; const LIMIT = 50; @@ -1680,17 +1678,17 @@ describe('ReactUpdates', () => { } const container = document.createElement('div'); - act(() => { + await act(async () => { ReactDOM.render(, container); }); expect(container.textContent).toBe('50'); - act(() => { + await act(async () => { _setStep(0); }); expect(container.textContent).toBe('50'); }); - it('can have many updates inside useEffect without triggering a warning', () => { + it('can have many updates inside useEffect without triggering a warning', async () => { function Terminating() { const [step, setStep] = React.useState(0); React.useEffect(() => { @@ -1703,7 +1701,7 @@ describe('ReactUpdates', () => { } const container = document.createElement('div'); - act(() => { + await act(async () => { ReactDOM.render(, container); }); diff --git a/packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js b/packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js index f34b335cab687..cb8c4ab76a0dc 100644 --- a/packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js +++ b/packages/react-interactions/events/src/dom/create-event-handle/__tests__/useFocusWithin-test.internal.js @@ -298,7 +298,7 @@ describe.each(table)(`useFocus`, hasPointerEvents => { }); // @gate www - it('should correctly handle focus visibility when typing into an input', () => { + it('should correctly handle focus visibility when typing into an input', async () => { const onFocusWithinVisibleChange = jest.fn(); const ref = React.createRef(); const inputRef = React.createRef(); @@ -312,7 +312,7 @@ describe.each(table)(`useFocus`, hasPointerEvents => { ); }; - act(() => { + await act(async () => { ReactDOM.render(, container); }); @@ -477,7 +477,7 @@ describe.each(table)(`useFocus`, hasPointerEvents => { }); // @gate www - it('is called after a focused suspended element is hidden', () => { + it('is called after a focused suspended element is hidden', async () => { const Suspense = React.Suspense; let suspend = false; let resolve; @@ -508,7 +508,7 @@ describe.each(table)(`useFocus`, hasPointerEvents => { const root = ReactDOMClient.createRoot(container2); - act(() => { + await act(async () => { root.render(); }); jest.runAllTimers(); @@ -522,7 +522,7 @@ describe.each(table)(`useFocus`, hasPointerEvents => { expect(onAfterBlurWithin).toHaveBeenCalledTimes(0); suspend = true; - act(() => { + await act(async () => { root.render(); }); jest.runAllTimers(); @@ -535,7 +535,7 @@ describe.each(table)(`useFocus`, hasPointerEvents => { }); // @gate www - it('is called after a focused suspended element is hidden then shown', () => { + it('is called after a focused suspended element is hidden then shown', async () => { const Suspense = React.Suspense; let suspend = false; let resolve; @@ -567,7 +567,7 @@ describe.each(table)(`useFocus`, hasPointerEvents => { const root = ReactDOMClient.createRoot(container2); - act(() => { + await act(async () => { root.render(); }); jest.runAllTimers(); @@ -576,14 +576,14 @@ describe.each(table)(`useFocus`, hasPointerEvents => { expect(onAfterBlurWithin).toHaveBeenCalledTimes(0); suspend = true; - act(() => { + await act(async () => { root.render(); }); jest.runAllTimers(); expect(onBeforeBlurWithin).toHaveBeenCalledTimes(0); expect(onAfterBlurWithin).toHaveBeenCalledTimes(0); - act(() => { + await act(async () => { root.render(); }); jest.runAllTimers(); @@ -592,7 +592,7 @@ describe.each(table)(`useFocus`, hasPointerEvents => { buttonRef.current.focus(); suspend = false; - act(() => { + await act(async () => { root.render(); }); jest.runAllTimers(); diff --git a/packages/react/src/__tests__/ReactProfiler-test.internal.js b/packages/react/src/__tests__/ReactProfiler-test.internal.js index ac345c0125337..b20442b9e9da9 100644 --- a/packages/react/src/__tests__/ReactProfiler-test.internal.js +++ b/packages/react/src/__tests__/ReactProfiler-test.internal.js @@ -270,7 +270,7 @@ describe(`onRender`, () => { jest.mock('scheduler', () => jest.requireActual('scheduler/unstable_mock')); }); - it('does not report work done on a sibling', () => { + it('does not report work done on a sibling', async () => { const callback = jest.fn(); const DoesNotUpdate = React.memo( @@ -646,7 +646,7 @@ describe(`onRender`, () => { expect(updateCall[5]).toBe(43); // commit time }); - it('should clear nested-update flag when multiple cascading renders are scheduled', () => { + it('should clear nested-update flag when multiple cascading renders are scheduled', async () => { loadModules({ useNoopRenderer: true, }); @@ -672,7 +672,7 @@ describe(`onRender`, () => { const onRender = jest.fn(); - act(() => { + await act(async () => { ReactNoop.render( @@ -1569,7 +1569,7 @@ describe(`onCommit`, () => { expect(call[3]).toBe(1011); // commit start time (before mutations or effects) }); - it('should bubble time spent in layout effects to higher profilers', () => { + it('should bubble time spent in layout effects to higher profilers', async () => { const callback = jest.fn(); const ComponentWithEffects = ({cleanupDuration, duration, setCountRef}) => { @@ -1590,7 +1590,7 @@ describe(`onCommit`, () => { const setCountRef = React.createRef(null); let renderer = null; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( @@ -1617,7 +1617,7 @@ describe(`onCommit`, () => { expect(call[2]).toBe(1010); // durations expect(call[3]).toBe(2); // commit start time (before mutations or effects) - act(() => setCountRef.current(count => count + 1)); + await act(async () => setCountRef.current(count => count + 1)); expect(callback).toHaveBeenCalledTimes(2); @@ -1629,7 +1629,7 @@ describe(`onCommit`, () => { expect(call[2]).toBe(110); // durations expect(call[3]).toBe(1013); // commit start time (before mutations or effects) - act(() => { + await act(async () => { renderer.update( @@ -1650,7 +1650,7 @@ describe(`onCommit`, () => { expect(call[3]).toBe(1124); // commit start time (before mutations or effects) }); - it('should properly report time in layout effects even when there are errors', () => { + it('should properly report time in layout effects even when there are errors', async () => { const callback = jest.fn(); class ErrorBoundary extends React.Component { @@ -1688,7 +1688,7 @@ describe(`onCommit`, () => { // Test an error that happens during an effect - act(() => { + await act(async () => { ReactTestRenderer.create( { expect(call[3]).toBe(10110111); // commit start time (before mutations or effects) }); - it('should properly report time in layout effect cleanup functions even when there are errors', () => { + it('should properly report time in layout effect cleanup functions even when there are errors', async () => { const callback = jest.fn(); class ErrorBoundary extends React.Component { @@ -1774,7 +1774,7 @@ describe(`onCommit`, () => { let renderer = null; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( { // Test an error that happens during an cleanup function - act(() => { + await act(async () => { renderer.update( { Scheduler.unstable_advanceTime(1); let renderer; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( @@ -1922,7 +1922,7 @@ describe(`onPostCommit`, () => { Scheduler.unstable_advanceTime(1); - act(() => { + await act(async () => { renderer.update( @@ -1943,7 +1943,7 @@ describe(`onPostCommit`, () => { Scheduler.unstable_advanceTime(1); - act(() => { + await act(async () => { renderer.update( , ); @@ -1965,7 +1965,7 @@ describe(`onPostCommit`, () => { expect(call[3]).toBe(12030); // commit start time (before mutations or effects) }); - it('should report time spent in passive effects with cascading renders', () => { + it('should report time spent in passive effects with cascading renders', async () => { const callback = jest.fn(); const ComponentWithEffects = () => { @@ -1985,7 +1985,7 @@ describe(`onPostCommit`, () => { Scheduler.unstable_advanceTime(1); - act(() => { + await act(async () => { ReactTestRenderer.create( @@ -2012,7 +2012,7 @@ describe(`onPostCommit`, () => { expect(call[3]).toBe(2011); // commit start time (before mutations or effects) }); - it('should bubble time spent in effects to higher profilers', () => { + it('should bubble time spent in effects to higher profilers', async () => { const callback = jest.fn(); const ComponentWithEffects = ({cleanupDuration, duration, setCountRef}) => { @@ -2033,7 +2033,7 @@ describe(`onPostCommit`, () => { const setCountRef = React.createRef(null); let renderer = null; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( @@ -2060,7 +2060,7 @@ describe(`onPostCommit`, () => { expect(call[2]).toBe(1010); // durations expect(call[3]).toBe(2); // commit start time (before mutations or effects) - act(() => setCountRef.current(count => count + 1)); + await act(async () => setCountRef.current(count => count + 1)); expect(callback).toHaveBeenCalledTimes(2); @@ -2072,7 +2072,7 @@ describe(`onPostCommit`, () => { expect(call[2]).toBe(110); // durations expect(call[3]).toBe(1013); // commit start time (before mutations or effects) - act(() => { + await act(async () => { renderer.update( @@ -2093,7 +2093,7 @@ describe(`onPostCommit`, () => { expect(call[3]).toBe(1124); // commit start time (before mutations or effects) }); - it('should properly report time in passive effects even when there are errors', () => { + it('should properly report time in passive effects even when there are errors', async () => { const callback = jest.fn(); class ErrorBoundary extends React.Component { @@ -2131,7 +2131,7 @@ describe(`onPostCommit`, () => { // Test an error that happens during an effect - act(() => { + await act(async () => { ReactTestRenderer.create( { expect(call[3]).toBe(10110111); // commit start time (before mutations or effects) }); - it('should properly report time in passive effect cleanup functions even when there are errors', () => { + it('should properly report time in passive effect cleanup functions even when there are errors', async () => { const callback = jest.fn(); class ErrorBoundary extends React.Component { @@ -2218,7 +2218,7 @@ describe(`onPostCommit`, () => { let renderer = null; - act(() => { + await act(async () => { renderer = ReactTestRenderer.create( { // Test an error that happens during an cleanup function - act(() => { + await act(async () => { renderer.update( { expect(onNestedUpdateScheduled).not.toHaveBeenCalled(); }); - it('is called when a function component schedules an update during a layout effect', () => { + it('is called when a function component schedules an update during a layout effect', async () => { function Component() { const [didMount, setDidMount] = React.useState(false); React.useLayoutEffect(() => { @@ -2377,7 +2377,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduled = jest.fn(); - act(() => { + await act(async () => { ReactNoop.render( { expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('root'); }); - it('bubbles up and calls all ancestor Profilers', () => { + it('bubbles up and calls all ancestor Profilers', async () => { function Component() { const [didMount, setDidMount] = React.useState(false); React.useLayoutEffect(() => { @@ -2438,7 +2438,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduledTwo = jest.fn(); const onNestedUpdateScheduledThree = jest.fn(); - act(() => { + await act(async () => { ReactNoop.render( { expect(onNestedUpdateScheduledThree).not.toHaveBeenCalled(); }); - it('is not called when an update is scheduled for another doort during a layout effect', () => { + it('is not called when an update is scheduled for another doort during a layout effect', async () => { const setStateRef = React.createRef(null); function ComponentRootOne() { @@ -2486,7 +2486,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduled = jest.fn(); - act(() => { + await act(async () => { ReactNoop.renderToRootWithID( { expect(onNestedUpdateScheduled).not.toHaveBeenCalled(); }); - it('is not called when a function component schedules an update during a passive effect', () => { + it('is not called when a function component schedules an update during a passive effect', async () => { function Component() { const [didMount, setDidMount] = React.useState(false); React.useEffect(() => { @@ -2526,7 +2526,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduled = jest.fn(); - act(() => { + await act(async () => { ReactNoop.render( { expect(onNestedUpdateScheduled).not.toHaveBeenCalled(); }); - it('is not called when a function component schedules an update outside of render', () => { + it('is not called when a function component schedules an update outside of render', async () => { const updateFnRef = React.createRef(null); function Component() { @@ -2552,7 +2552,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduled = jest.fn(); - act(() => { + await act(async () => { ReactNoop.render( { }); assertLog(['Component:false']); - act(() => { + await act(async () => { updateFnRef.current(); }); assertLog(['Component:true']); expect(onNestedUpdateScheduled).not.toHaveBeenCalled(); }); - it('it is not called when a component schedules an update during render', () => { + it('it is not called when a component schedules an update during render', async () => { function Component() { const [state, setState] = React.useState(false); if (state === false) { @@ -2582,7 +2582,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduled = jest.fn(); - act(() => { + await act(async () => { ReactNoop.render( { expect(onNestedUpdateScheduled).not.toHaveBeenCalled(); }); - it('it is called when a component schedules an update from a ref callback', () => { + it('it is called when a component schedules an update from a ref callback', async () => { function Component({mountChild}) { const [refAttached, setRefAttached] = React.useState(false); const [refDetached, setRefDetached] = React.useState(false); @@ -2613,7 +2613,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduled = jest.fn(); - act(() => { + await act(async () => { ReactNoop.render( { expect(onNestedUpdateScheduled).toHaveBeenCalledTimes(1); expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test'); - act(() => { + await act(async () => { ReactNoop.render( { expect(onNestedUpdateScheduled.mock.calls[1][0]).toBe('test'); }); - it('is called when a class component schedules an update from the componentDidMount lifecycles', () => { + it('is called when a class component schedules an update from the componentDidMount lifecycles', async () => { class Component extends React.Component { state = { value: false, @@ -2659,7 +2659,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduled = jest.fn(); - act(() => { + await act(async () => { ReactNoop.render( { expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test'); }); - it('is called when a class component schedules an update from the componentDidUpdate lifecycles', () => { + it('is called when a class component schedules an update from the componentDidUpdate lifecycles', async () => { class Component extends React.Component { state = { nestedUpdateSheduled: false, @@ -2699,7 +2699,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduled = jest.fn(); - act(() => { + await act(async () => { ReactNoop.render( { assertLog(['Component:false:false']); expect(onNestedUpdateScheduled).not.toHaveBeenCalled(); - act(() => { + await act(async () => { ReactNoop.render( { expect(onNestedUpdateScheduled.mock.calls[0][0]).toBe('test'); }); - it('is not called when a class component schedules an update outside of render', () => { + it('is not called when a class component schedules an update outside of render', async () => { const updateFnRef = React.createRef(null); class Component extends React.Component { @@ -2743,7 +2743,7 @@ describe(`onNestedUpdateScheduled`, () => { const onNestedUpdateScheduled = jest.fn(); - act(() => { + await act(async () => { ReactNoop.render( { }); assertLog(['Component:false']); - act(() => { + await act(async () => { updateFnRef.current(); }); assertLog(['Component:true']); diff --git a/packages/react/src/__tests__/ReactStartTransition-test.js b/packages/react/src/__tests__/ReactStartTransition-test.js index d02a221afb481..8cab56798de5c 100644 --- a/packages/react/src/__tests__/ReactStartTransition-test.js +++ b/packages/react/src/__tests__/ReactStartTransition-test.js @@ -27,7 +27,7 @@ describe('ReactStartTransition', () => { useTransition = React.useTransition; }); - it('Warns if a suspicious number of fibers are updated inside startTransition', () => { + it('Warns if a suspicious number of fibers are updated inside startTransition', async () => { const subs = new Set(); const useUserSpaceSubscription = () => { const setState = useState(0)[1]; @@ -47,14 +47,14 @@ describe('ReactStartTransition', () => { return null; }; - act(() => { + await act(async () => { ReactTestRenderer.create(, { unstable_isConcurrent: true, }); }); - expect(() => { - act(() => { + await expect(async () => { + await act(async () => { React.startTransition(() => { subs.forEach(setState => { setState(state => state + 1); @@ -70,8 +70,8 @@ describe('ReactStartTransition', () => { {withoutStack: true}, ); - expect(() => { - act(() => { + await expect(async () => { + await act(async () => { triggerHookTransition(() => { subs.forEach(setState => { setState(state => state + 1); diff --git a/packages/react/src/__tests__/ReactStrictMode-test.internal.js b/packages/react/src/__tests__/ReactStrictMode-test.internal.js index 9661d0f72e35d..b0c65c7e22561 100644 --- a/packages/react/src/__tests__/ReactStrictMode-test.internal.js +++ b/packages/react/src/__tests__/ReactStrictMode-test.internal.js @@ -45,8 +45,8 @@ describe('ReactStrictMode', () => { return null; } - it('should default to not strict', () => { - act(() => { + it('should default to not strict', async () => { + await act(async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); root.render(); @@ -60,8 +60,8 @@ describe('ReactStrictMode', () => { }); if (__DEV__) { - it('should support enabling strict mode via createRoot option', () => { - act(() => { + it('should support enabling strict mode via createRoot option', async () => { + await act(async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container, { unstable_strictMode: true, @@ -81,8 +81,8 @@ describe('ReactStrictMode', () => { ]); }); - it('should include legacy + strict effects mode', () => { - act(() => { + it('should include legacy + strict effects mode', async () => { + await act(async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); root.render( @@ -104,8 +104,8 @@ describe('ReactStrictMode', () => { ]); }); - it('should allow level to be increased with nesting', () => { - act(() => { + it('should allow level to be increased with nesting', async () => { + await act(async () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); root.render( diff --git a/packages/react/src/__tests__/ReactStrictMode-test.js b/packages/react/src/__tests__/ReactStrictMode-test.js index 61d53a7318056..93ad52fe34fb9 100644 --- a/packages/react/src/__tests__/ReactStrictMode-test.js +++ b/packages/react/src/__tests__/ReactStrictMode-test.js @@ -356,7 +356,7 @@ describe('ReactStrictMode', () => { const root = ReactDOMClient.createRoot(container); // Mount - await act(() => { + await act(async () => { root.render( @@ -372,7 +372,7 @@ describe('ReactStrictMode', () => { log = []; // Update - await act(() => { + await act(async () => { root.render( @@ -407,7 +407,7 @@ describe('ReactStrictMode', () => { const root = ReactDOMClient.createRoot(container); // Mount - await act(() => { + await act(async () => { root.render( @@ -429,7 +429,7 @@ describe('ReactStrictMode', () => { log = []; // Update - await act(() => { + await act(async () => { root.render( @@ -463,7 +463,7 @@ describe('ReactStrictMode', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await act(() => { + await act(async () => { root.render( @@ -472,7 +472,7 @@ describe('ReactStrictMode', () => { }); expect(container.textContent).toBe('0'); - await act(() => { + await act(async () => { setCount(() => { log.push('Compute count: 1'); return 1; @@ -501,7 +501,7 @@ describe('ReactStrictMode', () => { const container = document.createElement('div'); const root = ReactDOMClient.createRoot(container); - await act(() => { + await act(async () => { root.render( @@ -510,7 +510,7 @@ describe('ReactStrictMode', () => { }); expect(container.textContent).toBe('0'); - await act(() => { + await act(async () => { dispatch(1); }); expect(container.textContent).toBe('1');