From 90a0ae101571f58781225dd0dc1948b0a15ea9e4 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Tue, 20 Feb 2024 15:40:16 -0500 Subject: [PATCH] Remove RTR from ReactSuspense-test (#28390) ## Summary Cleaning up internal usage of ReactTestRenderer ## How did you test this change? `yarn test packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js` --- .../__tests__/ReactSuspense-test.internal.js | 454 +++++++++--------- 1 file changed, 225 insertions(+), 229 deletions(-) diff --git a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js index 4440f900294a7..ab68bdc7817cb 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js @@ -1,10 +1,12 @@ let React; -let ReactTestRenderer; +let ReactDOMClient; +let ReactDOM; let ReactFeatureFlags; let Scheduler; let Suspense; let act; let textCache; +let container; let assertLog; let waitForPaint; @@ -18,9 +20,11 @@ describe('ReactSuspense', () => { ReactFeatureFlags.replayFailedUnitOfWorkWithInvokeGuardedCallback = false; React = require('react'); - ReactTestRenderer = require('react-test-renderer'); + ReactDOM = require('react-dom'); + ReactDOMClient = require('react-dom/client'); act = require('internal-test-utils').act; Scheduler = require('scheduler'); + container = document.createElement('div'); Suspense = React.Suspense; @@ -115,18 +119,19 @@ describe('ReactSuspense', () => { ); } + const root = ReactDOMClient.createRoot(container); // Render an empty shell - const root = ReactTestRenderer.create(, { - isConcurrent: true, + await act(() => { + root.render(); }); - - await waitForAll(['Foo']); - expect(root).toMatchRenderedOutput(null); + assertLog(['Foo']); + const renderedEl = container; + expect(renderedEl.innerText).toBeUndefined(); // Navigate the shell to now render the child content. // This should suspend. React.startTransition(() => { - root.update(); + root.render(); }); await waitForAll([ @@ -136,19 +141,20 @@ describe('ReactSuspense', () => { 'Suspend! [A]', 'Loading...', ]); - expect(root).toMatchRenderedOutput(null); + expect(container.textContent).toEqual(''); await waitForAll([]); - expect(root).toMatchRenderedOutput(null); + expect(container.textContent).toEqual(''); - await resolveText('A'); + resolveText('A'); await waitForAll(['Foo', 'Bar', 'A', 'B']); - expect(root).toMatchRenderedOutput('AB'); + expect(container.textContent).toEqual('AB'); }); it('suspends siblings and later recovers each independently', async () => { + const root = ReactDOMClient.createRoot(container); // Render two sibling Suspense components - const root = ReactTestRenderer.create( + root.render( <> }> @@ -157,9 +163,6 @@ describe('ReactSuspense', () => { , - { - isConcurrent: true, - }, ); await waitForAll([ @@ -168,19 +171,19 @@ describe('ReactSuspense', () => { 'Suspend! [B]', 'Loading B...', ]); - expect(root).toMatchRenderedOutput('Loading A...Loading B...'); + expect(container.innerHTML).toEqual('Loading A...Loading B...'); // Resolve first Suspense's promise and switch back to the normal view. The // second Suspense should still show the placeholder await act(() => resolveText('A')); assertLog(['A']); - expect(root).toMatchRenderedOutput('ALoading B...'); + expect(container.textContent).toEqual('ALoading B...'); // Resolve the second Suspense's promise resolves and switche back to the // normal view await act(() => resolveText('B')); assertLog(['B']); - expect(root).toMatchRenderedOutput('AB'); + expect(container.textContent).toEqual('AB'); }); it('interrupts current render if promise resolves before current render phase', async () => { @@ -210,22 +213,22 @@ describe('ReactSuspense', () => { Scheduler.log('Async'); return 'Async'; } + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render( + <> + } /> + + , + ); + }); - const root = ReactTestRenderer.create( - <> - } /> - - , - { - isConcurrent: true, - }, - ); - await waitForAll(['Initial']); - expect(root).toMatchRenderedOutput('Initial'); + assertLog(['Initial']); + expect(container.textContent).toEqual('Initial'); // The update will suspend. React.startTransition(() => { - root.update( + root.render( <> }> @@ -242,7 +245,7 @@ describe('ReactSuspense', () => { // The promise resolves before the current render phase has completed resolveThenable(); assertLog([]); - expect(root).toMatchRenderedOutput('Initial'); + expect(container.textContent).toEqual('Initial'); // Start over from the root, instead of continuing. await waitForAll([ @@ -251,7 +254,7 @@ describe('ReactSuspense', () => { 'After Suspense', 'Sibling', ]); - expect(root).toMatchRenderedOutput('AsyncAfter SuspenseSibling'); + expect(container.textContent).toEqual('AsyncAfter SuspenseSibling'); }); it('throttles fallback committing globally', async () => { @@ -267,12 +270,13 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(, { - isConcurrent: true, + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); }); - await waitForAll(['Foo', 'Suspend! [A]', 'Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); + assertLog(['Foo', 'Suspend! [A]', 'Loading...']); + expect(container.textContent).toEqual('Loading...'); await resolveText('A'); await waitForAll(['A', 'Suspend! [B]', 'Loading more...']); @@ -280,13 +284,13 @@ describe('ReactSuspense', () => { // By this point, we have enough info to show "A" and "Loading more..." // However, we've just shown the outer fallback. So we'll delay // showing the inner fallback hoping that B will resolve soon enough. - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); await act(() => resolveText('B')); // By this point, B has resolved. // The contents of both should pop in together. assertLog(['A', 'B']); - expect(root).toMatchRenderedOutput('AB'); + expect(container.textContent).toEqual('AB'); }); it('does not throttle fallback committing for too long', async () => { @@ -302,12 +306,12 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(, { - isConcurrent: true, + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); }); - - await waitForAll(['Foo', 'Suspend! [A]', 'Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); + assertLog(['Foo', 'Suspend! [A]', 'Loading...']); + expect(container.textContent).toEqual('Loading...'); await resolveText('A'); await waitForAll(['A', 'Suspend! [B]', 'Loading more...']); @@ -315,16 +319,16 @@ describe('ReactSuspense', () => { // By this point, we have enough info to show "A" and "Loading more..." // However, we've just shown the outer fallback. So we'll delay // showing the inner fallback hoping that B will resolve soon enough. - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); // But if we wait a bit longer, eventually we'll give up and show a // fallback. The exact value here isn't important. It's a JND ("Just // Noticeable Difference"). jest.advanceTimersByTime(500); - expect(root).toMatchRenderedOutput('ALoading more...'); + expect(container.textContent).toEqual('ALoading more...'); await act(() => resolveText('B')); assertLog(['B']); - expect(root).toMatchRenderedOutput('AB'); + expect(container.textContent).toEqual('AB'); }); // @gate forceConcurrentByDefaultForTesting @@ -333,10 +337,12 @@ describe('ReactSuspense', () => { "delay and we've already skipped over a lower priority update in " + 'a parent', async () => { + const root = ReactDOMClient.createRoot(container); + function interrupt() { // React has a heuristic to batch all updates that occur within the same // event. This is a trick to circumvent that heuristic. - ReactTestRenderer.create('whatever'); + ReactDOM.render('whatever', document.createElement('div')); } function App({shouldSuspend, step}) { @@ -352,16 +358,12 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(null, { - isConcurrent: true, - }); - - root.update(); + root.render(); await waitForAll(['A0', 'B0', 'C0']); - expect(root).toMatchRenderedOutput('A0B0C0'); + expect(container.textContent).toEqual('A0B0C0'); // This update will suspend. - root.update(); + root.render(); // Do a bit of work await waitFor(['A1']); @@ -369,7 +371,7 @@ describe('ReactSuspense', () => { // Schedule another update. This will have lower priority because it's // a transition. React.startTransition(() => { - root.update(); + root.render(); }); // Interrupt to trigger a restart. @@ -384,7 +386,7 @@ describe('ReactSuspense', () => { ]); // Should not have committed loading state - expect(root).toMatchRenderedOutput('A0B0C0'); + expect(container.textContent).toEqual('A0B0C0'); // After suspending, should abort the first update and switch to the // second update. So, C1 should not appear in the log. @@ -393,11 +395,11 @@ describe('ReactSuspense', () => { // the render before the end of the current slice of work. await waitForAll(['A2', 'B2', 'C2']); - expect(root).toMatchRenderedOutput('A2B2C2'); + expect(container.textContent).toEqual('A2B2C2'); }, ); - it('mounts a lazy class component in non-concurrent mode', async () => { + it('mounts a lazy class component in non-concurrent mode (legacy)', async () => { class Class extends React.Component { componentDidMount() { Scheduler.log('Did mount: ' + this.props.label); @@ -416,19 +418,20 @@ describe('ReactSuspense', () => { const LazyClass = React.lazy(() => fakeImport(Class)); - const root = ReactTestRenderer.create( + ReactDOM.render( }> , + container, ); assertLog(['Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); await LazyClass; await waitForPaint(['Hi', 'Did mount: Hi']); - expect(root).toMatchRenderedOutput('Hi'); + expect(container.textContent).toEqual('Hi'); }); it('updates memoized child of suspense component when context updates (simple memo)', async () => { @@ -455,21 +458,22 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(, { - isConcurrent: true, + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); }); - await waitForAll(['Suspend! [default]', 'Loading...']); + assertLog(['Suspend! [default]', 'Loading...']); await act(() => resolveText('default')); assertLog(['default']); - expect(root).toMatchRenderedOutput('default'); + expect(container.textContent).toEqual('default'); await act(() => setValue('new value')); assertLog(['Suspend! [new value]', 'Loading...']); await act(() => resolveText('new value')); assertLog(['new value']); - expect(root).toMatchRenderedOutput('new value'); + expect(container.textContent).toEqual('new value'); }); it('updates memoized child of suspense component when context updates (manual memo)', async () => { @@ -501,21 +505,22 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(, { - isConcurrent: true, + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); }); - await waitForAll(['Suspend! [default]', 'Loading...']); + assertLog(['Suspend! [default]', 'Loading...']); await act(() => resolveText('default')); assertLog(['default']); - expect(root).toMatchRenderedOutput('default'); + expect(container.textContent).toEqual('default'); await act(() => setValue('new value')); assertLog(['Suspend! [new value]', 'Loading...']); await act(() => resolveText('new value')); assertLog(['new value']); - expect(root).toMatchRenderedOutput('new value'); + expect(container.textContent).toEqual('new value'); }); it('updates memoized child of suspense component when context updates (function)', async () => { @@ -538,28 +543,28 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create( - - }> - - - , - { - isConcurrent: true, - }, - ); - await waitForAll(['Suspend! [default]', 'Loading...']); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render( + + }> + + + , + ); + }); + assertLog(['Suspend! [default]', 'Loading...']); await act(() => resolveText('default')); assertLog(['default']); - expect(root).toMatchRenderedOutput('default'); + expect(container.textContent).toEqual('default'); await act(() => setValue('new value')); assertLog(['Suspend! [new value]', 'Loading...']); await act(() => resolveText('new value')); assertLog(['new value']); - expect(root).toMatchRenderedOutput('new value'); + expect(container.textContent).toEqual('new value'); }); it('updates memoized child of suspense component when context updates (forwardRef)', async () => { @@ -582,28 +587,28 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create( - - }> - - - , - { - isConcurrent: true, - }, - ); - await waitForAll(['Suspend! [default]', 'Loading...']); + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render( + + }> + + + , + ); + }); + assertLog(['Suspend! [default]', 'Loading...']); await act(() => resolveText('default')); assertLog(['default']); - expect(root).toMatchRenderedOutput('default'); + expect(container.textContent).toEqual('default'); await act(() => setValue('new value')); assertLog(['Suspend! [new value]', 'Loading...']); await act(() => resolveText('new value')); assertLog(['new value']); - expect(root).toMatchRenderedOutput('new value'); + expect(container.textContent).toEqual('new value'); }); it('re-fires layout effects when re-showing Suspense', async () => { @@ -630,12 +635,13 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(, { - isConcurrent: true, + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); }); - await waitForAll(['Child 1', 'create layout']); - expect(root).toMatchRenderedOutput('Child 1'); + assertLog(['Child 1', 'create layout']); + expect(container.textContent).toEqual('Child 1'); await act(() => { _setShow(true); @@ -649,10 +655,36 @@ describe('ReactSuspense', () => { await act(() => resolveText('Child 2')); assertLog(['Child 1', 'Child 2', 'create layout']); - expect(root).toMatchRenderedOutput(['Child 1', 'Child 2'].join('')); + expect(container.textContent).toEqual(['Child 1', 'Child 2'].join('')); }); - describe('outside concurrent mode', () => { + it('does not get stuck with fallback in concurrent mode for a large delay', async () => { + function App(props) { + return ( + }> + + + + ); + } + + const root = ReactDOMClient.createRoot(container); + await act(() => { + root.render(); + }); + + assertLog(['Suspend! [Child 1]', 'Loading...']); + await resolveText('Child 1'); + await waitForAll(['Child 1', 'Suspend! [Child 2]']); + + jest.advanceTimersByTime(6000); + + await act(() => resolveText('Child 2')); + assertLog(['Child 1', 'Child 2']); + expect(container.textContent).toEqual(['Child 1', 'Child 2'].join('')); + }); + + describe('outside concurrent mode (legacy)', () => { it('a mounted class component can suspend without losing state', async () => { class TextWithLifecycle extends React.Component { componentDidMount() { @@ -698,8 +730,7 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(); - + ReactDOM.render(, container); assertLog([ 'A', 'Suspend! [B:1]', @@ -712,24 +743,24 @@ describe('ReactSuspense', () => { 'Mount [C]', 'Mount [Loading...]', ]); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); await resolveText('B:1'); - await waitForPaint([ + assertLog([ 'B:1', 'Unmount [Loading...]', // Should be a mount, not an update 'Mount [B:1]', ]); - expect(root).toMatchRenderedOutput('AB:1C'); + expect(container.textContent).toEqual('AB:1C'); instance.setState({step: 2}); assertLog(['Suspend! [B:2]', 'Loading...', 'Mount [Loading...]']); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); await resolveText('B:2'); - await waitForPaint(['B:2', 'Unmount [Loading...]', 'Update [B:2]']); - expect(root).toMatchRenderedOutput('AB:2C'); + assertLog(['B:2', 'Unmount [Loading...]', 'Update [B:2]']); + expect(container.textContent).toEqual('AB:2C'); }); it('bails out on timed-out primary children even if they receive an update', async () => { @@ -751,25 +782,25 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(); + ReactDOM.render(, container); assertLog(['Stateful: 1', 'Suspend! [A]', 'Loading...']); await resolveText('A'); - await waitForPaint(['A']); - expect(root).toMatchRenderedOutput('Stateful: 1A'); + assertLog(['A']); + expect(container.textContent).toEqual('Stateful: 1A'); - root.update(); + ReactDOM.render(, container); assertLog(['Stateful: 1', 'Suspend! [B]', 'Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); instance.setState({step: 2}); assertLog(['Stateful: 2', 'Suspend! [B]']); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); await resolveText('B'); - await waitForPaint(['B']); - expect(root).toMatchRenderedOutput('Stateful: 2B'); + assertLog(['B']); + expect(container.textContent).toEqual('Stateful: 2B'); }); it('when updating a timed-out tree, always retries the suspended component', async () => { @@ -799,17 +830,17 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(); + ReactDOM.render(, container); assertLog(['Stateful: 1', 'Suspend! [A]', 'Loading...']); await resolveText('A'); - await waitForPaint(['A']); - expect(root).toMatchRenderedOutput('Stateful: 1A'); + assertLog(['A']); + expect(container.textContent).toEqual('Stateful: 1A'); - root.update(); + ReactDOM.render(, container); assertLog(['Stateful: 1', 'Suspend! [B]', 'Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); instance.setState({step: 2}); assertLog([ @@ -820,14 +851,14 @@ describe('ReactSuspense', () => { // pending work, so it was improperly treated as complete. 'Suspend! [B]', ]); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); await resolveText('B'); - await waitForPaint(['B']); - expect(root).toMatchRenderedOutput('Stateful: 2B'); + assertLog(['B']); + expect(container.textContent).toEqual('Stateful: 2B'); }); - it('suspends in a class that has componentWillUnmount and is then deleted', () => { + it('suspends in a class that has componentWillUnmount and is then deleted', async () => { class AsyncTextWithUnmount extends React.Component { componentWillUnmount() { Scheduler.log('will unmount'); @@ -845,12 +876,12 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(); + ReactDOM.render(, container); assertLog(['Suspend! [A]', 'Loading...']); - root.update(); + ReactDOM.render(, container); // Should not fire componentWillUnmount assertLog(['B']); - expect(root).toMatchRenderedOutput('B'); + expect(container.textContent).toEqual('B'); }); it('suspends in a component that also contains useEffect', async () => { @@ -874,10 +905,10 @@ describe('ReactSuspense', () => { ); } - ReactTestRenderer.create(); + ReactDOM.render(, container); assertLog(['Suspend! [A]', 'Loading...']); await resolveText('A'); - await waitForPaint(['A', 'Did commit: A']); + assertLog(['A', 'Did commit: A']); }); it('retries when an update is scheduled on a timed out tree', async () => { @@ -898,35 +929,33 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(, { - isConcurrent: true, - }); + ReactDOM.render(, container); // Initial render - await waitForAll(['Suspend! [Step: 1]', 'Loading...']); + assertLog(['Suspend! [Step: 1]', 'Loading...']); await act(() => resolveText('Step: 1')); assertLog(['Step: 1']); - expect(root).toMatchRenderedOutput('Step: 1'); + expect(container.textContent).toEqual('Step: 1'); // Update that suspends await act(() => { instance.setState({step: 2}); }); assertLog(['Suspend! [Step: 2]', 'Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); // Update while still suspended instance.setState({step: 3}); - await waitForAll(['Suspend! [Step: 3]']); - expect(root).toMatchRenderedOutput('Loading...'); + assertLog(['Suspend! [Step: 3]']); + expect(container.textContent).toEqual('Loading...'); await act(() => { resolveText('Step: 2'); resolveText('Step: 3'); }); assertLog(['Step: 3']); - expect(root).toMatchRenderedOutput('Step: 3'); + expect(container.textContent).toEqual('Step: 3'); }); it('does not remount the fallback while suspended children resolve in legacy mode', async () => { @@ -950,7 +979,7 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(); + ReactDOM.render(, container); // Initial render assertLog([ @@ -962,48 +991,19 @@ describe('ReactSuspense', () => { await waitForAll([]); await resolveText('Child 1'); - await waitForPaint([ - 'Child 1', - 'Suspend! [Child 2]', - 'Suspend! [Child 3]', - ]); + assertLog(['Child 1', 'Suspend! [Child 2]', 'Suspend! [Child 3]']); await resolveText('Child 2'); - await waitForPaint(['Child 2', 'Suspend! [Child 3]']); + assertLog(['Child 2', 'Suspend! [Child 3]']); await resolveText('Child 3'); - await waitForPaint(['Child 3']); - expect(root).toMatchRenderedOutput( + assertLog(['Child 3']); + expect(container.textContent).toEqual( ['Child 1', 'Child 2', 'Child 3'].join(''), ); expect(mounts).toBe(1); }); - it('does not get stuck with fallback in concurrent mode for a large delay', async () => { - function App(props) { - return ( - }> - - - - ); - } - - const root = ReactTestRenderer.create(, { - isConcurrent: true, - }); - - await waitForAll(['Suspend! [Child 1]', 'Loading...']); - await resolveText('Child 1'); - await waitForAll(['Child 1', 'Suspend! [Child 2]']); - - jest.advanceTimersByTime(6000); - - await act(() => resolveText('Child 2')); - assertLog(['Child 1', 'Child 2']); - expect(root).toMatchRenderedOutput(['Child 1', 'Child 2'].join('')); - }); - it('reuses effects, including deletions, from the suspended tree', async () => { const {useState} = React; @@ -1020,35 +1020,35 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(); + ReactDOM.render(, container); assertLog(['Suspend! [Tab: 0]', ' + sibling', 'Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); await resolveText('Tab: 0'); - await waitForPaint(['Tab: 0']); - expect(root).toMatchRenderedOutput('Tab: 0 + sibling'); + assertLog(['Tab: 0']); + expect(container.textContent).toEqual('Tab: 0 + sibling'); await act(() => setTab(1)); assertLog(['Suspend! [Tab: 1]', ' + sibling', 'Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); await resolveText('Tab: 1'); - await waitForPaint(['Tab: 1']); - expect(root).toMatchRenderedOutput('Tab: 1 + sibling'); + assertLog(['Tab: 1']); + expect(container.textContent).toEqual('Tab: 1 + sibling'); await act(() => setTab(2)); assertLog(['Suspend! [Tab: 2]', ' + sibling', 'Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); await resolveText('Tab: 2'); - await waitForPaint(['Tab: 2']); - expect(root).toMatchRenderedOutput('Tab: 2 + sibling'); + assertLog(['Tab: 2']); + expect(container.textContent).toEqual('Tab: 2 + sibling'); }); it('does not warn if a mounted component is pinged', async () => { const {useState} = React; - const root = ReactTestRenderer.create(null); + ReactDOM.render(null, container); let setStep; function UpdatingText({text, ms}) { @@ -1058,25 +1058,22 @@ describe('ReactSuspense', () => { return ; } - root.update( + ReactDOM.render( }> , + container, ); assertLog(['Suspend! [A:0]', 'Loading...']); await resolveText('A:0'); - await waitForPaint(['A:0']); - expect(root).toMatchRenderedOutput('A:0'); + assertLog(['A:0']); + expect(container.textContent).toEqual('A:0'); await act(() => setStep(1)); assertLog(['Suspend! [A:1]', 'Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); - - await act(() => { - root.update(null); - }); + expect(container.textContent).toEqual('Loading...'); }); it('memoizes promise listeners per thread ID to prevent redundant renders', async () => { @@ -1090,14 +1087,14 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(null); + ReactDOM.render(null, container); - root.update(); + ReactDOM.render(, container); assertLog(['Suspend! [A]', 'Suspend! [B]', 'Suspend! [C]', 'Loading...']); await resolveText('A'); - await waitForPaint([ + assertLog([ 'A', // The promises for B and C have now been thrown twice 'Suspend! [B]', @@ -1105,7 +1102,7 @@ describe('ReactSuspense', () => { ]); await resolveText('B'); - await waitForPaint([ + assertLog([ // Even though the promise for B was thrown twice, we should only // re-render once. 'B', @@ -1114,7 +1111,7 @@ describe('ReactSuspense', () => { ]); await resolveText('C'); - await waitForPaint([ + assertLog([ // Even though the promise for C was thrown three times, we should only // re-render once. 'C', @@ -1153,11 +1150,9 @@ describe('ReactSuspense', () => { } } - const root = ReactTestRenderer.create(null); + ReactDOM.render(null, container); - await act(() => { - root.update(); - }); + ReactDOM.render(, container); }); it('updates memoized child of suspense component when context updates (simple memo)', async () => { @@ -1184,19 +1179,19 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(); + ReactDOM.render(, container); assertLog(['Suspend! [default]', 'Loading...']); await resolveText('default'); - await waitForPaint(['default']); - expect(root).toMatchRenderedOutput('default'); + assertLog(['default']); + expect(container.textContent).toEqual('default'); await act(() => setValue('new value')); assertLog(['Suspend! [new value]', 'Loading...']); await resolveText('new value'); - await waitForPaint(['new value']); - expect(root).toMatchRenderedOutput('new value'); + assertLog(['new value']); + expect(container.textContent).toEqual('new value'); }); it('updates memoized child of suspense component when context updates (manual memo)', async () => { @@ -1228,19 +1223,19 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(); + ReactDOM.render(, container); assertLog(['Suspend! [default]', 'Loading...']); await resolveText('default'); - await waitForPaint(['default']); - expect(root).toMatchRenderedOutput('default'); + assertLog(['default']); + expect(container.textContent).toEqual('default'); await act(() => setValue('new value')); assertLog(['Suspend! [new value]', 'Loading...']); await resolveText('new value'); - await waitForPaint(['new value']); - expect(root).toMatchRenderedOutput('new value'); + assertLog(['new value']); + expect(container.textContent).toEqual('new value'); }); it('updates memoized child of suspense component when context updates (function)', async () => { @@ -1265,25 +1260,26 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create( + ReactDOM.render( }> , + container, ); assertLog(['Suspend! [default]', 'Loading...']); await resolveText('default'); - await waitForPaint(['default']); - expect(root).toMatchRenderedOutput('default'); + assertLog(['default']); + expect(container.textContent).toEqual('default'); await act(() => setValue('new value')); assertLog(['Suspend! [new value]', 'Loading...']); await resolveText('new value'); - await waitForPaint(['new value']); - expect(root).toMatchRenderedOutput('new value'); + assertLog(['new value']); + expect(container.textContent).toEqual('new value'); }); it('updates memoized child of suspense component when context updates (forwardRef)', async () => { @@ -1310,19 +1306,19 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(); + ReactDOM.render(, container); assertLog(['Suspend! [default]', 'Loading...']); await resolveText('default'); - await waitForPaint(['default']); - expect(root).toMatchRenderedOutput('default'); + assertLog(['default']); + expect(container.textContent).toEqual('default'); await act(() => setValue('new value')); assertLog(['Suspend! [new value]', 'Loading...']); await resolveText('new value'); - await waitForPaint(['new value']); - expect(root).toMatchRenderedOutput('new value'); + assertLog(['new value']); + expect(container.textContent).toEqual('new value'); }); it('updates context consumer within child of suspended suspense component when context updates', async () => { @@ -1364,17 +1360,17 @@ describe('ReactSuspense', () => { ); } - const root = ReactTestRenderer.create(); + ReactDOM.render(, container); assertLog(['Received context value [default]', 'default']); - expect(root).toMatchRenderedOutput('default'); + expect(container.textContent).toEqual('default'); await act(() => setValue('new value')); assertLog(['Received context value [new value]', 'Loading...']); - expect(root).toMatchRenderedOutput('Loading...'); + expect(container.textContent).toEqual('Loading...'); await act(() => setValue('default')); assertLog(['Received context value [default]', 'default']); - expect(root).toMatchRenderedOutput('default'); + expect(container.textContent).toEqual('default'); }); }); });