From 07def0cc5a377fc36c410b85112fdc51485ecc11 Mon Sep 17 00:00:00 2001 From: Ricky Date: Tue, 26 Mar 2024 00:02:46 -0400 Subject: [PATCH] Add test for throttling suspended siblings (#28361) # Overview Adds a test to show the combination of the new throttling behavior and not pre-rendering siblings results in pushing out content that could have rendered much faster. - Without the new throttling, the sibling content would render in 30ms. - Without removing pre-rendering, the sibling content would render in 0ms. - With both, the sibling content takes 600ms. ## Example https://github.com/facebook/react/assets/2440089/abd62dc4-93f9-4b7b-a5aa-b795827c1a3a --- .../__tests__/ReactSuspense-test.internal.js | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js index 8f4664a5325a3..12563be1724ec 100644 --- a/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js +++ b/packages/react-reconciler/src/__tests__/ReactSuspense-test.internal.js @@ -289,6 +289,59 @@ describe('ReactSuspense', () => { expect(container.textContent).toEqual('AB'); }); + it('pushes out siblings that render faster than throttle', async () => { + function Foo() { + Scheduler.log('Foo'); + return ( + }> + + }> + + + + ); + } + + setTimeout(async () => { + // TODO: this is dumb, but AsyncText isn't timer based after the act changes. + // Pretend that this is the start of the sibling suspending. + // In a real test, the timer would start when we render B. + setTimeout(async () => { + resolveText('B'); + }, 30); + + resolveText('A'); + }, 290); + + // Render an empty shell + const root = ReactTestRenderer.create(, { + isConcurrent: true, + }); + + await waitForAll(['Foo', 'Suspend! [A]', 'Loading...']); + expect(root).toMatchRenderedOutput('Loading...'); + + // Now resolve A + jest.advanceTimersByTime(290); + await waitFor(['A']); + expect(root).toMatchRenderedOutput('Loading...'); + + // B starts loading. Parent boundary is in throttle. + // Still shows parent loading under throttle + jest.advanceTimersByTime(10); + await waitForAll(['Suspend! [B]', 'Loading more...']); + expect(root).toMatchRenderedOutput('Loading...'); + + // !! B could have finished before the throttle, but we show a fallback. + // !! Pushing out the 30ms fetch for B to 300ms. + jest.advanceTimersByTime(300); + await waitFor(['B']); + expect(root).toMatchRenderedOutput('ALoading more...'); + + await act(() => {}); + expect(root).toMatchRenderedOutput('AB'); + }); + it('does not throttle fallback committing for too long', async () => { function Foo() { Scheduler.log('Foo');