diff --git a/packages/react-dom/src/__tests__/ReactDOMHooks-test.js b/packages/react-dom/src/__tests__/ReactDOMHooks-test.js index 59ec9dd4f7a9e..faf182236f6aa 100644 --- a/packages/react-dom/src/__tests__/ReactDOMHooks-test.js +++ b/packages/react-dom/src/__tests__/ReactDOMHooks-test.js @@ -12,6 +12,7 @@ let React; let ReactDOM; let Scheduler; +let act; describe('ReactDOMHooks', () => { let container; @@ -22,6 +23,7 @@ describe('ReactDOMHooks', () => { React = require('react'); ReactDOM = require('react-dom'); Scheduler = require('scheduler'); + act = require('react-dom/test-utils').unstable_concurrentAct; container = document.createElement('div'); document.body.appendChild(container); @@ -106,7 +108,7 @@ describe('ReactDOMHooks', () => { }); // @gate experimental - it('should not bail out when an update is scheduled from within an event handler in Concurrent Mode', () => { + it('should not bail out when an update is scheduled from within an event handler in Concurrent Mode', async () => { const {createRef, useCallback, useState} = React; const Example = ({inputRef, labelRef}) => { @@ -132,11 +134,14 @@ describe('ReactDOMHooks', () => { Scheduler.unstable_flushAll(); inputRef.current.value = 'abc'; - inputRef.current.dispatchEvent( - new Event('input', {bubbles: true, cancelable: true}), - ); - - Scheduler.unstable_flushAll(); + await act(async () => { + inputRef.current.dispatchEvent( + new Event('input', { + bubbles: true, + cancelable: true, + }), + ); + }); expect(labelRef.current.innerHTML).toBe('abc'); }); diff --git a/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js b/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js index 4067df79f372a..57807679e8eb2 100644 --- a/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js +++ b/packages/react-dom/src/__tests__/ReactTestUtilsAct-test.js @@ -187,7 +187,7 @@ function runActTests(label, render, unmount, rerender) { expect(Scheduler).toHaveYielded([100]); }); - it('flushes effects on every call', () => { + it('flushes effects on every call', async () => { function App() { const [ctr, setCtr] = React.useState(0); React.useEffect(() => { @@ -209,16 +209,16 @@ function runActTests(label, render, unmount, rerender) { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); } - act(() => { + await act(async () => { click(); click(); click(); }); // it consolidates the 3 updates, then fires the effect expect(Scheduler).toHaveYielded([3]); - act(click); + await act(async () => click()); expect(Scheduler).toHaveYielded([4]); - act(click); + await act(async () => click()); expect(Scheduler).toHaveYielded([5]); expect(button.innerHTML).toBe('5'); }); diff --git a/packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js b/packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js index 041231cac30cd..2a806b2888c18 100644 --- a/packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js +++ b/packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js @@ -685,7 +685,7 @@ describe('ChangeEventPlugin', () => { }); // @gate experimental - it('is async for non-input events', () => { + it('is async for non-input events', async () => { const root = ReactDOM.unstable_createRoot(container); let input; diff --git a/packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js b/packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js index 92ee2e369315a..0579e9571cbc2 100644 --- a/packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js +++ b/packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js @@ -13,6 +13,7 @@ describe('SimpleEventPlugin', function() { let React; let ReactDOM; let Scheduler; + let TestUtils; let onClick; let container; @@ -39,6 +40,7 @@ describe('SimpleEventPlugin', function() { React = require('react'); ReactDOM = require('react-dom'); Scheduler = require('scheduler'); + TestUtils = require('react-dom/test-utils'); onClick = jest.fn(); }); @@ -314,7 +316,7 @@ describe('SimpleEventPlugin', function() { }); // @gate experimental - it('end result of many interactive updates is deterministic', () => { + it('end result of many interactive updates is deterministic', async () => { container = document.createElement('div'); const root = ReactDOM.unstable_createRoot(container); document.body.appendChild(container); @@ -361,12 +363,14 @@ describe('SimpleEventPlugin', function() { expect(button.textContent).toEqual('Count: 0'); // Click the button many more times - click(); - click(); - click(); - click(); - click(); - click(); + await TestUtils.act(async () => { + click(); + click(); + click(); + click(); + click(); + click(); + }); // Flush the remaining work Scheduler.unstable_flushAll(); @@ -375,7 +379,7 @@ describe('SimpleEventPlugin', function() { }); // @gate experimental - it('flushes discrete updates in order', () => { + it('flushes discrete updates in order', async () => { container = document.createElement('div'); document.body.appendChild(container); diff --git a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js index 06668b4eb3896..4cdb4410ba592 100644 --- a/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactIncrementalErrorHandling-test.internal.js @@ -232,7 +232,8 @@ describe('ReactIncrementalErrorHandling', () => { expect(ReactNoop.getChildren()).toEqual([span('Caught an error: oops!')]); }); - it("retries at a lower priority if there's additional pending work", () => { + // @gate experimental + it("retries at a lower priority if there's additional pending work", async () => { function App(props) { if (props.isBroken) { Scheduler.unstable_yieldValue('error'); @@ -252,14 +253,14 @@ describe('ReactIncrementalErrorHandling', () => { }); } - ReactNoop.discreteUpdates(() => { - ReactNoop.render(, onCommit); - }); + ReactNoop.render(, onCommit); expect(Scheduler).toFlushAndYieldThrough(['error']); interrupt(); - // This update is in a separate batch - ReactNoop.render(, onCommit); + React.unstable_startTransition(() => { + // This update is in a separate batch + ReactNoop.render(, onCommit); + }); expect(Scheduler).toFlushAndYieldThrough([ // The first render fails. But because there's a lower priority pending @@ -311,16 +312,16 @@ describe('ReactIncrementalErrorHandling', () => { }); } - ReactNoop.discreteUpdates(() => { - ReactNoop.render(, onCommit); - }); + ReactNoop.render(, onCommit); expect(Scheduler).toFlushAndYieldThrough(['error']); interrupt(); expect(ReactNoop).toMatchRenderedOutput(null); - // This update is in a separate batch - ReactNoop.render(, onCommit); + React.unstable_startTransition(() => { + // This update is in a separate batch + ReactNoop.render(, onCommit); + }); expect(Scheduler).toFlushAndYieldThrough([ // The first render fails. But because there's a lower priority pending @@ -1786,6 +1787,7 @@ describe('ReactIncrementalErrorHandling', () => { }); } + // @gate experimental it('uncaught errors should be discarded if the render is aborted', async () => { const root = ReactNoop.createRoot(); @@ -1795,22 +1797,24 @@ describe('ReactIncrementalErrorHandling', () => { } await ReactNoop.act(async () => { - ReactNoop.discreteUpdates(() => { - root.render(); - }); + root.render(); + // Render past the component that throws, then yield. expect(Scheduler).toFlushAndYieldThrough(['Oops']); expect(root).toMatchRenderedOutput(null); // Interleaved update. When the root completes, instead of throwing the // error, it should try rendering again. This update will cause it to // recover gracefully. - root.render('Everything is fine.'); + React.unstable_startTransition(() => { + root.render('Everything is fine.'); + }); }); // Should finish without throwing. expect(root).toMatchRenderedOutput('Everything is fine.'); }); + // @gate experimental it('uncaught errors are discarded if the render is aborted, case 2', async () => { const {useState} = React; const root = ReactNoop.createRoot(); @@ -1835,21 +1839,20 @@ describe('ReactIncrementalErrorHandling', () => { }); await ReactNoop.act(async () => { - // Schedule a high pri and a low pri update on the root. - ReactNoop.discreteUpdates(() => { - root.render(); + // Schedule a default pri and a low pri update on the root. + root.render(); + React.unstable_startTransition(() => { + root.render(); }); - root.render(); - // Render through just the high pri update. The low pri update remains on + + // Render through just the default pri update. The low pri update remains on // the queue. expect(Scheduler).toFlushAndYieldThrough(['Everything is fine.']); - // Schedule a high pri update on a child that triggers an error. + // Schedule a default pri update on a child that triggers an error. // The root should capture this error. But since there's still a pending // update on the root, the error should be suppressed. - ReactNoop.discreteUpdates(() => { - setShouldThrow(true); - }); + setShouldThrow(true); }); // Should render the final state without throwing the error. expect(Scheduler).toHaveYielded(['Everything is fine.']); diff --git a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js index 3fc2e8e573ba0..5021c32c8b11e 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspenseWithNoopRenderer-test.js @@ -570,14 +570,13 @@ describe('ReactSuspenseWithNoopRenderer', () => { ); } - // Schedule a high pri update and a low pri update, without rendering in - // between. - ReactNoop.discreteUpdates(() => { - // High pri - ReactNoop.render(); - }); + // Schedule a default pri update and a low pri update, without rendering in between. + // Default pri + ReactNoop.render(); // Low pri - ReactNoop.render(); + React.unstable_startTransition(() => { + ReactNoop.render(); + }); expect(Scheduler).toFlushAndYield([ // The first update suspends @@ -1879,9 +1878,7 @@ describe('ReactSuspenseWithNoopRenderer', () => { ReactNoop.render(); expect(Scheduler).toFlushAndYield(['Foo']); - ReactNoop.discreteUpdates(() => - ReactNoop.render(), - ); + ReactNoop.render(); expect(Scheduler).toFlushAndYieldThrough(['Foo']); // Advance some time. @@ -3080,48 +3077,48 @@ describe('ReactSuspenseWithNoopRenderer', () => { // Schedule an update inside the Suspense boundary that suspends. setAppText('B'); expect(Scheduler).toFlushAndYield(['Suspend! [B]', 'Loading...']); + }); - // Commit the placeholder - await advanceTimers(250); - expect(root).toMatchRenderedOutput( - <> -