/* eslint-disable react/jsx-boolean-value */ let React; let ReactNoop; let Scheduler; let act; let Suspense; let useState; let textCache; let readText; let resolveText; // let rejectText; let assertLog; let waitForPaint; describe('ReactSuspenseWithNoopRenderer', () => { beforeEach(() => { jest.resetModules(); React = require('react'); ReactNoop = require('react-noop-renderer'); Scheduler = require('scheduler'); act = require('internal-test-utils').act; Suspense = React.Suspense; useState = React.useState; const InternalTestUtils = require('internal-test-utils'); assertLog = InternalTestUtils.assertLog; waitForPaint = InternalTestUtils.waitForPaint; textCache = new Map(); readText = text => { const record = textCache.get(text); if (record !== undefined) { switch (record.status) { case 'pending': throw record.promise; case 'rejected': throw Error('Failed to load: ' + text); case 'resolved': return text; } } else { let ping; const promise = new Promise(resolve => (ping = resolve)); const newRecord = { status: 'pending', ping: ping, promise, }; textCache.set(text, newRecord); throw promise; } }; resolveText = text => { const record = textCache.get(text); if (record !== undefined) { if (record.status === 'pending') { record.ping(); record.ping = null; record.status = 'resolved'; record.promise = null; } } else { const newRecord = { ping: null, status: 'resolved', promise: null, }; textCache.set(text, newRecord); } }; // rejectText = text => { // const record = textCache.get(text); // if (record !== undefined) { // if (record.status === 'pending') { // Scheduler.log(`Promise rejected [${text}]`); // record.ping(); // record.status = 'rejected'; // clearTimeout(record.promise._timer); // record.promise = null; // } // } else { // const newRecord = { // ping: null, // status: 'rejected', // promise: null, // }; // textCache.set(text, newRecord); // } // }; }); function Text(props) { Scheduler.log(props.text); return props.text; } function AsyncText(props) { const text = props.text; try { readText(text); Scheduler.log(text); return text; } catch (promise) { if (typeof promise.then === 'function') { Scheduler.log(`Suspend! [${text}]`); } else { Scheduler.log(`Error! [${text}]`); } throw promise; } } // @gate enableCPUSuspense it('skips CPU-bound trees on initial mount', async () => { function App() { return ( <>
}>
); } const root = ReactNoop.createRoot(); await act(async () => { root.render(); await waitForPaint(['Outer', 'Loading...']); expect(root).toMatchRenderedOutput( <> Outer
Loading...
, ); }); // Inner contents finish in separate commit from outer assertLog(['Inner']); expect(root).toMatchRenderedOutput( <> Outer
Inner
, ); }); // @gate enableCPUSuspense it('does not skip CPU-bound trees during updates', async () => { let setCount; function App() { const [count, _setCount] = useState(0); setCount = _setCount; return ( <>
}>
); } // Initial mount const root = ReactNoop.createRoot(); await act(() => { root.render(); }); // Inner contents finish in separate commit from outer assertLog(['Outer', 'Loading...', 'Inner [0]']); expect(root).toMatchRenderedOutput( <> Outer
Inner [0]
, ); // Update await act(() => { setCount(1); }); // Entire update finishes in a single commit assertLog(['Outer', 'Inner [1]']); expect(root).toMatchRenderedOutput( <> Outer
Inner [1]
, ); }); // @gate enableCPUSuspense it('suspend inside CPU-bound tree', async () => { function App() { return ( <>
}>
); } const root = ReactNoop.createRoot(); await act(async () => { root.render(); await waitForPaint(['Outer', 'Loading...']); expect(root).toMatchRenderedOutput( <> Outer
Loading...
, ); }); // Inner contents suspended, so we continue showing a fallback. assertLog([ 'Suspend! [Inner]', // pre-warming 'Suspend! [Inner]', ]); expect(root).toMatchRenderedOutput( <> Outer
Loading...
, ); // Resolve the data and finish rendering await act(async () => { await resolveText('Inner'); }); assertLog(['Inner']); expect(root).toMatchRenderedOutput( <> Outer
Inner
, ); }); // @gate enableCPUSuspense it('nested CPU-bound trees', async () => { function App() { return ( <>
}>
}>
); } const root = ReactNoop.createRoot(); await act(() => { root.render(); }); // Each level commits separately assertLog(['A', 'Loading B...', 'B', 'Loading C...', 'C']); expect(root).toMatchRenderedOutput( <> A
B
C
, ); }); });